github.com/greenpau/go-authcrunch@v1.0.50/pkg/authn/portal_test.go (about)

     1  // Copyright 2022 Paul Greenberg greenpau@outlook.com
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package authn
    16  
    17  import (
    18  	"github.com/google/go-cmp/cmp"
    19  	"github.com/greenpau/go-authcrunch/internal/tests"
    20  	"github.com/greenpau/go-authcrunch/internal/testutils"
    21  	"github.com/greenpau/go-authcrunch/pkg/acl"
    22  	"github.com/greenpau/go-authcrunch/pkg/authn/cookie"
    23  	"github.com/greenpau/go-authcrunch/pkg/authn/transformer"
    24  	"github.com/greenpau/go-authcrunch/pkg/authn/ui"
    25  	"github.com/greenpau/go-authcrunch/pkg/authz/options"
    26  	"github.com/greenpau/go-authcrunch/pkg/errors"
    27  	"github.com/greenpau/go-authcrunch/pkg/ids"
    28  	logutil "github.com/greenpau/go-authcrunch/pkg/util/log"
    29  	"go.uber.org/zap"
    30  	"testing"
    31  )
    32  
    33  func TestNewPortal(t *testing.T) {
    34  	db, err := testutils.CreateTestDatabase("TestNewPortal")
    35  	if err != nil {
    36  		t.Fatalf("failed to create temp dir: %v", err)
    37  	}
    38  	dbPath := db.GetPath()
    39  	t.Logf("%v", dbPath)
    40  
    41  	var testcases = []struct {
    42  		name      string
    43  		disabled  bool
    44  		want      string
    45  		shouldErr bool
    46  		err       error
    47  
    48  		loggerFunc func() *zap.Logger
    49  		configFunc func() *PortalConfig
    50  
    51  		// Portal Config fields.
    52  		uiConfig               *ui.Parameters
    53  		userTransformerConfigs []*transformer.Config
    54  		cookieConfig           *cookie.Config
    55  		identityStoreConfigs   []*ids.IdentityStoreConfig
    56  		aclConfigs             []*acl.RuleConfiguration
    57  		tokenValidatorOptions  *options.TokenValidatorOptions
    58  		tokenGrantorOptions    *options.TokenGrantorOptions
    59  		cryptoRawConfigs       []string
    60  	}{
    61  		{
    62  			name: "test new portal without logger",
    63  			loggerFunc: func() *zap.Logger {
    64  				return nil
    65  			},
    66  			configFunc: func() *PortalConfig {
    67  				return nil
    68  			},
    69  			shouldErr: true,
    70  			err:       errors.ErrNewPortalLoggerNil,
    71  		},
    72  		{
    73  			name: "test new portal without config",
    74  			loggerFunc: func() *zap.Logger {
    75  				return logutil.NewLogger()
    76  			},
    77  			configFunc: func() *PortalConfig {
    78  				return nil
    79  			},
    80  			shouldErr: true,
    81  			err:       errors.ErrNewPortalConfigNil,
    82  		},
    83  		{
    84  			name: "test new portal without name",
    85  			loggerFunc: func() *zap.Logger {
    86  				return logutil.NewLogger()
    87  			},
    88  			configFunc: func() *PortalConfig {
    89  				return &PortalConfig{}
    90  			},
    91  			shouldErr: true,
    92  			err:       errors.ErrNewPortal.WithArgs(errors.ErrPortalConfigNameNotFound),
    93  		},
    94  		{
    95  			name: "test new portal without backends",
    96  			loggerFunc: func() *zap.Logger {
    97  				return logutil.NewLogger()
    98  			},
    99  			configFunc: func() *PortalConfig {
   100  				return &PortalConfig{
   101  					Name: "myportal",
   102  				}
   103  			},
   104  			shouldErr: true,
   105  			err:       errors.ErrNewPortal.WithArgs(errors.ErrPortalConfigBackendsNotFound),
   106  		},
   107  		{
   108  			name: "test new portal backed by local database",
   109  			loggerFunc: func() *zap.Logger {
   110  				return logutil.NewLogger()
   111  			},
   112  			configFunc: func() *PortalConfig {
   113  				return &PortalConfig{
   114  					Name: "myportal",
   115  					IdentityStores: []string{
   116  						"local_backend",
   117  					},
   118  				}
   119  			},
   120  			identityStoreConfigs: []*ids.IdentityStoreConfig{
   121  				{
   122  					Name: "local_backend",
   123  					Kind: "local",
   124  					Params: map[string]interface{}{
   125  						"path":  dbPath,
   126  						"realm": "local",
   127  					},
   128  				},
   129  			},
   130  			want: `{
   131                "config": {
   132  			    "name": "myportal",
   133  				"ui": {
   134  				  "theme": "basic"
   135  				},
   136  				"token_validator_options": {
   137  				  "validate_bearer_header": true
   138  				},
   139  				"access_list_configs": [
   140                    {
   141                      "action": "` + defaultPortalACLAction + `",
   142                      "conditions": ["` + defaultPortalACLCondition + `"]
   143  				  }
   144  				],
   145  				"identity_stores": ["local_backend"]
   146                }
   147              }`,
   148  		},
   149  	}
   150  
   151  	for _, tc := range testcases {
   152  		t.Run(tc.name, func(t *testing.T) {
   153  			if tc.disabled {
   154  				return
   155  			}
   156  			cfg := tc.configFunc()
   157  			if cfg != nil {
   158  				if tc.uiConfig != nil {
   159  					cfg.UI = tc.uiConfig
   160  				}
   161  				if len(tc.userTransformerConfigs) > 0 {
   162  					cfg.UserTransformerConfigs = tc.userTransformerConfigs
   163  				}
   164  				if tc.cookieConfig != nil {
   165  					cfg.CookieConfig = tc.cookieConfig
   166  				}
   167  				if len(tc.aclConfigs) > 0 {
   168  					cfg.AccessListConfigs = tc.aclConfigs
   169  				}
   170  				if tc.tokenValidatorOptions != nil {
   171  					cfg.TokenValidatorOptions = tc.tokenValidatorOptions
   172  				}
   173  				if tc.tokenGrantorOptions != nil {
   174  					cfg.TokenGrantorOptions = tc.tokenGrantorOptions
   175  				}
   176  				for _, s := range tc.cryptoRawConfigs {
   177  					cfg.AddRawCryptoConfigs(s)
   178  				}
   179  			}
   180  
   181  			params := PortalParameters{
   182  				Config: cfg,
   183  				Logger: tc.loggerFunc(),
   184  			}
   185  
   186  			for _, storeCfg := range tc.identityStoreConfigs {
   187  				store, err := ids.NewIdentityStore(storeCfg, logutil.NewLogger())
   188  				if err != nil {
   189  					t.Fatal(err)
   190  				}
   191  				if err := store.Configure(); err != nil {
   192  					t.Fatal(err)
   193  				}
   194  				params.IdentityStores = append(params.IdentityStores, store)
   195  			}
   196  
   197  			portal, err := NewPortal(params)
   198  			if err != nil {
   199  				if !tc.shouldErr {
   200  					t.Fatalf("expected success, got: %v", err)
   201  				}
   202  				if diff := cmp.Diff(err.Error(), tc.err.Error()); diff != "" {
   203  					t.Fatalf("unexpected error: %v, want: %v", err, tc.err)
   204  				}
   205  				return
   206  			}
   207  			if tc.shouldErr {
   208  				t.Fatalf("unexpected success, want: %v", tc.err)
   209  			}
   210  
   211  			got := make(map[string]interface{})
   212  			got["config"] = tests.Unpack(t, portal.config)
   213  			want := tests.Unpack(t, tc.want)
   214  
   215  			if diff := cmp.Diff(want, got); diff != "" {
   216  				t.Logf("JSON: %s", tests.UnpackJSON(t, got))
   217  				t.Errorf("NewPortal() config mismatch (-want +got):\n%s", diff)
   218  			}
   219  		})
   220  	}
   221  }