diff --git a/storage/conformance/conformance.go b/storage/conformance/conformance.go index 7ebd7cf9..0d41ba2a 100644 --- a/storage/conformance/conformance.go +++ b/storage/conformance/conformance.go @@ -80,9 +80,9 @@ func mustBeErrAlreadyExists(t *testing.T, kind string, err error) { } func testAuthRequestCRUD(t *testing.T, s storage.Storage) { - a := storage.AuthRequest{ + a1 := storage.AuthRequest{ ID: storage.NewID(), - ClientID: "foobar", + ClientID: "client1", ResponseTypes: []string{"code"}, Scopes: []string{"openid", "email"}, RedirectURI: "https://localhost:80/callback", @@ -104,15 +104,41 @@ func testAuthRequestCRUD(t *testing.T, s storage.Storage) { identity := storage.Claims{Email: "foobar"} - if err := s.CreateAuthRequest(a); err != nil { + if err := s.CreateAuthRequest(a1); err != nil { t.Fatalf("failed creating auth request: %v", err) } // Attempt to create same AuthRequest twice. - err := s.CreateAuthRequest(a) + err := s.CreateAuthRequest(a1) mustBeErrAlreadyExists(t, "auth request", err) - if err := s.UpdateAuthRequest(a.ID, func(old storage.AuthRequest) (storage.AuthRequest, error) { + a2 := storage.AuthRequest{ + ID: storage.NewID(), + ClientID: "client2", + ResponseTypes: []string{"code"}, + Scopes: []string{"openid", "email"}, + RedirectURI: "https://localhost:80/callback", + Nonce: "bar", + State: "foo", + ForceApprovalPrompt: true, + LoggedIn: true, + Expiry: neverExpire, + ConnectorID: "ldap", + ConnectorData: []byte(`{"some":"data"}`), + Claims: storage.Claims{ + UserID: "2", + Username: "john", + Email: "john.doe@example.com", + EmailVerified: true, + Groups: []string{"a"}, + }, + } + + if err := s.CreateAuthRequest(a2); err != nil { + t.Fatalf("failed creating auth request: %v", err) + } + + if err := s.UpdateAuthRequest(a1.ID, func(old storage.AuthRequest) (storage.AuthRequest, error) { old.Claims = identity old.ConnectorID = "connID" return old, nil @@ -120,19 +146,28 @@ func testAuthRequestCRUD(t *testing.T, s storage.Storage) { t.Fatalf("failed to update auth request: %v", err) } - got, err := s.GetAuthRequest(a.ID) + got, err := s.GetAuthRequest(a1.ID) if err != nil { t.Fatalf("failed to get auth req: %v", err) } if !reflect.DeepEqual(got.Claims, identity) { t.Fatalf("update failed, wanted identity=%#v got %#v", identity, got.Claims) } + + if err := s.DeleteAuthRequest(a1.ID); err != nil { + t.Fatalf("failed to delete auth request: %v", err) + } + + if err := s.DeleteAuthRequest(a2.ID); err != nil { + t.Fatalf("failed to delete auth request: %v", err) + } + } func testAuthCodeCRUD(t *testing.T, s storage.Storage) { - a := storage.AuthCode{ + a1 := storage.AuthCode{ ID: storage.NewID(), - ClientID: "foobar", + ClientID: "client1", RedirectURI: "https://localhost:80/callback", Nonce: "foobar", Scopes: []string{"openid", "email"}, @@ -148,56 +183,95 @@ func testAuthCodeCRUD(t *testing.T, s storage.Storage) { }, } - if err := s.CreateAuthCode(a); err != nil { + if err := s.CreateAuthCode(a1); err != nil { t.Fatalf("failed creating auth code: %v", err) } + a2 := storage.AuthCode{ + ID: storage.NewID(), + ClientID: "client2", + RedirectURI: "https://localhost:80/callback", + Nonce: "foobar", + Scopes: []string{"openid", "email"}, + Expiry: neverExpire, + ConnectorID: "ldap", + ConnectorData: []byte(`{"some":"data"}`), + Claims: storage.Claims{ + UserID: "2", + Username: "john", + Email: "john.doe@example.com", + EmailVerified: true, + Groups: []string{"a"}, + }, + } + // Attempt to create same AuthCode twice. - err := s.CreateAuthCode(a) + err := s.CreateAuthCode(a1) mustBeErrAlreadyExists(t, "auth code", err) - got, err := s.GetAuthCode(a.ID) + if err := s.CreateAuthCode(a2); err != nil { + t.Fatalf("failed creating auth code: %v", err) + } + + got, err := s.GetAuthCode(a1.ID) if err != nil { t.Fatalf("failed to get auth req: %v", err) } - if a.Expiry.Unix() != got.Expiry.Unix() { - t.Errorf("auth code expiry did not match want=%s vs got=%s", a.Expiry, got.Expiry) + if a1.Expiry.Unix() != got.Expiry.Unix() { + t.Errorf("auth code expiry did not match want=%s vs got=%s", a1.Expiry, got.Expiry) } - got.Expiry = a.Expiry // time fields do not compare well - if diff := pretty.Compare(a, got); diff != "" { + got.Expiry = a1.Expiry // time fields do not compare well + if diff := pretty.Compare(a1, got); diff != "" { t.Errorf("auth code retrieved from storage did not match: %s", diff) } - if err := s.DeleteAuthCode(a.ID); err != nil { + if err := s.DeleteAuthCode(a1.ID); err != nil { t.Fatalf("delete auth code: %v", err) } - _, err = s.GetAuthCode(a.ID) + if err := s.DeleteAuthCode(a2.ID); err != nil { + t.Fatalf("delete auth code: %v", err) + } + + _, err = s.GetAuthCode(a1.ID) mustBeErrNotFound(t, "auth code", err) } func testClientCRUD(t *testing.T, s storage.Storage) { - id := storage.NewID() - c := storage.Client{ - ID: id, + id1 := storage.NewID() + c1 := storage.Client{ + ID: id1, Secret: "foobar", RedirectURIs: []string{"foo://bar.com/", "https://auth.example.com"}, Name: "dex client", LogoURL: "https://goo.gl/JIyzIC", } - err := s.DeleteClient(id) + err := s.DeleteClient(id1) mustBeErrNotFound(t, "client", err) - if err := s.CreateClient(c); err != nil { + if err := s.CreateClient(c1); err != nil { t.Fatalf("create client: %v", err) } // Attempt to create same Client twice. - err = s.CreateClient(c) + err = s.CreateClient(c1) mustBeErrAlreadyExists(t, "client", err) + id2 := storage.NewID() + c2 := storage.Client{ + ID: id2, + Secret: "barfoo", + RedirectURIs: []string{"foo://bar.com/", "https://auth.example.com"}, + Name: "dex client", + LogoURL: "https://goo.gl/JIyzIC", + } + + if err := s.CreateClient(c2); err != nil { + t.Fatalf("create client: %v", err) + } + getAndCompare := func(id string, want storage.Client) { - gc, err := s.GetClient(id) + gc, err := s.GetClient(id1) if err != nil { t.Errorf("get client: %v", err) return @@ -207,24 +281,28 @@ func testClientCRUD(t *testing.T, s storage.Storage) { } } - getAndCompare(id, c) + getAndCompare(id1, c1) newSecret := "barfoo" - err = s.UpdateClient(id, func(old storage.Client) (storage.Client, error) { + err = s.UpdateClient(id1, func(old storage.Client) (storage.Client, error) { old.Secret = newSecret return old, nil }) if err != nil { t.Errorf("update client: %v", err) } - c.Secret = newSecret - getAndCompare(id, c) + c1.Secret = newSecret + getAndCompare(id1, c1) - if err := s.DeleteClient(id); err != nil { + if err := s.DeleteClient(id1); err != nil { t.Fatalf("delete client: %v", err) } - _, err = s.GetClient(id) + if err := s.DeleteClient(id2); err != nil { + t.Fatalf("delete client: %v", err) + } + + _, err = s.GetClient(id1) mustBeErrNotFound(t, "client", err) } @@ -316,6 +394,10 @@ func testRefreshTokenCRUD(t *testing.T, s storage.Storage) { t.Fatalf("failed to delete refresh request: %v", err) } + if err := s.DeleteRefresh(id2); err != nil { + t.Fatalf("failed to delete refresh request: %v", err) + } + _, err = s.GetRefresh(id) mustBeErrNotFound(t, "refresh token", err) } @@ -328,25 +410,40 @@ func (n byEmail) Swap(i, j int) { n[i], n[j] = n[j], n[i] } func testPasswordCRUD(t *testing.T, s storage.Storage) { // Use bcrypt.MinCost to keep the tests short. - passwordHash, err := bcrypt.GenerateFromPassword([]byte("secret"), bcrypt.MinCost) + passwordHash1, err := bcrypt.GenerateFromPassword([]byte("secret"), bcrypt.MinCost) if err != nil { t.Fatal(err) } - password := storage.Password{ + password1 := storage.Password{ Email: "jane@example.com", - Hash: passwordHash, + Hash: passwordHash1, Username: "jane", UserID: "foobar", } - if err := s.CreatePassword(password); err != nil { + if err := s.CreatePassword(password1); err != nil { t.Fatalf("create password token: %v", err) } // Attempt to create same Password twice. - err = s.CreatePassword(password) + err = s.CreatePassword(password1) mustBeErrAlreadyExists(t, "password", err) + passwordHash2, err := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.MinCost) + if err != nil { + t.Fatal(err) + } + + password2 := storage.Password{ + Email: "john@example.com", + Hash: passwordHash2, + Username: "john", + UserID: "barfoo", + } + if err := s.CreatePassword(password2); err != nil { + t.Fatalf("create password token: %v", err) + } + getAndCompare := func(id string, want storage.Password) { gr, err := s.GetPassword(id) if err != nil { @@ -358,21 +455,21 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) { } } - getAndCompare("jane@example.com", password) - getAndCompare("JANE@example.com", password) // Emails should be case insensitive + getAndCompare("jane@example.com", password1) + getAndCompare("JANE@example.com", password1) // Emails should be case insensitive - if err := s.UpdatePassword(password.Email, func(old storage.Password) (storage.Password, error) { + if err := s.UpdatePassword(password1.Email, func(old storage.Password) (storage.Password, error) { old.Username = "jane doe" return old, nil }); err != nil { t.Fatalf("failed to update auth request: %v", err) } - password.Username = "jane doe" - getAndCompare("jane@example.com", password) + password1.Username = "jane doe" + getAndCompare("jane@example.com", password1) var passwordList []storage.Password - passwordList = append(passwordList, password) + passwordList = append(passwordList, password1, password2) listAndCompare := func(want []storage.Password) { passwords, err := s.ListPasswords() @@ -389,32 +486,48 @@ func testPasswordCRUD(t *testing.T, s storage.Storage) { listAndCompare(passwordList) - if err := s.DeletePassword(password.Email); err != nil { + if err := s.DeletePassword(password1.Email); err != nil { t.Fatalf("failed to delete password: %v", err) } - _, err = s.GetPassword(password.Email) + if err := s.DeletePassword(password2.Email); err != nil { + t.Fatalf("failed to delete password: %v", err) + } + + _, err = s.GetPassword(password1.Email) mustBeErrNotFound(t, "password", err) } func testOfflineSessionCRUD(t *testing.T, s storage.Storage) { - session := storage.OfflineSessions{ - UserID: "User", - ConnID: "Conn", + userID1 := storage.NewID() + session1 := storage.OfflineSessions{ + UserID: userID1, + ConnID: "Conn1", Refresh: make(map[string]*storage.RefreshTokenRef), } // Creating an OfflineSession with an empty Refresh list to ensure that // an empty map is translated as expected by the storage. - if err := s.CreateOfflineSessions(session); err != nil { - t.Fatalf("create offline session: %v", err) + if err := s.CreateOfflineSessions(session1); err != nil { + t.Fatalf("create offline session with UserID = %s: %v", session1.UserID, err) } // Attempt to create same OfflineSession twice. - err := s.CreateOfflineSessions(session) + err := s.CreateOfflineSessions(session1) mustBeErrAlreadyExists(t, "offline session", err) + userID2 := storage.NewID() + session2 := storage.OfflineSessions{ + UserID: userID2, + ConnID: "Conn2", + Refresh: make(map[string]*storage.RefreshTokenRef), + } + + if err := s.CreateOfflineSessions(session2); err != nil { + t.Fatalf("create offline session with UserID = %s: %v", session2.UserID, err) + } + getAndCompare := func(userID string, connID string, want storage.OfflineSessions) { gr, err := s.GetOfflineSessions(userID, connID) if err != nil { @@ -426,7 +539,7 @@ func testOfflineSessionCRUD(t *testing.T, s storage.Storage) { } } - getAndCompare("User", "Conn", session) + getAndCompare(userID1, "Conn1", session1) id := storage.NewID() tokenRef := storage.RefreshTokenRef{ @@ -435,24 +548,27 @@ func testOfflineSessionCRUD(t *testing.T, s storage.Storage) { CreatedAt: time.Now().UTC().Round(time.Millisecond), LastUsed: time.Now().UTC().Round(time.Millisecond), } - session.Refresh[tokenRef.ClientID] = &tokenRef + session1.Refresh[tokenRef.ClientID] = &tokenRef - if err := s.UpdateOfflineSessions(session.UserID, session.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) { + if err := s.UpdateOfflineSessions(session1.UserID, session1.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) { old.Refresh[tokenRef.ClientID] = &tokenRef return old, nil }); err != nil { t.Fatalf("failed to update offline session: %v", err) } - getAndCompare("User", "Conn", session) + getAndCompare(userID1, "Conn1", session1) - if err := s.DeleteOfflineSessions(session.UserID, session.ConnID); err != nil { + if err := s.DeleteOfflineSessions(session1.UserID, session1.ConnID); err != nil { t.Fatalf("failed to delete offline session: %v", err) } - _, err = s.GetOfflineSessions(session.UserID, session.ConnID) - mustBeErrNotFound(t, "offline session", err) + if err := s.DeleteOfflineSessions(session2.UserID, session2.ConnID); err != nil { + t.Fatalf("failed to delete offline session: %v", err) + } + _, err = s.GetOfflineSessions(session1.UserID, session1.ConnID) + mustBeErrNotFound(t, "offline session", err) } func testKeysCRUD(t *testing.T, s storage.Storage) {