github.com/greenpau/go-authcrunch@v1.1.4/pkg/ids/local/store_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 "path" 20 "path/filepath" 21 "testing" 22 23 "github.com/greenpau/go-authcrunch/internal/tests" 24 "github.com/greenpau/go-authcrunch/internal/testutils" 25 "github.com/greenpau/go-authcrunch/pkg/authn/enums/operator" 26 "github.com/greenpau/go-authcrunch/pkg/errors" 27 "github.com/greenpau/go-authcrunch/pkg/requests" 28 logutil "github.com/greenpau/go-authcrunch/pkg/util/log" 29 "go.uber.org/zap" 30 ) 31 32 func TestNewIdentityStore(t *testing.T) { 33 db, err := testutils.CreateTestDatabase("TestLocalIdentityStore") 34 if err != nil { 35 t.Fatalf("failed to create temp dir: %v", err) 36 } 37 dbPath := db.GetPath() 38 testcases := []struct { 39 name string 40 config *Config 41 logger *zap.Logger 42 testRequests bool 43 publicKeysEnabled bool 44 want map[string]interface{} 45 shouldErr bool 46 err error 47 }{ 48 { 49 name: "test local store", 50 config: &Config{ 51 Name: "local_store", 52 Realm: "local", 53 Path: dbPath, 54 }, 55 logger: logutil.NewLogger(), 56 want: map[string]interface{}{ 57 "name": "local_store", 58 "kind": "local", 59 "realm": "local", 60 "config": map[string]interface{}{ 61 "name": "local_store", 62 "realm": "local", 63 "path": dbPath, 64 "login_icon": map[string]interface{}{ 65 "background_color": string("#324960"), 66 "class_name": string("las la-key la-2x"), 67 "color": string("white"), 68 "text_color": string("#37474f"), 69 }, 70 }, 71 }, 72 }, 73 { 74 name: "test local store with operations", 75 config: &Config{ 76 Name: "local_store", 77 Realm: "local", 78 Path: dbPath, 79 }, 80 logger: logutil.NewLogger(), 81 testRequests: true, 82 publicKeysEnabled: true, 83 want: map[string]interface{}{ 84 "name": "local_store", 85 "realm": "local", 86 "kind": "local", 87 "config": map[string]interface{}{ 88 "name": "local_store", 89 "realm": "local", 90 "path": dbPath, 91 "login_icon": map[string]interface{}{ 92 "background_color": string("#324960"), 93 "class_name": string("las la-key la-2x"), 94 "color": string("white"), 95 "text_color": string("#37474f"), 96 }, 97 }, 98 "ops": map[string]bool{ 99 "AddAPIKey": true, 100 "AddKeyGPG": true, 101 "AddKeySSH": true, 102 "AddMfaToken": true, 103 "AddUser": true, 104 "ChangePassword": true, 105 "DeleteAPIKey": true, 106 "DeleteMfaToken": true, 107 "DeletePublicKey": true, 108 "DeleteUser": true, 109 "GetAPIKeys": false, 110 "GetMfaTokens": false, 111 "GetMfaToken": true, 112 "GetPublicKeys": false, 113 "GetUser": false, 114 "GetUsers": false, 115 "IdentifyUser": false, 116 "LookupAPIKey": true, 117 }, 118 }, 119 }, 120 { 121 name: "test empty config name", 122 config: &Config{ 123 Name: "", 124 Realm: "local", 125 Path: filepath.Join(path.Dir(dbPath), "user_db1.json"), 126 }, 127 logger: logutil.NewLogger(), 128 shouldErr: true, 129 err: errors.ErrIdentityStoreConfigureNameEmpty, 130 }, 131 { 132 name: "test empty config realm", 133 config: &Config{ 134 Name: "local_store", 135 Path: filepath.Join(path.Dir(dbPath), "user_db1.json"), 136 }, 137 logger: logutil.NewLogger(), 138 shouldErr: true, 139 err: errors.ErrIdentityStoreConfigureRealmEmpty, 140 }, 141 { 142 name: "test empty config database path", 143 config: &Config{ 144 Name: "local_store", 145 Realm: "local", 146 }, 147 logger: logutil.NewLogger(), 148 shouldErr: true, 149 err: errors.ErrIdentityStoreLocalConfigurePathEmpty, 150 }, 151 { 152 name: "test empty logger", 153 config: &Config{ 154 Name: "local_store", 155 Realm: "local", 156 Path: filepath.Join(path.Dir(dbPath), "user_db1.json"), 157 }, 158 shouldErr: true, 159 err: errors.ErrIdentityStoreConfigureLoggerNotFound, 160 }, 161 } 162 for _, tc := range testcases { 163 t.Run(tc.name, func(t *testing.T) { 164 got := make(map[string]interface{}) 165 msgs := []string{fmt.Sprintf("test name: %s", tc.name)} 166 msgs = append(msgs, fmt.Sprintf("db path: %v", tc.config.Path)) 167 msgs = append(msgs, fmt.Sprintf("config:\n%v", tc.config)) 168 169 st, err := NewIdentityStore(tc.config, tc.logger) 170 if tests.EvalErrWithLog(t, err, "NewIdentityStore", tc.shouldErr, tc.err, msgs) { 171 return 172 } 173 174 if tc.testRequests { 175 results := make(map[string]bool) 176 if err := st.Configure(); err != nil { 177 t.Fatalf("configuration error: %v", err) 178 } 179 180 ops := []operator.Type{ 181 operator.ChangePassword, 182 operator.AddKeySSH, 183 operator.AddKeyGPG, 184 operator.GetPublicKeys, 185 operator.DeletePublicKey, 186 operator.AddMfaToken, 187 operator.GetMfaTokens, 188 operator.GetMfaToken, 189 operator.DeleteMfaToken, 190 operator.AddUser, 191 operator.GetUser, 192 operator.GetUsers, 193 operator.DeleteUser, 194 operator.IdentifyUser, 195 operator.AddAPIKey, 196 operator.DeleteAPIKey, 197 operator.GetAPIKeys, 198 operator.LookupAPIKey, 199 } 200 201 if tc.publicKeysEnabled { 202 ops = append(ops, operator.GetPublicKeys) 203 } 204 205 for _, op := range ops { 206 req := &requests.Request{ 207 User: requests.User{ 208 Username: tests.TestUser1, 209 Email: tests.TestEmail1, 210 }, 211 } 212 if op == operator.GetPublicKeys { 213 req.Key = requests.Key{ 214 Usage: "ssh", 215 } 216 } 217 218 if err := st.Request(op, req); err != nil { 219 results[op.String()] = true 220 } else { 221 results[op.String()] = false 222 } 223 } 224 225 got["ops"] = results 226 } 227 228 got["name"] = st.GetName() 229 got["realm"] = st.GetRealm() 230 got["config"] = st.GetConfig() 231 got["kind"] = st.GetKind() 232 233 tests.EvalObjectsWithLog(t, "config", tc.want, got, msgs) 234 }) 235 } 236 } 237 238 func TestConfigureIdentityStore(t *testing.T) { 239 db, err := testutils.CreateTestDatabase("TestLocalIdentityStore") 240 if err != nil { 241 t.Fatalf("failed to create temp dir: %v", err) 242 } 243 dbPath := db.GetPath() 244 testcases := []struct { 245 name string 246 configs []*Config 247 testRequests bool 248 skipPublicKeys bool 249 want map[string]interface{} 250 shouldErr bool 251 err error 252 }{ 253 { 254 name: "test two configs having same realm and same path", 255 configs: []*Config{ 256 &Config{ 257 Name: "local_store", 258 Realm: "local", 259 Path: dbPath, 260 }, 261 &Config{ 262 Name: "local_store", 263 Realm: "local", 264 Path: dbPath, 265 }, 266 }, 267 want: map[string]interface{}{ 268 "local_store_kind": "local", 269 "local_store_realm": "local", 270 "local_store_config": map[string]interface{}{ 271 "name": "local_store", 272 "realm": "local", 273 "path": dbPath, 274 "login_icon": map[string]interface{}{ 275 "background_color": string("#324960"), 276 "class_name": string("las la-key la-2x"), 277 "color": string("white"), 278 "text_color": string("#37474f"), 279 }, 280 }, 281 "local_store_configured": true, 282 }, 283 }, 284 { 285 name: "test unsupported file path", 286 configs: []*Config{ 287 &Config{ 288 Name: "local_store", 289 Realm: "local", 290 Path: "/dev/null", 291 }, 292 }, 293 shouldErr: true, 294 err: errors.ErrNewDatabase.WithArgs("/dev/null", "null path"), 295 }, 296 } 297 for _, tc := range testcases { 298 t.Run(tc.name, func(t *testing.T) { 299 got := make(map[string]interface{}) 300 msgs := []string{fmt.Sprintf("test name: %s", tc.name)} 301 logger := logutil.NewLogger() 302 303 for i, config := range tc.configs { 304 msgs = append(msgs, fmt.Sprintf("db path %d: %v", i, config.Path)) 305 msgs = append(msgs, fmt.Sprintf("config:\n%v", config)) 306 b, err := NewIdentityStore(config, logger) 307 if err != nil { 308 t.Fatalf("failed creating identity store: %v", err) 309 } 310 311 err = b.Configure() 312 if i == 0 && len(tc.configs) > 1 { 313 if err != nil { 314 t.Fatalf("first config expected to succeed, got error: %v", err) 315 } 316 } else { 317 if tests.EvalErrWithLog(t, err, "Configure", tc.shouldErr, tc.err, msgs) { 318 return 319 } 320 } 321 322 got[b.GetName()+"_realm"] = b.GetRealm() 323 got[b.GetName()+"_kind"] = b.GetKind() 324 got[b.GetName()+"_config"] = b.GetConfig() 325 got[b.GetName()+"_configured"] = b.Configured() 326 } 327 tests.EvalObjectsWithLog(t, "config", tc.want, got, msgs) 328 }) 329 } 330 }