github.com/greenpau/go-authcrunch@v1.1.4/config_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 authcrunch
    16  
    17  import (
    18  	"fmt"
    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"
    23  	"github.com/greenpau/go-authcrunch/pkg/authz"
    24  	"github.com/greenpau/go-authcrunch/pkg/credentials"
    25  	"github.com/greenpau/go-authcrunch/pkg/errors"
    26  	"github.com/greenpau/go-authcrunch/pkg/idp"
    27  	"github.com/greenpau/go-authcrunch/pkg/ids"
    28  	"github.com/greenpau/go-authcrunch/pkg/messaging"
    29  	"path"
    30  	"path/filepath"
    31  	"testing"
    32  )
    33  
    34  func TestNewConfig(t *testing.T) {
    35  	db, err := testutils.CreateTestDatabase("TestNewPortal")
    36  	if err != nil {
    37  		t.Fatalf("failed to create temp dir: %v", err)
    38  	}
    39  	dbPath := db.GetPath()
    40  	// t.Logf("%v", dbPath)
    41  
    42  	var testcases = []struct {
    43  		name string
    44  
    45  		identityStores    []*ids.IdentityStoreConfig
    46  		identityProviders []*idp.IdentityProviderConfig
    47  		credentials       []credentials.Credential
    48  		messaging         []messaging.Provider
    49  		portals           []*authn.PortalConfig
    50  		policies          []*authz.PolicyConfig
    51  
    52  		shouldErr bool
    53  		errPhase  string
    54  		err       error
    55  	}{
    56  		{
    57  			name:      "test empty config",
    58  			shouldErr: true,
    59  			errPhase:  "Validate",
    60  			err:       fmt.Errorf("no portals and gatekeepers found"),
    61  		},
    62  		{
    63  			name: "test failed local identity store config",
    64  			identityStores: []*ids.IdentityStoreConfig{
    65  				{
    66  					Name: "localdb",
    67  					Kind: "local",
    68  					Params: map[string]interface{}{
    69  						"realm": "local",
    70  					},
    71  				},
    72  			},
    73  			shouldErr: true,
    74  			errPhase:  "AddIdentityStore",
    75  			err: errors.ErrIdentityStoreConfigInvalid.WithArgs(
    76  				fmt.Errorf("required field %q not found", "path"),
    77  			),
    78  		},
    79  		{
    80  			name: "test local identity stores having same realm but different paths",
    81  			identityStores: []*ids.IdentityStoreConfig{
    82  				{
    83  					Name: "localdb1",
    84  					Kind: "local",
    85  					Params: map[string]interface{}{
    86  						"realm": "local",
    87  						"path":  filepath.Join(path.Dir(dbPath), "user_db1.json"),
    88  					},
    89  				},
    90  				{
    91  					Name: "localdb2",
    92  					Kind: "local",
    93  					Params: map[string]interface{}{
    94  						"realm": "local",
    95  						"path":  filepath.Join(path.Dir(dbPath), "user_db2.json"),
    96  					},
    97  				},
    98  			},
    99  			portals: []*authn.PortalConfig{
   100  				{
   101  					Name: "myportal",
   102  					IdentityStores: []string{
   103  						"localdb1",
   104  						"localdb2",
   105  					},
   106  				},
   107  			},
   108  			shouldErr: true,
   109  			errPhase:  "Validate",
   110  			err:       fmt.Errorf("identity provider %q has the same %q realm as %q", "localdb2", "local", "localdb1"),
   111  		},
   112  		{
   113  			name: "test local identity stores having different realms but the same path",
   114  			identityStores: []*ids.IdentityStoreConfig{
   115  				{
   116  					Name: "localdb1",
   117  					Kind: "local",
   118  					Params: map[string]interface{}{
   119  						"realm": "contoso",
   120  						"path":  filepath.Join(path.Dir(dbPath), "user_db.json"),
   121  					},
   122  				},
   123  			},
   124  			identityProviders: []*idp.IdentityProviderConfig{
   125  				{
   126  					Name: "provider1",
   127  					Kind: "oauth",
   128  					Params: map[string]interface{}{
   129  						"base_auth_url":         "https://localhost/oauth",
   130  						"token_url":             "https://localhost/oauth/access_token",
   131  						"authorization_url":     "https://localhost/oauth/authorize",
   132  						"client_id":             "foo",
   133  						"client_secret":         "bar",
   134  						"driver":                "generic",
   135  						"realm":                 "contoso",
   136  						"required_token_fields": []interface{}{"access_token"},
   137  						"response_type":         []interface{}{"code"},
   138  
   139  						"tls_insecure_skip_verify":  true,
   140  						"key_verification_disabled": true,
   141  						"jwks_keys": map[string]string{
   142  							"87329db33bf": "testdata/oauth/87329db33bf_pub.pem",
   143  						},
   144  					},
   145  				},
   146  			},
   147  			portals: []*authn.PortalConfig{
   148  				{
   149  					Name: "myportal",
   150  					IdentityStores: []string{
   151  						"localdb1",
   152  					},
   153  					IdentityProviders: []string{
   154  						"provider1",
   155  					},
   156  				},
   157  			},
   158  			shouldErr: true,
   159  			errPhase:  "Validate",
   160  			err:       fmt.Errorf("identity provider %q has the same %q realm as %q", "provider1", "contoso", "localdb1"),
   161  		},
   162  		{
   163  			name: "test failed identity provider config",
   164  			identityProviders: []*idp.IdentityProviderConfig{
   165  				{
   166  					Name: "authp",
   167  					Kind: "oauth",
   168  					Params: map[string]interface{}{
   169  						"realm": "authp",
   170  					},
   171  				},
   172  			},
   173  			shouldErr: true,
   174  			errPhase:  "AddIdentityProvider",
   175  			err: errors.ErrIdentityProviderConfigInvalid.WithArgs(
   176  				fmt.Errorf("required field %q not found", "driver"),
   177  			),
   178  		},
   179  		{
   180  			name: "test failed auth portal config",
   181  			portals: []*authn.PortalConfig{
   182  				{
   183  					Name: "myportal",
   184  				},
   185  			},
   186  			shouldErr: true,
   187  			errPhase:  "Validate",
   188  			err:       errors.ErrPortalConfigBackendsNotFound,
   189  		},
   190  		{
   191  			name: "test failed credentials config",
   192  			credentials: []credentials.Credential{
   193  				&credentials.Generic{
   194  					Name:     "foobar",
   195  					Username: "foo",
   196  				},
   197  			},
   198  			shouldErr: true,
   199  			errPhase:  "AddCredential",
   200  			err:       errors.ErrCredKeyValueEmpty.WithArgs("password"),
   201  		},
   202  		{
   203  			name: "test failed messaging provider config",
   204  			messaging: []messaging.Provider{
   205  				&messaging.EmailProvider{
   206  					Name:    "default",
   207  					Address: "localhost",
   208  					// Protocol:    "smtp",
   209  					Credentials: "foobar",
   210  					SenderEmail: "root@localhost",
   211  				},
   212  			},
   213  			shouldErr: true,
   214  			errPhase:  "AddMessagingProvider",
   215  			err:       errors.ErrMessagingProviderKeyValueEmpty.WithArgs("protocol"),
   216  		},
   217  		{
   218  			name: "test failed authorization policy config",
   219  			policies: []*authz.PolicyConfig{
   220  				{
   221  					Name: "mygatekeeper",
   222  				},
   223  			},
   224  			shouldErr: true,
   225  			errPhase:  "AddAuthorizationPolicy",
   226  			err:       errors.ErrInvalidConfiguration.WithArgs("mygatekeeper", "access list rule config not found"),
   227  		},
   228  		{
   229  			name: "test valid local auth config",
   230  			credentials: []credentials.Credential{
   231  				&credentials.Generic{
   232  					Name:     "foobar",
   233  					Username: "foo",
   234  					Password: "bar",
   235  				},
   236  			},
   237  			messaging: []messaging.Provider{
   238  				&messaging.EmailProvider{
   239  					Name:        "default",
   240  					Address:     "localhost",
   241  					Protocol:    "smtp",
   242  					Credentials: "foobar",
   243  					SenderEmail: "root@localhost",
   244  				},
   245  			},
   246  			identityStores: []*ids.IdentityStoreConfig{
   247  				{
   248  					Name: "localdb",
   249  					Kind: "local",
   250  					Params: map[string]interface{}{
   251  						"realm": "local",
   252  						"path":  dbPath,
   253  					},
   254  				},
   255  			},
   256  			identityProviders: []*idp.IdentityProviderConfig{
   257  				{
   258  					Name: "contoso",
   259  					Kind: "oauth",
   260  					Params: map[string]interface{}{
   261  						"base_auth_url":         "https://localhost/oauth",
   262  						"token_url":             "https://localhost/oauth/access_token",
   263  						"authorization_url":     "https://localhost/oauth/authorize",
   264  						"client_id":             "foo",
   265  						"client_secret":         "bar",
   266  						"driver":                "generic",
   267  						"realm":                 "contoso",
   268  						"required_token_fields": []interface{}{"access_token"},
   269  						"response_type":         []interface{}{"code"},
   270  
   271  						"tls_insecure_skip_verify":  true,
   272  						"key_verification_disabled": true,
   273  						"jwks_keys": map[string]string{
   274  							"87329db33bf": "testdata/oauth/87329db33bf_pub.pem",
   275  						},
   276  					},
   277  				},
   278  			},
   279  			portals: []*authn.PortalConfig{
   280  				{
   281  					Name: "myportal",
   282  					IdentityStores: []string{
   283  						"localdb",
   284  					},
   285  				},
   286  			},
   287  			policies: []*authz.PolicyConfig{
   288  				{
   289  					Name: "mygatekeeper",
   290  					AccessListRules: []*acl.RuleConfiguration{
   291  						{
   292  							Conditions: []string{
   293  								"match roles authp/admin authp/user",
   294  							},
   295  							Action: "allow stop",
   296  						},
   297  					},
   298  					AuthRedirectDisabled: true,
   299  				},
   300  			},
   301  		},
   302  	}
   303  
   304  	for _, tc := range testcases {
   305  		t.Run(tc.name, func(t *testing.T) {
   306  			msgs := []string{fmt.Sprintf("test name: %s", tc.name)}
   307  
   308  			cfg := NewConfig()
   309  
   310  			for _, item := range tc.credentials {
   311  				err := cfg.AddCredential(item)
   312  				if tests.EvalErrPhaseWithLog(t, err, "AddCredential", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   313  					return
   314  				}
   315  			}
   316  
   317  			for _, item := range tc.messaging {
   318  				err := cfg.AddMessagingProvider(item)
   319  				if tests.EvalErrPhaseWithLog(t, err, "AddMessagingProvider", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   320  					return
   321  				}
   322  			}
   323  
   324  			for _, item := range tc.identityStores {
   325  				err := cfg.AddIdentityStore(item.Name, item.Kind, item.Params)
   326  				if tests.EvalErrPhaseWithLog(t, err, "AddIdentityStore", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   327  					return
   328  				}
   329  			}
   330  
   331  			for _, item := range tc.identityProviders {
   332  				err := cfg.AddIdentityProvider(item.Name, item.Kind, item.Params)
   333  				if tests.EvalErrPhaseWithLog(t, err, "AddIdentityProvider", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   334  					return
   335  				}
   336  			}
   337  
   338  			for _, item := range tc.portals {
   339  				err := cfg.AddAuthenticationPortal(item)
   340  				if tests.EvalErrPhaseWithLog(t, err, "AddAuthenticationPortal", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   341  					return
   342  				}
   343  			}
   344  
   345  			for _, item := range tc.policies {
   346  				err := cfg.AddAuthorizationPolicy(item)
   347  				if tests.EvalErrPhaseWithLog(t, err, "AddAuthorizationPolicy", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   348  					return
   349  				}
   350  			}
   351  
   352  			err := cfg.Validate()
   353  			if err != nil {
   354  				if tests.EvalErrPhaseWithLog(t, err, "Validate", tc.errPhase, tc.shouldErr, tc.err, msgs) {
   355  					return
   356  				}
   357  			}
   358  			if tc.shouldErr {
   359  				t.Fatalf("unexpected success, want: %v", tc.err)
   360  			}
   361  		})
   362  	}
   363  }