func TestDBRefreshRepoCreate(t *testing.T) { r := db.NewRefreshTokenRepo(connect(t)) tests := []struct { userID string clientID string err error }{ { "", "client-foo", refresh.ErrorInvalidUserID, }, { "user-foo", "", refresh.ErrorInvalidClientID, }, { "user-foo", "client-foo", nil, }, } for i, tt := range tests { _, err := r.Create(tt.userID, tt.clientID) if err != tt.err { t.Errorf("Case #%d: expected: %v, got: %v", i, tt.err, err) } } }
func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients []client.LoadableClient) refresh.RefreshTokenRepo { dbMap := connect(t) if _, err := db.NewUserRepoFromUsers(dbMap, users); err != nil { t.Fatalf("Unable to add users: %v", err) } if _, err := db.NewClientRepoFromClients(dbMap, clients); err != nil { t.Fatalf("Unable to add clients: %v", err) } return db.NewRefreshTokenRepo(dbMap) }
func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients []client.Client) refresh.RefreshTokenRepo { var dbMap *gorp.DbMap if dsn := os.Getenv("DEX_TEST_DSN"); dsn == "" { dbMap = db.NewMemDB() } else { dbMap = connect(t) } if _, err := db.NewUserRepoFromUsers(dbMap, users); err != nil { t.Fatalf("Unable to add users: %v", err) } if _, err := manager.NewClientManagerFromClients(db.NewClientRepo(dbMap), db.TransactionFactory(dbMap), clients, manager.ManagerOptions{}); err != nil { t.Fatalf("Unable to add clients: %v", err) } return db.NewRefreshTokenRepo(dbMap) }
func (cfg *MultiServerConfig) Configure(srv *Server) error { if len(cfg.KeySecrets) == 0 { return errors.New("missing key secret") } if cfg.DatabaseConfig.DSN == "" { return errors.New("missing database connection string") } dbc, err := db.NewConnection(cfg.DatabaseConfig) if err != nil { return fmt.Errorf("unable to initialize database connection: %v", err) } if _, ok := dbc.Dialect.(gorp.PostgresDialect); !ok { return errors.New("only postgres backend supported for multi server configurations") } kRepo, err := db.NewPrivateKeySetRepo(dbc, cfg.UseOldFormat, cfg.KeySecrets...) if err != nil { return fmt.Errorf("unable to create PrivateKeySetRepo: %v", err) } ciRepo := db.NewClientRepo(dbc) sRepo := db.NewSessionRepo(dbc) skRepo := db.NewSessionKeyRepo(dbc) cfgRepo := db.NewConnectorConfigRepo(dbc) userRepo := db.NewUserRepo(dbc) pwiRepo := db.NewPasswordInfoRepo(dbc) userManager := usermanager.NewUserManager(userRepo, pwiRepo, cfgRepo, db.TransactionFactory(dbc), usermanager.ManagerOptions{}) clientManager := clientmanager.NewClientManager(ciRepo, db.TransactionFactory(dbc), clientmanager.ManagerOptions{}) refreshTokenRepo := db.NewRefreshTokenRepo(dbc) sm := sessionmanager.NewSessionManager(sRepo, skRepo) srv.ClientRepo = ciRepo srv.ClientManager = clientManager srv.KeySetRepo = kRepo srv.ConnectorConfigRepo = cfgRepo srv.UserRepo = userRepo srv.UserManager = userManager srv.PasswordInfoRepo = pwiRepo srv.SessionManager = sm srv.RefreshTokenRepo = refreshTokenRepo srv.HealthChecks = append(srv.HealthChecks, db.NewHealthChecker(dbc)) srv.dbMap = dbc return nil }
func TestDBRefreshRepoCreate(t *testing.T) { r := db.NewRefreshTokenRepo(connect(t)) tests := []struct { userID string clientID string err error }{ { "", "client-foo", refresh.ErrorInvalidUserID, }, { "user-foo", "", refresh.ErrorInvalidClientID, }, { "user-foo", "client-foo", nil, }, } for i, tt := range tests { token, err := r.Create(tt.userID, tt.clientID) if err != nil { if tt.err == nil { t.Errorf("case %d: create failed: %v", i, err) } continue } if tt.err != nil { t.Errorf("case %d: expected error, didn't get one", i) continue } userID, err := r.Verify(tt.clientID, token) if err != nil { t.Errorf("case %d: failed to verify good token: %v", i, err) continue } if userID != tt.userID { t.Errorf("case %d: want userID=%s, got userID=%s", i, tt.userID, userID) } } }
func (cfg *MultiServerConfig) Configure(srv *Server) error { if len(cfg.KeySecrets) == 0 { return errors.New("missing key secret") } if cfg.DatabaseConfig.DSN == "" { return errors.New("missing database connection string") } dbc, err := db.NewConnection(cfg.DatabaseConfig) if err != nil { return fmt.Errorf("unable to initialize database connection: %v", err) } kRepo, err := db.NewPrivateKeySetRepo(dbc, cfg.UseOldFormat, cfg.KeySecrets...) if err != nil { return fmt.Errorf("unable to create PrivateKeySetRepo: %v", err) } ciRepo := db.NewClientIdentityRepo(dbc) sRepo := db.NewSessionRepo(dbc) skRepo := db.NewSessionKeyRepo(dbc) cfgRepo := db.NewConnectorConfigRepo(dbc) userRepo := db.NewUserRepo(dbc) pwiRepo := db.NewPasswordInfoRepo(dbc) userManager := user.NewManager(userRepo, pwiRepo, db.TransactionFactory(dbc), user.ManagerOptions{}) refreshTokenRepo := db.NewRefreshTokenRepo(dbc) sm := session.NewSessionManager(sRepo, skRepo) srv.ClientIdentityRepo = ciRepo srv.KeySetRepo = kRepo srv.ConnectorConfigRepo = cfgRepo srv.UserRepo = userRepo srv.UserManager = userManager srv.PasswordInfoRepo = pwiRepo srv.SessionManager = sm srv.RefreshTokenRepo = refreshTokenRepo return nil }
func makeUserAPITestFixtures(clientCredsFlag bool) *userAPITestFixtures { f := &userAPITestFixtures{} dbMap, _, _, um := makeUserObjects(userUsers, userPasswords) clients := []client.LoadableClient{ { Client: client.Client{ Credentials: oidc.ClientCredentials{ ID: testClientID, Secret: testClientSecret, }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ testRedirectURL, }, }, }, }, { Client: client.Client{ Credentials: oidc.ClientCredentials{ ID: userBadClientID, Secret: base64.URLEncoding.EncodeToString([]byte("secret")), }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ testBadRedirectURL, }, }, }, }, } _, clientManager, err := makeClientRepoAndManager(dbMap, clients) if err != nil { panic("Failed to create client identity manager: " + err.Error()) } clientManager.SetDexAdmin(testClientID, true) noop := func() error { return nil } keysFunc := func() []key.PublicKey { return []key.PublicKey{*key.NewPublicKey(testPrivKey.JWK())} } jwtvFactory := func(clientID string) oidc.JWTVerifier { return oidc.NewJWTVerifier(testIssuerURL.String(), clientID, noop, keysFunc) } refreshRepo := db.NewRefreshTokenRepo(dbMap) for _, user := range userUsers { if _, err := refreshRepo.Create(user.User.ID, testClientID, "", append([]string{"offline_access"}, oidc.DefaultScope...)); err != nil { panic("Failed to create refresh token: " + err.Error()) } } f.emailer = &testEmailer{} um.Clock = clock api := api.NewUsersAPI(um, clientManager, refreshRepo, f.emailer, "local", clientCredsFlag) usrSrv := server.NewUserMgmtServer(api, jwtvFactory, um, clientManager, clientCredsFlag) f.hSrv = httptest.NewServer(usrSrv.HTTPHandler()) f.trans = &tokenHandlerTransport{ Handler: usrSrv.HTTPHandler(), Token: userGoodToken, } hc := &http.Client{ Transport: f.trans, } f.client, _ = schema.NewWithBasePath(hc, f.hSrv.URL) return f }
func (cfg *SingleServerConfig) Configure(srv *Server) error { k, err := key.GeneratePrivateKey() if err != nil { return err } dbMap := db.NewMemDB() ks := key.NewPrivateKeySet([]*key.PrivateKey{k}, time.Now().Add(24*time.Hour)) kRepo := key.NewPrivateKeySetRepo() if err = kRepo.Set(ks); err != nil { return err } clients, err := loadClients(cfg.ClientsFile) if err != nil { return fmt.Errorf("unable to read clients from file %s: %v", cfg.ClientsFile, err) } clientRepo, err := db.NewClientRepoFromClients(dbMap, clients) if err != nil { return err } f, err := os.Open(cfg.ConnectorsFile) if err != nil { return fmt.Errorf("opening connectors file: %v", err) } defer f.Close() cfgs, err := connector.ReadConfigs(f) if err != nil { return fmt.Errorf("decoding connector configs: %v", err) } cfgRepo := db.NewConnectorConfigRepo(dbMap) if err := cfgRepo.Set(cfgs); err != nil { return fmt.Errorf("failed to set connectors: %v", err) } sRepo := db.NewSessionRepo(dbMap) skRepo := db.NewSessionKeyRepo(dbMap) sm := sessionmanager.NewSessionManager(sRepo, skRepo) users, pwis, err := loadUsers(cfg.UsersFile) if err != nil { return fmt.Errorf("unable to read users from file: %v", err) } userRepo, err := db.NewUserRepoFromUsers(dbMap, users) if err != nil { return err } pwiRepo, err := db.NewPasswordInfoRepoFromPasswordInfos(dbMap, pwis) if err != nil { return err } refTokRepo := db.NewRefreshTokenRepo(dbMap) txnFactory := db.TransactionFactory(dbMap) userManager := usermanager.NewUserManager(userRepo, pwiRepo, cfgRepo, txnFactory, usermanager.ManagerOptions{}) clientManager := clientmanager.NewClientManager(clientRepo, db.TransactionFactory(dbMap), clientmanager.ManagerOptions{}) if err != nil { return fmt.Errorf("Failed to create client identity manager: %v", err) } srv.ClientRepo = clientRepo srv.ClientManager = clientManager srv.KeySetRepo = kRepo srv.ConnectorConfigRepo = cfgRepo srv.UserRepo = userRepo srv.UserManager = userManager srv.PasswordInfoRepo = pwiRepo srv.SessionManager = sm srv.RefreshTokenRepo = refTokRepo srv.HealthChecks = append(srv.HealthChecks, db.NewHealthChecker(dbMap)) srv.dbMap = dbMap return nil }
func makeUserAPITestFixtures() *userAPITestFixtures { f := &userAPITestFixtures{} dbMap, _, _, um := makeUserObjects(userUsers, userPasswords) clients := []client.Client{ client.Client{ Credentials: oidc.ClientCredentials{ ID: testClientID, Secret: testClientSecret, }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ testRedirectURL, }, }, }, client.Client{ Credentials: oidc.ClientCredentials{ ID: userBadClientID, Secret: base64.URLEncoding.EncodeToString([]byte("secret")), }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ testBadRedirectURL, }, }, }, } clientIDGenerator := func(hostport string) (string, error) { return hostport, nil } secGen := func() ([]byte, error) { return []byte(testClientSecret), nil } clientRepo := db.NewClientRepo(dbMap) clientManager, err := manager.NewClientManagerFromClients(clientRepo, db.TransactionFactory(dbMap), clients, manager.ManagerOptions{ClientIDGenerator: clientIDGenerator, SecretGenerator: secGen}) if err != nil { panic("Failed to create client identity manager: " + err.Error()) } clientManager.SetDexAdmin(testClientID, true) noop := func() error { return nil } keysFunc := func() []key.PublicKey { return []key.PublicKey{*key.NewPublicKey(testPrivKey.JWK())} } jwtvFactory := func(clientID string) oidc.JWTVerifier { return oidc.NewJWTVerifier(testIssuerURL.String(), clientID, noop, keysFunc) } refreshRepo := db.NewRefreshTokenRepo(dbMap) for _, user := range userUsers { if _, err := refreshRepo.Create(user.User.ID, testClientID); err != nil { panic("Failed to create refresh token: " + err.Error()) } } f.emailer = &testEmailer{} um.Clock = clock api := api.NewUsersAPI(um, clientManager, refreshRepo, f.emailer, "local") usrSrv := server.NewUserMgmtServer(api, jwtvFactory, um, clientManager) f.hSrv = httptest.NewServer(usrSrv.HTTPHandler()) f.trans = &tokenHandlerTransport{ Handler: usrSrv.HTTPHandler(), Token: userGoodToken, } hc := &http.Client{ Transport: f.trans, } f.client, _ = schema.NewWithBasePath(hc, f.hSrv.URL) return f }
func TestDBRefreshRepoRevoke(t *testing.T) { r := db.NewRefreshTokenRepo(connect(t)) token, err := r.Create("user-foo", "client-foo") if err != nil { t.Fatalf("Unexpected error: %v", err) } badTokenPayload, err := refresh.DefaultRefreshTokenGenerator() if err != nil { t.Fatalf("Unexpected error: %v", err) } tokenWithBadID := "404" + token[1:] tokenWithBadPayload := buildRefreshToken(1, badTokenPayload) tests := []struct { token string userID string err error }{ { "invalid-token-format", "user-foo", refresh.ErrorInvalidToken, }, { "1/invalid-base64-encoded-format", "user-foo", refresh.ErrorInvalidToken, }, { token + "corrupted-token-payload", "user-foo", refresh.ErrorInvalidToken, }, { // The token's ID is invalid. tokenWithBadID, "user-foo", refresh.ErrorInvalidToken, }, { // The token's payload is invalid. tokenWithBadPayload, "user-foo", refresh.ErrorInvalidToken, }, { token, "invalid-user", refresh.ErrorInvalidUserID, }, { token, "user-foo", nil, }, } for i, tt := range tests { if err := r.Revoke(tt.userID, tt.token); err != tt.err { t.Errorf("Case #%d: expected: %v, got: %v", i, tt.err, err) } } }
func TestDBRefreshRepoVerify(t *testing.T) { r := db.NewRefreshTokenRepo(connect(t)) token, err := r.Create("user-foo", "client-foo") if err != nil { t.Fatalf("Unexpected error: %v", err) } badTokenPayload, err := refresh.DefaultRefreshTokenGenerator() if err != nil { t.Fatalf("Unexpected error: %v", err) } tokenWithBadID := "404" + token[1:] tokenWithBadPayload := buildRefreshToken(1, badTokenPayload) tests := []struct { token string creds oidc.ClientCredentials err error expected string }{ { "invalid-token-format", oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { "b/invalid-base64-encoded-format", oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { "1/invalid-base64-encoded-format", oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { token + "corrupted-token-payload", oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { // The token's ID content is invalid. tokenWithBadID, oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { // The token's payload content is invalid. tokenWithBadPayload, oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, refresh.ErrorInvalidToken, "", }, { token, oidc.ClientCredentials{ID: "invalid-client", Secret: "secret-foo"}, refresh.ErrorInvalidClientID, "", }, { token, oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"}, nil, "user-foo", }, } for i, tt := range tests { result, err := r.Verify(tt.creds.ID, tt.token) if err != tt.err { t.Errorf("Case #%d: expected: %v, got: %v", i, tt.err, err) } if result != tt.expected { t.Errorf("Case #%d: expected: %v, got: %v", i, tt.expected, result) } } }
func makeTestFixtures(clientCredsFlag bool) (*UsersAPI, *testEmailer) { dbMap := db.NewMemDB() ur := func() user.UserRepo { repo, err := db.NewUserRepoFromUsers(dbMap, []user.UserWithRemoteIdentities{ { User: user.User{ ID: "ID-1", Email: "*****@*****.**", Admin: true, CreatedAt: clock.Now(), }, }, { User: user.User{ ID: "ID-2", Email: "*****@*****.**", EmailVerified: true, CreatedAt: clock.Now(), }, }, { User: user.User{ ID: "ID-3", Email: "*****@*****.**", CreatedAt: clock.Now(), }, }, { User: user.User{ ID: "ID-4", Email: "*****@*****.**", CreatedAt: clock.Now(), Disabled: true, }, }, }) if err != nil { panic("Failed to create user repo: " + err.Error()) } return repo }() pwr := func() user.PasswordInfoRepo { repo, err := db.NewPasswordInfoRepoFromPasswordInfos(dbMap, []user.PasswordInfo{ { UserID: "ID-1", Password: []byte("password-1"), }, { UserID: "ID-2", Password: []byte("password-2"), }, }) if err != nil { panic("Failed to create user repo: " + err.Error()) } return repo }() ccr := func() connector.ConnectorConfigRepo { repo := db.NewConnectorConfigRepo(dbMap) c := []connector.ConnectorConfig{ &connector.LocalConnectorConfig{ID: "local"}, } if err := repo.Set(c); err != nil { panic(err) } return repo }() mgr := manager.NewUserManager(ur, pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{}) mgr.Clock = clock ci := client.Client{ Credentials: oidc.ClientCredentials{ ID: goodClientID, Secret: base64.URLEncoding.EncodeToString([]byte("secret")), }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ validRedirURL, }, }, } ci2 := client.Client{ Credentials: oidc.ClientCredentials{ ID: nonAdminClientID, Secret: base64.URLEncoding.EncodeToString([]byte("anothersecret")), }, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ validRedirURL2, }, }, } clientIDGenerator := func(hostport string) (string, error) { return hostport, nil } secGen := func() ([]byte, error) { return []byte("secret"), nil } clientRepo, err := db.NewClientRepoFromClients(dbMap, []client.LoadableClient{{Client: ci}, {Client: ci2}}) if err != nil { panic("Failed to create client manager: " + err.Error()) } clientManager := clientmanager.NewClientManager(clientRepo, db.TransactionFactory(dbMap), clientmanager.ManagerOptions{ClientIDGenerator: clientIDGenerator, SecretGenerator: secGen}) // Used in TestRevokeRefreshToken test. refreshTokens := []struct { clientID string userID string }{ {goodClientID, "ID-1"}, {goodClientID, "ID-2"}, } refreshRepo := db.NewRefreshTokenRepo(dbMap) for _, token := range refreshTokens { if _, err := refreshRepo.Create(token.userID, token.clientID, "local", []string{"openid"}); err != nil { panic("Failed to create refresh token: " + err.Error()) } } emailer := &testEmailer{} api := NewUsersAPI(mgr, clientManager, refreshRepo, emailer, "local", clientCredsFlag) return api, emailer }