package server import ( "encoding/base64" "fmt" "net/url" "time" "github.com/coreos/go-oidc/key" "github.com/coreos/go-oidc/oidc" "github.com/coreos/dex/client" clientmanager "github.com/coreos/dex/client/manager" "github.com/coreos/dex/connector" "github.com/coreos/dex/db" "github.com/coreos/dex/email" "github.com/coreos/dex/refresh/refreshtest" sessionmanager "github.com/coreos/dex/session/manager" "github.com/coreos/dex/user" useremail "github.com/coreos/dex/user/email" usermanager "github.com/coreos/dex/user/manager" ) const ( templatesLocation = "../static/html" emailTemplatesLocation = "../static/email" ) var ( testUserID1 = "ID-1" testUserEmail1 = "Email-1@example.com" testUserRemoteID1 = "RID-1" testIssuerURL = url.URL{Scheme: "http", Host: "server.example.com"} testClientID = "client.example.com" clientTestSecret = base64.URLEncoding.EncodeToString([]byte("secret")) testClientCredentials = oidc.ClientCredentials{ ID: testClientID, Secret: clientTestSecret, } testPublicClientID = "publicclient.example.com" publicClientTestSecret = base64.URLEncoding.EncodeToString([]byte("secret")) testPublicClientCredentials = oidc.ClientCredentials{ ID: testPublicClientID, Secret: publicClientTestSecret, } testClients = []client.LoadableClient{ { Client: client.Client{ Credentials: testClientCredentials, Metadata: oidc.ClientMetadata{ RedirectURIs: []url.URL{ testRedirectURL, }, }, }, }, { Client: client.Client{ Credentials: testPublicClientCredentials, Public: true, }, }, } testConnectorID1 = "IDPC-1" testConnectorIDOpenID = "oidc" testConnectorIDOpenIDTrusted = "oidc-trusted" testConnectorLocalID = "local" testRedirectURL = url.URL{Scheme: "http", Host: "client.example.com", Path: "/callback"} testUsers = []user.UserWithRemoteIdentities{ { User: user.User{ ID: testUserID1, Email: testUserEmail1, }, RemoteIdentities: []user.RemoteIdentity{ { ConnectorID: testConnectorID1, ID: testUserRemoteID1, }, }, }, { User: user.User{ ID: "ID-Verified", Email: "Email-Verified@example.com", EmailVerified: true, }, RemoteIdentities: []user.RemoteIdentity{ { ConnectorID: "IDPC-1", ID: "RID-2", }, }, }, } testPasswordInfos = []user.PasswordInfo{ { UserID: "ID-1", Password: []byte("password"), }, { UserID: "ID-Verified", Password: []byte("password"), }, } testPrivKey, _ = key.GeneratePrivateKey() testClientCreds = oidc.ClientCredentials{ ID: testClientID, Secret: base64.URLEncoding.EncodeToString([]byte("secret")), } ) type testFixtures struct { srv *Server userRepo user.UserRepo sessionManager *sessionmanager.SessionManager emailer *email.TemplatizedEmailer redirectURL url.URL clientRepo client.ClientRepo clientManager *clientmanager.ClientManager clientCreds map[string]oidc.ClientCredentials } type testFixtureOptions struct { clients []client.LoadableClient } func sequentialGenerateCodeFunc() sessionmanager.GenerateCodeFunc { x := 0 return func() (string, error) { x += 1 return fmt.Sprintf("code-%d", x), nil } } func makeTestFixtures() (*testFixtures, error) { return makeTestFixturesWithOptions(testFixtureOptions{}) } func makeTestFixturesWithOptions(options testFixtureOptions) (*testFixtures, error) { dbMap := db.NewMemDB() userRepo, err := db.NewUserRepoFromUsers(dbMap, testUsers) if err != nil { return nil, err } pwRepo, err := db.NewPasswordInfoRepoFromPasswordInfos(dbMap, testPasswordInfos) if err != nil { return nil, err } connConfigs := []connector.ConnectorConfig{ &connector.OIDCConnectorConfig{ ID: testConnectorIDOpenID, IssuerURL: testIssuerURL.String(), ClientID: "12345", ClientSecret: "567789", }, &connector.OIDCConnectorConfig{ ID: testConnectorIDOpenIDTrusted, IssuerURL: testIssuerURL.String(), ClientID: "12345-trusted", ClientSecret: "567789-trusted", TrustedEmailProvider: true, }, &connector.OIDCConnectorConfig{ ID: testConnectorID1, IssuerURL: testIssuerURL.String(), ClientID: testConnectorID1 + "_client_id", ClientSecret: testConnectorID1 + "_client_secret", TrustedEmailProvider: true, }, &connector.LocalConnectorConfig{ ID: testConnectorLocalID, }, } connCfgRepo := db.NewConnectorConfigRepo(dbMap) if err := connCfgRepo.Set(connConfigs); err != nil { return nil, err } userManager := usermanager.NewUserManager(userRepo, pwRepo, connCfgRepo, db.TransactionFactory(dbMap), usermanager.ManagerOptions{}) sessionManager := sessionmanager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())) sessionManager.GenerateCode = sequentialGenerateCodeFunc() refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo() emailer, err := email.NewTemplatizedEmailerFromGlobs( emailTemplatesLocation+"/*.txt", emailTemplatesLocation+"/*.html", &email.FakeEmailer{}, "admin@example.com") if err != nil { return nil, err } var clients []client.LoadableClient if options.clients == nil { clients = testClients } else { clients = options.clients } clientIDGenerator := func(hostport string) (string, error) { return hostport, nil } secGen := func() ([]byte, error) { return []byte("secret"), nil } clientRepo, err := db.NewClientRepoFromClients(dbMap, clients) if err != nil { return nil, err } clientManager := clientmanager.NewClientManager(clientRepo, db.TransactionFactory(dbMap), clientmanager.ManagerOptions{ClientIDGenerator: clientIDGenerator, SecretGenerator: secGen}) km := key.NewPrivateKeyManager() err = km.Set(key.NewPrivateKeySet([]*key.PrivateKey{testPrivKey}, time.Now().Add(time.Minute))) if err != nil { return nil, err } tpl, err := getTemplates("dex", "https://coreos.com/assets/images/brand/coreos-mark-30px.png", true, templatesLocation) if err != nil { return nil, err } srv := &Server{ IssuerURL: testIssuerURL, SessionManager: sessionManager, ClientRepo: clientRepo, Templates: tpl, UserRepo: userRepo, PasswordInfoRepo: pwRepo, UserManager: userManager, ClientManager: clientManager, KeyManager: km, RefreshTokenRepo: refreshTokenRepo, } err = setTemplates(srv, tpl) if err != nil { return nil, err } for _, config := range connConfigs { if err := srv.AddConnector(config); err != nil { return nil, err } } srv.UserEmailer = useremail.NewUserEmailer(srv.UserRepo, srv.PasswordInfoRepo, srv.KeyManager.Signer, srv.SessionManager.ValidityWindow, srv.IssuerURL, emailer, srv.absURL(httpPathResetPassword), srv.absURL(httpPathEmailVerify), srv.absURL(httpPathAcceptInvitation), ) clientCreds := map[string]oidc.ClientCredentials{} for _, c := range clients { clientCreds[c.Client.Credentials.ID] = c.Client.Credentials } return &testFixtures{ srv: srv, redirectURL: testRedirectURL, userRepo: userRepo, sessionManager: sessionManager, emailer: emailer, clientRepo: clientRepo, clientManager: clientManager, clientCreds: clientCreds, }, nil } func clientsToLoadableClients(cs []client.Client) []client.LoadableClient { lcs := make([]client.LoadableClient, len(cs), len(cs)) for i, c := range cs { lcs[i] = client.LoadableClient{ Client: c, } } return lcs }