github.com/greenpau/go-authcrunch@v1.1.4/pkg/ids/local/authenticator_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 local
    16  
    17  import (
    18  	"fmt"
    19  	"github.com/google/uuid"
    20  	"github.com/greenpau/go-authcrunch/internal/tests"
    21  	"github.com/greenpau/go-authcrunch/internal/testutils"
    22  	"github.com/greenpau/go-authcrunch/pkg/authn/enums/operator"
    23  	"github.com/greenpau/go-authcrunch/pkg/errors"
    24  	"github.com/greenpau/go-authcrunch/pkg/identity"
    25  	"github.com/greenpau/go-authcrunch/pkg/requests"
    26  	logutil "github.com/greenpau/go-authcrunch/pkg/util/log"
    27  	"os"
    28  	"testing"
    29  )
    30  
    31  func TestAuthenticate(t *testing.T) {
    32  	db, err := testutils.CreateTestDatabase("TestLocalIdentityStore")
    33  	if err != nil {
    34  		t.Fatalf("failed to create temp dir: %v", err)
    35  	}
    36  	dbPath := db.GetPath()
    37  
    38  	config := &Config{
    39  		Name:  "local_store",
    40  		Realm: "local",
    41  		Path:  dbPath,
    42  	}
    43  
    44  	testcases := []struct {
    45  		name      string
    46  		config    *Config
    47  		op        operator.Type
    48  		req       *requests.Request
    49  		opts      map[string]interface{}
    50  		want      map[string]interface{}
    51  		shouldErr bool
    52  		err       error
    53  	}{
    54  		{
    55  			name:   "authenticate user",
    56  			config: config,
    57  			op:     operator.Authenticate,
    58  			req: &requests.Request{
    59  				User: requests.User{
    60  					Username: tests.TestUser1,
    61  					Email:    tests.TestEmail1,
    62  					Password: tests.TestPwd1,
    63  				},
    64  			},
    65  			want: map[string]interface{}{
    66  				"config": map[string]interface{}{
    67  					"name":  "local_store",
    68  					"realm": "local",
    69  					"path":  dbPath,
    70  					"login_icon": map[string]interface{}{
    71  						"background_color": string("#324960"),
    72  						"class_name":       string("las la-key la-2x"),
    73  						"color":            string("white"),
    74  						"text_color":       string("#37474f"),
    75  					},
    76  				},
    77  			},
    78  		},
    79  		{
    80  			name:   "authenticate user with invalid password",
    81  			config: config,
    82  			op:     operator.Authenticate,
    83  			req: &requests.Request{
    84  				User: requests.User{
    85  					Username: tests.TestUser1,
    86  					Email:    tests.TestEmail1,
    87  				},
    88  			},
    89  			shouldErr: true,
    90  			err:       errors.ErrIdentityStoreLocalAuthFailed.WithArgs("user authentication failed: malformed auth request"),
    91  		},
    92  		{
    93  			name:      "test unknown operator",
    94  			config:    config,
    95  			op:        operator.Unknown,
    96  			shouldErr: true,
    97  			err:       errors.ErrOperatorNotSupported.WithArgs(operator.Unknown),
    98  		},
    99  	}
   100  	for _, tc := range testcases {
   101  		t.Run(tc.name, func(t *testing.T) {
   102  			msgs := []string{fmt.Sprintf("test name: %s", tc.name)}
   103  			msgs = append(msgs, fmt.Sprintf("db path: %v", tc.config.Path))
   104  			msgs = append(msgs, fmt.Sprintf("config:\n%v", tc.config))
   105  			logger := logutil.NewLogger()
   106  
   107  			b, err := NewIdentityStore(tc.config, logger)
   108  			if err != nil {
   109  				t.Fatalf("initialization error: %v", err)
   110  			}
   111  
   112  			if err := b.Configure(); err != nil {
   113  				t.Fatalf("configuration error: %v", err)
   114  			}
   115  
   116  			err = b.Request(tc.op, tc.req)
   117  			if tests.EvalErrWithLog(t, err, "authenticate", tc.shouldErr, tc.err, msgs) {
   118  				return
   119  			}
   120  
   121  			got := make(map[string]interface{})
   122  			got["config"] = b.GetConfig()
   123  			tests.EvalObjectsWithLog(t, "user", tc.want, got, msgs)
   124  		})
   125  	}
   126  }
   127  
   128  func TestNewAuthenticator(t *testing.T) {
   129  	testcases := []struct {
   130  		name         string
   131  		config       *Config
   132  		db           func() *identity.Database
   133  		env          map[string]string
   134  		authenticate bool
   135  		want         map[string]interface{}
   136  		shouldErr    bool
   137  		err          error
   138  	}{
   139  		{
   140  			name: "test new authenticator with user env var",
   141  			config: &Config{
   142  				Name:  "local_store",
   143  				Realm: "local",
   144  			},
   145  			env: map[string]string{
   146  				"AUTHP_ADMIN_USER":   "myadmin",
   147  				"AUTHP_ADMIN_SECRET": uuid.New().String(),
   148  				"AUTHP_ADMIN_EMAIL":  "myadmin@localdomain.local",
   149  			},
   150  			db: func() *identity.Database {
   151  				db, err := testutils.CreateEmptyTestDatabase("TestLocalIdentityStore")
   152  				if err != nil {
   153  					t.Fatalf("failed to create temp dir: %v", err)
   154  				}
   155  				return db
   156  			},
   157  			authenticate: true,
   158  			want: map[string]interface{}{
   159  				"response": requests.Response{
   160  					Code: 200,
   161  				},
   162  			},
   163  		},
   164  		{
   165  			name: "test new authenticator without user env var",
   166  			config: &Config{
   167  				Name:  "local_store",
   168  				Realm: "local",
   169  			},
   170  			db: func() *identity.Database {
   171  				db, err := testutils.CreateEmptyTestDatabase("TestLocalIdentityStore")
   172  				if err != nil {
   173  					t.Fatalf("failed to create temp dir: %v", err)
   174  				}
   175  				return db
   176  			},
   177  			want: map[string]interface{}{},
   178  		},
   179  		{
   180  			name: "test new authenticator with invalid user email",
   181  			config: &Config{
   182  				Name:  "local_store",
   183  				Realm: "local",
   184  			},
   185  			env: map[string]string{
   186  				"AUTHP_ADMIN_USER":   "myadmin",
   187  				"AUTHP_ADMIN_SECRET": uuid.New().String(),
   188  				"AUTHP_ADMIN_EMAIL":  "localdomain.local",
   189  			},
   190  			db: func() *identity.Database {
   191  				db, err := testutils.CreateEmptyTestDatabase("TestLocalIdentityStore")
   192  				if err != nil {
   193  					t.Fatalf("failed to create temp dir: %v", err)
   194  				}
   195  				return db
   196  			},
   197  			shouldErr: true,
   198  			err:       errors.ErrAddUser.WithArgs("myadmin", "invalid email address"),
   199  		},
   200  	}
   201  	for _, tc := range testcases {
   202  		t.Run(tc.name, func(t *testing.T) {
   203  			msgs := []string{fmt.Sprintf("test name: %s", tc.name)}
   204  			for k, v := range tc.env {
   205  				msgs = append(msgs, fmt.Sprintf("env: %s = %s", k, v))
   206  				os.Setenv(k, v)
   207  				defer os.Unsetenv(k)
   208  			}
   209  			db := tc.db()
   210  			tc.config.Path = db.GetPath()
   211  			msgs = append(msgs, fmt.Sprintf("db path: %v", tc.config.Path))
   212  			msgs = append(msgs, fmt.Sprintf("config:\n%v", tc.config))
   213  
   214  			b := NewAuthenticator()
   215  			b.logger = logutil.NewLogger()
   216  			err := b.Configure(db.GetPath(), nil)
   217  			if tests.EvalErrWithLog(t, err, "configure", tc.shouldErr, tc.err, msgs) {
   218  				return
   219  			}
   220  
   221  			req := &requests.Request{
   222  				User: requests.User{
   223  					Username: os.Getenv("AUTHP_ADMIN_USER"),
   224  					Email:    os.Getenv("AUTHP_ADMIN_EMAIL"),
   225  					Password: os.Getenv("AUTHP_ADMIN_SECRET"),
   226  				},
   227  			}
   228  
   229  			if tc.authenticate {
   230  				err = b.AuthenticateUser(req)
   231  				if tests.EvalErrWithLog(t, err, "authenticate", tc.shouldErr, tc.err, msgs) {
   232  					return
   233  				}
   234  
   235  				got := make(map[string]interface{})
   236  				got["response"] = req.Response
   237  				tests.EvalObjectsWithLog(t, "user", tc.want, got, msgs)
   238  			}
   239  		})
   240  	}
   241  }