75473b4cba
Before, this logic was only in the OIDCServer.CodeToken() method; now it has been pulled out so that other paths, like OIDCServer.RefreshToken() can use it. The net affect, is that now refresh tokens can be used to get cross-client authenticated ID Tokens.
275 lines
6.7 KiB
Go
275 lines
6.7 KiB
Go
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,
|
|
}
|
|
testClients = []client.LoadableClient{
|
|
{
|
|
Client: client.Client{
|
|
Credentials: testClientCredentials,
|
|
Metadata: oidc.ClientMetadata{
|
|
RedirectURIs: []url.URL{
|
|
testRedirectURL,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
testConnectorID1 = "IDPC-1"
|
|
|
|
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: "oidc",
|
|
IssuerURL: testIssuerURL.String(),
|
|
ClientID: "12345",
|
|
ClientSecret: "567789",
|
|
},
|
|
&connector.OIDCConnectorConfig{
|
|
ID: "oidc-trusted",
|
|
IssuerURL: testIssuerURL.String(),
|
|
ClientID: "12345-trusted",
|
|
ClientSecret: "567789-trusted",
|
|
TrustedEmailProvider: true,
|
|
},
|
|
&connector.LocalConnectorConfig{
|
|
ID: "local",
|
|
},
|
|
}
|
|
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{})
|
|
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,
|
|
"noreply@example.com",
|
|
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
|
|
}
|