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