forked from mystiq/dex
Merge pull request #411 from bobbyrullo/cross_client
Use Client defined in dex instead of go-oidc for storing clients
This commit is contained in:
commit
69ca9dba2e
44 changed files with 1181 additions and 515 deletions
81
admin/api.go
81
admin/api.go
|
@ -5,36 +5,36 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
"github.com/go-gorp/gorp"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/client"
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/db"
|
|
||||||
"github.com/coreos/dex/schema/adminschema"
|
"github.com/coreos/dex/schema/adminschema"
|
||||||
"github.com/coreos/dex/user"
|
"github.com/coreos/dex/user"
|
||||||
"github.com/coreos/dex/user/manager"
|
"github.com/coreos/dex/user/manager"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ClientIDGenerator = oidc.GenClientID
|
||||||
|
)
|
||||||
|
|
||||||
// AdminAPI provides the logic necessary to implement the Admin API.
|
// AdminAPI provides the logic necessary to implement the Admin API.
|
||||||
type AdminAPI struct {
|
type AdminAPI struct {
|
||||||
userManager *manager.UserManager
|
userManager *manager.UserManager
|
||||||
userRepo user.UserRepo
|
userRepo user.UserRepo
|
||||||
passwordInfoRepo user.PasswordInfoRepo
|
passwordInfoRepo user.PasswordInfoRepo
|
||||||
clientIdentityRepo client.ClientIdentityRepo
|
clientRepo client.ClientRepo
|
||||||
localConnectorID string
|
localConnectorID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ericchiang): Swap the DbMap for a storage interface. See #278
|
func NewAdminAPI(userRepo user.UserRepo, pwiRepo user.PasswordInfoRepo, clientRepo client.ClientRepo, userManager *manager.UserManager, localConnectorID string) *AdminAPI {
|
||||||
|
|
||||||
func NewAdminAPI(dbMap *gorp.DbMap, userManager *manager.UserManager, localConnectorID string) *AdminAPI {
|
|
||||||
if localConnectorID == "" {
|
if localConnectorID == "" {
|
||||||
panic("must specify non-blank localConnectorID")
|
panic("must specify non-blank localConnectorID")
|
||||||
}
|
}
|
||||||
return &AdminAPI{
|
return &AdminAPI{
|
||||||
userManager: userManager,
|
userManager: userManager,
|
||||||
userRepo: db.NewUserRepo(dbMap),
|
userRepo: userRepo,
|
||||||
passwordInfoRepo: db.NewPasswordInfoRepo(dbMap),
|
passwordInfoRepo: pwiRepo,
|
||||||
clientIdentityRepo: db.NewClientIdentityRepo(dbMap),
|
clientRepo: clientRepo,
|
||||||
localConnectorID: localConnectorID,
|
localConnectorID: localConnectorID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +67,20 @@ func errorMaker(typ string, desc string, code int) func(internal error) Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
ErrorMissingClient = errorMaker("bad_request", "The 'client' cannot be empty", http.StatusBadRequest)(nil)
|
||||||
|
|
||||||
|
// Called when oidc.ClientMetadata.Valid() fails.
|
||||||
|
ErrorInvalidClientFunc = errorMaker("bad_request", "Your client could not be validated.", http.StatusBadRequest)
|
||||||
|
|
||||||
errorMap = map[error]func(error) Error{
|
errorMap = map[error]func(error) Error{
|
||||||
user.ErrorNotFound: errorMaker("resource_not_found", "Resource could not be found.", http.StatusNotFound),
|
user.ErrorNotFound: errorMaker("resource_not_found", "Resource could not be found.", http.StatusNotFound),
|
||||||
user.ErrorDuplicateEmail: errorMaker("bad_request", "Email already in use.", http.StatusBadRequest),
|
user.ErrorDuplicateEmail: errorMaker("bad_request", "Email already in use.", http.StatusBadRequest),
|
||||||
user.ErrorInvalidEmail: errorMaker("bad_request", "invalid email.", http.StatusBadRequest),
|
user.ErrorInvalidEmail: errorMaker("bad_request", "invalid email.", http.StatusBadRequest),
|
||||||
|
|
||||||
|
adminschema.ErrorInvalidRedirectURI: errorMaker("bad_request", "invalid redirectURI.", http.StatusBadRequest),
|
||||||
|
adminschema.ErrorInvalidLogoURI: errorMaker("bad_request", "invalid logoURI.", http.StatusBadRequest),
|
||||||
|
adminschema.ErrorInvalidClientURI: errorMaker("bad_request", "invalid clientURI.", http.StatusBadRequest),
|
||||||
|
adminschema.ErrorNoRedirectURI: errorMaker("bad_request", "invalid redirectURI.", http.StatusBadRequest),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,25 +126,38 @@ func (a *AdminAPI) GetState() (adminschema.State, error) {
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientRegistrationRequest struct {
|
func (a *AdminAPI) CreateClient(req adminschema.ClientCreateRequest) (adminschema.ClientCreateResponse, error) {
|
||||||
IsAdmin bool `json:"isAdmin"`
|
if req.Client == nil {
|
||||||
Client oidc.ClientMetadata `json:"client"`
|
return adminschema.ClientCreateResponse{}, ErrorMissingClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminAPI) CreateClient(req ClientRegistrationRequest) (oidc.ClientRegistrationResponse, error) {
|
cli, err := adminschema.MapSchemaClientToClient(*req.Client)
|
||||||
if err := req.Client.Valid(); err != nil {
|
|
||||||
return oidc.ClientRegistrationResponse{}, mapError(err)
|
|
||||||
}
|
|
||||||
// metadata is guarenteed to have at least one redirect_uri by earlier validation.
|
|
||||||
id, err := oidc.GenClientID(req.Client.RedirectURIs[0].Host)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oidc.ClientRegistrationResponse{}, mapError(err)
|
return adminschema.ClientCreateResponse{}, mapError(err)
|
||||||
}
|
}
|
||||||
c, err := a.clientIdentityRepo.New(id, req.Client, req.IsAdmin)
|
|
||||||
|
if err := cli.Metadata.Valid(); err != nil {
|
||||||
|
return adminschema.ClientCreateResponse{}, ErrorInvalidClientFunc(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// metadata is guaranteed to have at least one redirect_uri by earlier validation.
|
||||||
|
id, err := ClientIDGenerator(cli.Metadata.RedirectURIs[0].Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oidc.ClientRegistrationResponse{}, mapError(err)
|
return adminschema.ClientCreateResponse{}, mapError(err)
|
||||||
}
|
}
|
||||||
return oidc.ClientRegistrationResponse{ClientID: c.ID, ClientSecret: c.Secret, ClientMetadata: req.Client}, nil
|
|
||||||
|
cli.Credentials.ID = id
|
||||||
|
|
||||||
|
creds, err := a.clientRepo.New(cli)
|
||||||
|
if err != nil {
|
||||||
|
return adminschema.ClientCreateResponse{}, mapError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Client.Id = creds.ID
|
||||||
|
req.Client.Secret = creds.Secret
|
||||||
|
return adminschema.ClientCreateResponse{
|
||||||
|
Client: req.Client,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapError(e error) error {
|
func mapError(e error) error {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package admin
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
"github.com/coreos/dex/schema/adminschema"
|
"github.com/coreos/dex/schema/adminschema"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
type testFixtures struct {
|
type testFixtures struct {
|
||||||
ur user.UserRepo
|
ur user.UserRepo
|
||||||
pwr user.PasswordInfoRepo
|
pwr user.PasswordInfoRepo
|
||||||
|
cr client.ClientRepo
|
||||||
mgr *manager.UserManager
|
mgr *manager.UserManager
|
||||||
adAPI *AdminAPI
|
adAPI *AdminAPI
|
||||||
}
|
}
|
||||||
|
@ -69,7 +71,7 @@ func makeTestFixtures() *testFixtures {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
f.mgr = manager.NewUserManager(f.ur, f.pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
f.mgr = manager.NewUserManager(f.ur, f.pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
||||||
f.adAPI = NewAdminAPI(dbMap, f.mgr, "local")
|
f.adAPI = NewAdminAPI(f.ur, f.pwr, f.cr, f.mgr, "local")
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
@ -15,7 +17,15 @@ var (
|
||||||
ErrorNotFound = errors.New("no data found")
|
ErrorNotFound = errors.New("no data found")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClientIdentityRepo interface {
|
type Client struct {
|
||||||
|
Credentials oidc.ClientCredentials
|
||||||
|
Metadata oidc.ClientMetadata
|
||||||
|
Admin bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientRepo interface {
|
||||||
|
Get(clientID string) (Client, error)
|
||||||
|
|
||||||
// Metadata returns one matching ClientMetadata if the given client
|
// Metadata returns one matching ClientMetadata if the given client
|
||||||
// exists, otherwise nil. The returned error will be non-nil only
|
// exists, otherwise nil. The returned error will be non-nil only
|
||||||
// if the repo was unable to determine client existence.
|
// if the repo was unable to determine client existence.
|
||||||
|
@ -27,13 +37,13 @@ type ClientIdentityRepo interface {
|
||||||
// to make these assertions will a non-nil error be returned.
|
// to make these assertions will a non-nil error be returned.
|
||||||
Authenticate(creds oidc.ClientCredentials) (bool, error)
|
Authenticate(creds oidc.ClientCredentials) (bool, error)
|
||||||
|
|
||||||
// All returns all registered Client Identities.
|
// All returns all registered Clients
|
||||||
All() ([]oidc.ClientIdentity, error)
|
All() ([]Client, error)
|
||||||
|
|
||||||
// New registers a ClientIdentity with the repo for the given metadata.
|
// New registers a Client with the repo.
|
||||||
// An unused ID must be provided. A corresponding secret will be returned
|
// An unused ID must be provided. A corresponding secret will be returned
|
||||||
// in a ClientCredentials struct along with the provided ID.
|
// in a ClientCredentials struct along with the provided ID.
|
||||||
New(id string, meta oidc.ClientMetadata, admin bool) (*oidc.ClientCredentials, error)
|
New(client Client) (*oidc.ClientCredentials, error)
|
||||||
|
|
||||||
SetDexAdmin(clientID string, isAdmin bool) error
|
SetDexAdmin(clientID string, isAdmin bool) error
|
||||||
|
|
||||||
|
@ -64,3 +74,42 @@ func ValidRedirectURL(rURL *url.URL, redirectURLs []url.URL) (url.URL, error) {
|
||||||
}
|
}
|
||||||
return url.URL{}, ErrorInvalidRedirectURL
|
return url.URL{}, ErrorInvalidRedirectURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ClientsFromReader(r io.Reader) ([]Client, error) {
|
||||||
|
var c []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
RedirectURLs []string `json:"redirectURLs"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r).Decode(&c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clients := make([]Client, len(c))
|
||||||
|
for i, client := range c {
|
||||||
|
if client.ID == "" {
|
||||||
|
return nil, errors.New("clients must have an ID")
|
||||||
|
}
|
||||||
|
if len(client.Secret) == 0 {
|
||||||
|
return nil, errors.New("clients must have a Secret")
|
||||||
|
}
|
||||||
|
redirectURIs := make([]url.URL, len(client.RedirectURLs))
|
||||||
|
for j, u := range client.RedirectURLs {
|
||||||
|
uri, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
redirectURIs[j] = *uri
|
||||||
|
}
|
||||||
|
|
||||||
|
clients[i] = Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: client.ID,
|
||||||
|
Secret: client.Secret,
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: redirectURIs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clients, nil
|
||||||
|
}
|
||||||
|
|
149
client/client_test.go
Normal file
149
client/client_test.go
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/oidc"
|
||||||
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
goodSecret1 = base64.URLEncoding.EncodeToString([]byte("my_secret"))
|
||||||
|
goodSecret2 = base64.URLEncoding.EncodeToString([]byte("my_other_secret"))
|
||||||
|
|
||||||
|
goodClient1 = `{
|
||||||
|
"id": "my_id",
|
||||||
|
"secret": "` + goodSecret1 + `",
|
||||||
|
"redirectURLs": ["https://client.example.com"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
goodClient2 = `{
|
||||||
|
"id": "my_other_id",
|
||||||
|
"secret": "` + goodSecret2 + `",
|
||||||
|
"redirectURLs": ["https://client2.example.com","https://client2_a.example.com"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
badURLClient = `{
|
||||||
|
"id": "my_id",
|
||||||
|
"secret": "` + goodSecret1 + `",
|
||||||
|
"redirectURLs": ["hdtp:/\(bad)(u)(r)(l)"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
badSecretClient = `{
|
||||||
|
"id": "my_id",
|
||||||
|
"secret": "` + "****" + `",
|
||||||
|
"redirectURLs": ["https://client.example.com"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
noSecretClient = `{
|
||||||
|
"id": "my_id",
|
||||||
|
"redirectURLs": ["https://client.example.com"]
|
||||||
|
}`
|
||||||
|
noIDClient = `{
|
||||||
|
"secret": "` + goodSecret1 + `",
|
||||||
|
"redirectURLs": ["https://client.example.com"]
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClientsFromReader(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
json string
|
||||||
|
want []Client
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
json: "[]",
|
||||||
|
want: []Client{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: "[" + goodClient1 + "]",
|
||||||
|
want: []Client{
|
||||||
|
{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "my_id",
|
||||||
|
Secret: "my_secret",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
mustParseURL(t, "https://client.example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: "[" + strings.Join([]string{goodClient1, goodClient2}, ",") + "]",
|
||||||
|
want: []Client{
|
||||||
|
{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "my_id",
|
||||||
|
Secret: "my_secret",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
mustParseURL(t, "https://client.example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "my_other_id",
|
||||||
|
Secret: "my_other_secret",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
mustParseURL(t, "https://client2.example.com"),
|
||||||
|
mustParseURL(t, "https://client2_a.example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
json: "[" + badURLClient + "]",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: "[" + badSecretClient + "]",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: "[" + noSecretClient + "]",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: "[" + noIDClient + "]",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
r := strings.NewReader(tt.json)
|
||||||
|
cs, err := ClientsFromReader(r)
|
||||||
|
if tt.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("case %d: want non-nil err", i)
|
||||||
|
t.Logf(pretty.Sprint(cs))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: got unexpected error parsing clients: %v", i, err)
|
||||||
|
t.Logf(tt.json)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := pretty.Compare(tt.want, cs); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got): %v", i, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseURL(t *testing.T, s string) url.URL {
|
||||||
|
u, err := url.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot parse %v as url: %v", s, err)
|
||||||
|
}
|
||||||
|
return *u
|
||||||
|
}
|
|
@ -116,10 +116,11 @@ func main() {
|
||||||
userRepo := db.NewUserRepo(dbc)
|
userRepo := db.NewUserRepo(dbc)
|
||||||
pwiRepo := db.NewPasswordInfoRepo(dbc)
|
pwiRepo := db.NewPasswordInfoRepo(dbc)
|
||||||
connCfgRepo := db.NewConnectorConfigRepo(dbc)
|
connCfgRepo := db.NewConnectorConfigRepo(dbc)
|
||||||
|
clientRepo := db.NewClientRepo(dbc)
|
||||||
userManager := manager.NewUserManager(userRepo,
|
userManager := manager.NewUserManager(userRepo,
|
||||||
pwiRepo, connCfgRepo, db.TransactionFactory(dbc), manager.ManagerOptions{})
|
pwiRepo, connCfgRepo, db.TransactionFactory(dbc), manager.ManagerOptions{})
|
||||||
|
|
||||||
adminAPI := admin.NewAdminAPI(dbc, userManager, *localConnectorID)
|
adminAPI := admin.NewAdminAPI(userRepo, pwiRepo, clientRepo, userManager, *localConnectorID)
|
||||||
kRepo, err := db.NewPrivateKeySetRepo(dbc, *useOldFormat, keySecrets.BytesSlice()...)
|
kRepo, err := db.NewPrivateKeySetRepo(dbc, *useOldFormat, keySecrets.BytesSlice()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
|
|
|
@ -14,7 +14,7 @@ func newDBDriver(dsn string) (driver, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
drv := &dbDriver{
|
drv := &dbDriver{
|
||||||
ciRepo: db.NewClientIdentityRepo(dbc),
|
ciRepo: db.NewClientRepo(dbc),
|
||||||
cfgRepo: db.NewConnectorConfigRepo(dbc),
|
cfgRepo: db.NewConnectorConfigRepo(dbc),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ func newDBDriver(dsn string) (driver, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type dbDriver struct {
|
type dbDriver struct {
|
||||||
ciRepo client.ClientIdentityRepo
|
ciRepo client.ClientRepo
|
||||||
cfgRepo *db.ConnectorConfigRepo
|
cfgRepo *db.ConnectorConfigRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,12 @@ func (d *dbDriver) NewClient(meta oidc.ClientMetadata) (*oidc.ClientCredentials,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.ciRepo.New(clientID, meta, false)
|
return d.ciRepo.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: clientID,
|
||||||
|
},
|
||||||
|
Metadata: meta,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbDriver) ConnectorConfigs() ([]connector.ConnectorConfig, error) {
|
func (d *dbDriver) ConnectorConfigs() ([]connector.ConnectorConfig, error) {
|
||||||
|
|
151
db/client.go
151
db/client.go
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
clientIdentityTableName = "client_identity"
|
clientTableName = "client_identity"
|
||||||
|
|
||||||
bcryptHashCost = 10
|
bcryptHashCost = 10
|
||||||
|
|
||||||
|
@ -34,46 +34,53 @@ const (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register(table{
|
register(table{
|
||||||
name: clientIdentityTableName,
|
name: clientTableName,
|
||||||
model: clientIdentityModel{},
|
model: clientModel{},
|
||||||
autoinc: false,
|
autoinc: false,
|
||||||
pkey: []string{"id"},
|
pkey: []string{"id"},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClientIdentityModel(id string, secret []byte, meta *oidc.ClientMetadata) (*clientIdentityModel, error) {
|
func newClientModel(cli client.Client) (*clientModel, error) {
|
||||||
hashed, err := bcrypt.GenerateFromPassword(secret, bcryptHashCost)
|
secretBytes, err := base64.URLEncoding.DecodeString(cli.Credentials.Secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hashed, err := bcrypt.GenerateFromPassword([]byte(
|
||||||
|
secretBytes),
|
||||||
|
bcryptHashCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bmeta, err := json.Marshal(meta)
|
bmeta, err := json.Marshal(&cli.Metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim := clientIdentityModel{
|
cim := clientModel{
|
||||||
ID: id,
|
ID: cli.Credentials.ID,
|
||||||
Secret: hashed,
|
Secret: hashed,
|
||||||
Metadata: string(bmeta),
|
Metadata: string(bmeta),
|
||||||
|
DexAdmin: cli.Admin,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cim, nil
|
return &cim, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientIdentityModel struct {
|
type clientModel struct {
|
||||||
ID string `db:"id"`
|
ID string `db:"id"`
|
||||||
Secret []byte `db:"secret"`
|
Secret []byte `db:"secret"`
|
||||||
Metadata string `db:"metadata"`
|
Metadata string `db:"metadata"`
|
||||||
DexAdmin bool `db:"dex_admin"`
|
DexAdmin bool `db:"dex_admin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *clientIdentityModel) ClientIdentity() (*oidc.ClientIdentity, error) {
|
func (m *clientModel) Client() (*client.Client, error) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: m.ID,
|
ID: m.ID,
|
||||||
Secret: string(m.Secret),
|
|
||||||
},
|
},
|
||||||
|
Admin: m.DexAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(m.Metadata), &ci.Metadata); err != nil {
|
if err := json.Unmarshal([]byte(m.Metadata), &ci.Metadata); err != nil {
|
||||||
|
@ -83,16 +90,26 @@ func (m *clientIdentityModel) ClientIdentity() (*oidc.ClientIdentity, error) {
|
||||||
return &ci, nil
|
return &ci, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientIdentityRepo(dbm *gorp.DbMap) client.ClientIdentityRepo {
|
func NewClientRepo(dbm *gorp.DbMap) client.ClientRepo {
|
||||||
return newClientIdentityRepo(dbm)
|
return newClientRepo(dbm)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClientIdentityRepo(dbm *gorp.DbMap) *clientIdentityRepo {
|
func NewClientRepoWithSecretGenerator(dbm *gorp.DbMap, secGen SecretGenerator) client.ClientRepo {
|
||||||
return &clientIdentityRepo{db: &db{dbm}}
|
rep := newClientRepo(dbm)
|
||||||
|
rep.secretGenerator = secGen
|
||||||
|
return rep
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []oidc.ClientIdentity) (client.ClientIdentityRepo, error) {
|
func newClientRepo(dbm *gorp.DbMap) *clientRepo {
|
||||||
repo := newClientIdentityRepo(dbm)
|
return &clientRepo{
|
||||||
|
db: &db{dbm},
|
||||||
|
secretGenerator: DefaultSecretGenerator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientRepoFromClients(dbm *gorp.DbMap, clients []client.Client) (client.ClientRepo, error) {
|
||||||
|
repo := newClientRepo(dbm)
|
||||||
tx, err := repo.begin()
|
tx, err := repo.begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -103,12 +120,7 @@ func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []oidc.ClientIden
|
||||||
if c.Credentials.Secret == "" {
|
if c.Credentials.Secret == "" {
|
||||||
return nil, fmt.Errorf("client %q has no secret", c.Credentials.ID)
|
return nil, fmt.Errorf("client %q has no secret", c.Credentials.ID)
|
||||||
}
|
}
|
||||||
dec, err := base64.URLEncoding.DecodeString(c.Credentials.Secret)
|
cm, err := newClientModel(c)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("client secrets must be base64 decodable. See issue #337. Please consider replacing %q with %q",
|
|
||||||
c.Credentials.Secret, base64.URLEncoding.EncodeToString([]byte(c.Credentials.Secret)))
|
|
||||||
}
|
|
||||||
cm, err := newClientIdentityModel(c.Credentials.ID, dec, &c.Metadata)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -123,49 +135,59 @@ func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []oidc.ClientIden
|
||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientIdentityRepo struct {
|
type clientRepo struct {
|
||||||
*db
|
*db
|
||||||
|
secretGenerator SecretGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) Metadata(clientID string) (*oidc.ClientMetadata, error) {
|
func (r *clientRepo) Get(clientID string) (client.Client, error) {
|
||||||
m, err := r.executor(nil).Get(clientIdentityModel{}, clientID)
|
m, err := r.executor(nil).Get(clientModel{}, clientID)
|
||||||
if err == sql.ErrNoRows || m == nil {
|
if err == sql.ErrNoRows || m == nil {
|
||||||
return nil, client.ErrorNotFound
|
return client.Client{}, client.ErrorNotFound
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return client.Client{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim, ok := m.(*clientIdentityModel)
|
cim, ok := m.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m))
|
log.Errorf("expected clientModel but found %v", reflect.TypeOf(m))
|
||||||
return nil, errors.New("unrecognized model")
|
return client.Client{}, errors.New("unrecognized model")
|
||||||
}
|
}
|
||||||
|
|
||||||
ci, err := cim.ClientIdentity()
|
ci, err := cim.Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return client.Client{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ci.Metadata, nil
|
return *ci, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) IsDexAdmin(clientID string) (bool, error) {
|
func (r *clientRepo) Metadata(clientID string) (*oidc.ClientMetadata, error) {
|
||||||
m, err := r.executor(nil).Get(clientIdentityModel{}, clientID)
|
c, err := r.Get(clientID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &c.Metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepo) IsDexAdmin(clientID string) (bool, error) {
|
||||||
|
m, err := r.executor(nil).Get(clientModel{}, clientID)
|
||||||
if m == nil || err != nil {
|
if m == nil || err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim, ok := m.(*clientIdentityModel)
|
cim, ok := m.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m))
|
log.Errorf("expected clientModel but found %v", reflect.TypeOf(m))
|
||||||
return false, errors.New("unrecognized model")
|
return false, errors.New("unrecognized model")
|
||||||
}
|
}
|
||||||
|
|
||||||
return cim.DexAdmin, nil
|
return cim.DexAdmin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) SetDexAdmin(clientID string, isAdmin bool) error {
|
func (r *clientRepo) SetDexAdmin(clientID string, isAdmin bool) error {
|
||||||
tx, err := r.begin()
|
tx, err := r.begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -173,14 +195,14 @@ func (r *clientIdentityRepo) SetDexAdmin(clientID string, isAdmin bool) error {
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
exec := r.executor(tx)
|
exec := r.executor(tx)
|
||||||
|
|
||||||
m, err := exec.Get(clientIdentityModel{}, clientID)
|
m, err := exec.Get(clientModel{}, clientID)
|
||||||
if m == nil || err != nil {
|
if m == nil || err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim, ok := m.(*clientIdentityModel)
|
cim, ok := m.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m))
|
log.Errorf("expected clientModel but found %v", reflect.TypeOf(m))
|
||||||
return errors.New("unrecognized model")
|
return errors.New("unrecognized model")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,15 +215,15 @@ func (r *clientIdentityRepo) SetDexAdmin(clientID string, isAdmin bool) error {
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) Authenticate(creds oidc.ClientCredentials) (bool, error) {
|
func (r *clientRepo) Authenticate(creds oidc.ClientCredentials) (bool, error) {
|
||||||
m, err := r.executor(nil).Get(clientIdentityModel{}, creds.ID)
|
m, err := r.executor(nil).Get(clientModel{}, creds.ID)
|
||||||
if m == nil || err != nil {
|
if m == nil || err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim, ok := m.(*clientIdentityModel)
|
cim, ok := m.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m))
|
log.Errorf("expected clientModel but found %v", reflect.TypeOf(m))
|
||||||
return false, errors.New("unrecognized model")
|
return false, errors.New("unrecognized model")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,17 +260,24 @@ func isAlreadyExistsErr(err error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) New(id string, meta oidc.ClientMetadata, admin bool) (*oidc.ClientCredentials, error) {
|
type SecretGenerator func() ([]byte, error)
|
||||||
secret, err := pcrypto.RandBytes(maxSecretLength)
|
|
||||||
|
func DefaultSecretGenerator() ([]byte, error) {
|
||||||
|
return pcrypto.RandBytes(maxSecretLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepo) New(cli client.Client) (*oidc.ClientCredentials, error) {
|
||||||
|
secret, err := r.secretGenerator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cim, err := newClientIdentityModel(id, secret, &meta)
|
cli.Credentials.Secret = base64.URLEncoding.EncodeToString(secret)
|
||||||
|
cim, err := newClientModel(cli)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cim.DexAdmin = admin
|
|
||||||
|
|
||||||
if err := r.executor(nil).Insert(cim); err != nil {
|
if err := r.executor(nil).Insert(cim); err != nil {
|
||||||
if isAlreadyExistsErr(err) {
|
if isAlreadyExistsErr(err) {
|
||||||
|
@ -258,29 +287,29 @@ func (r *clientIdentityRepo) New(id string, meta oidc.ClientMetadata, admin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
cc := oidc.ClientCredentials{
|
cc := oidc.ClientCredentials{
|
||||||
ID: id,
|
ID: cli.Credentials.ID,
|
||||||
Secret: base64.URLEncoding.EncodeToString(secret),
|
Secret: cli.Credentials.Secret,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cc, nil
|
return &cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *clientIdentityRepo) All() ([]oidc.ClientIdentity, error) {
|
func (r *clientRepo) All() ([]client.Client, error) {
|
||||||
qt := r.quote(clientIdentityTableName)
|
qt := r.quote(clientTableName)
|
||||||
q := fmt.Sprintf("SELECT * FROM %s", qt)
|
q := fmt.Sprintf("SELECT * FROM %s", qt)
|
||||||
objs, err := r.executor(nil).Select(&clientIdentityModel{}, q)
|
objs, err := r.executor(nil).Select(&clientModel{}, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := make([]oidc.ClientIdentity, len(objs))
|
cs := make([]client.Client, len(objs))
|
||||||
for i, obj := range objs {
|
for i, obj := range objs {
|
||||||
m, ok := obj.(*clientIdentityModel)
|
m, ok := obj.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("unable to cast client identity to clientIdentityModel")
|
return nil, errors.New("unable to cast client identity to clientModel")
|
||||||
}
|
}
|
||||||
|
|
||||||
ci, err := m.ClientIdentity()
|
ci, err := m.Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ func TestMigrateClientMetadata(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
model := &clientIdentityModel{
|
model := &clientModel{
|
||||||
ID: strconv.Itoa(i),
|
ID: strconv.Itoa(i),
|
||||||
Secret: []byte("verysecret"),
|
Secret: []byte("verysecret"),
|
||||||
Metadata: tt.before,
|
Metadata: tt.before,
|
||||||
|
@ -108,12 +108,12 @@ func TestMigrateClientMetadata(t *testing.T) {
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
id := strconv.Itoa(i)
|
id := strconv.Itoa(i)
|
||||||
m, err := dbMap.Get(clientIdentityModel{}, id)
|
m, err := dbMap.Get(clientModel{}, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: failed to get model: %v", i, err)
|
t.Errorf("case %d: failed to get model: %v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cim, ok := m.(*clientIdentityModel)
|
cim, ok := m.(*clientModel)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("case %d: unrecognized model type: %T", i, m)
|
t.Errorf("case %d: unrecognized model type: %T", i, m)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -11,10 +11,10 @@ import (
|
||||||
"github.com/go-gorp/gorp"
|
"github.com/go-gorp/gorp"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/pkg/log"
|
"github.com/coreos/dex/pkg/log"
|
||||||
"github.com/coreos/dex/refresh"
|
"github.com/coreos/dex/refresh"
|
||||||
"github.com/coreos/dex/repo"
|
"github.com/coreos/dex/repo"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -186,19 +186,19 @@ func (r *refreshTokenRepo) RevokeTokensForClient(userID, clientID string) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *refreshTokenRepo) ClientsWithRefreshTokens(userID string) ([]oidc.ClientIdentity, error) {
|
func (r *refreshTokenRepo) ClientsWithRefreshTokens(userID string) ([]client.Client, error) {
|
||||||
q := `SELECT c.* FROM %s as c
|
q := `SELECT c.* FROM %s as c
|
||||||
INNER JOIN %s as r ON c.id = r.client_id WHERE r.user_id = $1;`
|
INNER JOIN %s as r ON c.id = r.client_id WHERE r.user_id = $1;`
|
||||||
q = fmt.Sprintf(q, r.quote(clientIdentityTableName), r.quote(refreshTokenTableName))
|
q = fmt.Sprintf(q, r.quote(clientTableName), r.quote(refreshTokenTableName))
|
||||||
|
|
||||||
var clients []clientIdentityModel
|
var clients []clientModel
|
||||||
if _, err := r.executor(nil).Select(&clients, q, userID); err != nil {
|
if _, err := r.executor(nil).Select(&clients, q, userID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c := make([]oidc.ClientIdentity, len(clients))
|
c := make([]client.Client, len(clients))
|
||||||
for i, client := range clients {
|
for i, client := range clients {
|
||||||
ident, err := client.ClientIdentity()
|
ident, err := client.Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,8 +181,8 @@ func TestDBPrivateKeySetRepoSetGet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBClientIdentityRepoMetadata(t *testing.T) {
|
func TestDBClientRepoMetadata(t *testing.T) {
|
||||||
r := db.NewClientIdentityRepo(connect(t))
|
r := db.NewClientRepo(connect(t))
|
||||||
|
|
||||||
cm := oidc.ClientMetadata{
|
cm := oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -191,7 +191,12 @@ func TestDBClientIdentityRepoMetadata(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := r.New("foo", cm, false)
|
_, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Metadata: cm,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -206,8 +211,8 @@ func TestDBClientIdentityRepoMetadata(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBClientIdentityRepoMetadataNoExist(t *testing.T) {
|
func TestDBClientRepoMetadataNoExist(t *testing.T) {
|
||||||
r := db.NewClientIdentityRepo(connect(t))
|
r := db.NewClientRepo(connect(t))
|
||||||
|
|
||||||
got, err := r.Metadata("noexist")
|
got, err := r.Metadata("noexist")
|
||||||
if err != client.ErrorNotFound {
|
if err != client.ErrorNotFound {
|
||||||
|
@ -218,8 +223,8 @@ func TestDBClientIdentityRepoMetadataNoExist(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBClientIdentityRepoNewDuplicate(t *testing.T) {
|
func TestDBClientRepoNewDuplicate(t *testing.T) {
|
||||||
r := db.NewClientIdentityRepo(connect(t))
|
r := db.NewClientRepo(connect(t))
|
||||||
|
|
||||||
meta1 := oidc.ClientMetadata{
|
meta1 := oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -227,7 +232,12 @@ func TestDBClientIdentityRepoNewDuplicate(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := r.New("foo", meta1, false); err != nil {
|
if _, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Metadata: meta1,
|
||||||
|
}); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,13 +247,54 @@ func TestDBClientIdentityRepoNewDuplicate(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := r.New("foo", meta2, false); err == nil {
|
if _, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Metadata: meta2,
|
||||||
|
}); err == nil {
|
||||||
t.Fatalf("expected non-nil error")
|
t.Fatalf("expected non-nil error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBClientIdentityRepoAuthenticate(t *testing.T) {
|
func TestDBClientRepoNewAdmin(t *testing.T) {
|
||||||
r := db.NewClientIdentityRepo(connect(t))
|
|
||||||
|
for _, admin := range []bool{true, false} {
|
||||||
|
r := db.NewClientRepo(connect(t))
|
||||||
|
if _, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
url.URL{Scheme: "http", Host: "foo.example.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Admin: admin,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("expected non-nil error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotAdmin, err := r.IsDexAdmin("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected non-nil error")
|
||||||
|
}
|
||||||
|
if gotAdmin != admin {
|
||||||
|
t.Errorf("want=%v, gotAdmin=%v", admin, gotAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := r.Get("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected non-nil error")
|
||||||
|
}
|
||||||
|
if cli.Admin != admin {
|
||||||
|
t.Errorf("want=%v, cli.Admin=%v", admin, cli.Admin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func TestDBClientRepoAuthenticate(t *testing.T) {
|
||||||
|
r := db.NewClientRepo(connect(t))
|
||||||
|
|
||||||
cm := oidc.ClientMetadata{
|
cm := oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -251,7 +302,12 @@ func TestDBClientIdentityRepoAuthenticate(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := r.New("baz", cm, false)
|
cc, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "baz",
|
||||||
|
},
|
||||||
|
Metadata: cm,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -290,8 +346,8 @@ func TestDBClientIdentityRepoAuthenticate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBClientIdentityAll(t *testing.T) {
|
func TestDBClientAll(t *testing.T) {
|
||||||
r := db.NewClientIdentityRepo(connect(t))
|
r := db.NewClientRepo(connect(t))
|
||||||
|
|
||||||
cm := oidc.ClientMetadata{
|
cm := oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -299,7 +355,12 @@ func TestDBClientIdentityAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := r.New("foo", cm, false)
|
_, err := r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
Metadata: cm,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -322,7 +383,12 @@ func TestDBClientIdentityAll(t *testing.T) {
|
||||||
url.URL{Scheme: "http", Host: "foo.com", Path: "/cb"},
|
url.URL{Scheme: "http", Host: "foo.com", Path: "/cb"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = r.New("bar", cm, false)
|
_, err = r.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "bar",
|
||||||
|
},
|
||||||
|
Metadata: cm,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testClients = []oidc.ClientIdentity{
|
testClients = []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "client1",
|
ID: "client1",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secret-1")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secret-1")),
|
||||||
|
@ -30,7 +30,7 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "client2",
|
ID: "client2",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secret-2")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secret-2")),
|
||||||
|
@ -48,7 +48,7 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func newClientIdentityRepo(t *testing.T) client.ClientIdentityRepo {
|
func newClientRepo(t *testing.T) client.ClientRepo {
|
||||||
dsn := os.Getenv("DEX_TEST_DSN")
|
dsn := os.Getenv("DEX_TEST_DSN")
|
||||||
var dbMap *gorp.DbMap
|
var dbMap *gorp.DbMap
|
||||||
if dsn == "" {
|
if dsn == "" {
|
||||||
|
@ -56,7 +56,7 @@ func newClientIdentityRepo(t *testing.T) client.ClientIdentityRepo {
|
||||||
} else {
|
} else {
|
||||||
dbMap = connect(t)
|
dbMap = connect(t)
|
||||||
}
|
}
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(dbMap, testClients)
|
repo, err := db.NewClientRepoFromClients(dbMap, testClients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create client repo from clients: %v", err)
|
t.Fatalf("failed to create client repo from clients: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ func TestGetSetAdminClient(t *testing.T) {
|
||||||
|
|
||||||
Tests:
|
Tests:
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
repo := newClientIdentityRepo(t)
|
repo := newClientRepo(t)
|
||||||
for _, cid := range startAdmins {
|
for _, cid := range startAdmins {
|
||||||
err := repo.SetDexAdmin(cid, true)
|
err := repo.SetDexAdmin(cid, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,12 +11,13 @@ import (
|
||||||
"github.com/go-gorp/gorp"
|
"github.com/go-gorp/gorp"
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
"github.com/coreos/dex/refresh"
|
"github.com/coreos/dex/refresh"
|
||||||
"github.com/coreos/dex/user"
|
"github.com/coreos/dex/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients []oidc.ClientIdentity) refresh.RefreshTokenRepo {
|
func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients []client.Client) refresh.RefreshTokenRepo {
|
||||||
var dbMap *gorp.DbMap
|
var dbMap *gorp.DbMap
|
||||||
if dsn := os.Getenv("DEX_TEST_DSN"); dsn == "" {
|
if dsn := os.Getenv("DEX_TEST_DSN"); dsn == "" {
|
||||||
dbMap = db.NewMemDB()
|
dbMap = db.NewMemDB()
|
||||||
|
@ -26,7 +27,7 @@ func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients
|
||||||
if _, err := db.NewUserRepoFromUsers(dbMap, users); err != nil {
|
if _, err := db.NewUserRepoFromUsers(dbMap, users); err != nil {
|
||||||
t.Fatalf("Unable to add users: %v", err)
|
t.Fatalf("Unable to add users: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := db.NewClientIdentityRepoFromClients(dbMap, clients); err != nil {
|
if _, err := db.NewClientRepoFromClients(dbMap, clients); err != nil {
|
||||||
t.Fatalf("Unable to add clients: %v", err)
|
t.Fatalf("Unable to add clients: %v", err)
|
||||||
}
|
}
|
||||||
return db.NewRefreshTokenRepo(dbMap)
|
return db.NewRefreshTokenRepo(dbMap)
|
||||||
|
@ -35,7 +36,7 @@ func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients
|
||||||
func TestRefreshTokenRepo(t *testing.T) {
|
func TestRefreshTokenRepo(t *testing.T) {
|
||||||
clientID := "client1"
|
clientID := "client1"
|
||||||
userID := "user1"
|
userID := "user1"
|
||||||
clients := []oidc.ClientIdentity{
|
clients := []client.Client{
|
||||||
{
|
{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: clientID,
|
ID: clientID,
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/oidc"
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
|
|
||||||
"github.com/coreos/dex/admin"
|
"github.com/coreos/dex/admin"
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
|
"github.com/coreos/dex/db"
|
||||||
"github.com/coreos/dex/schema/adminschema"
|
"github.com/coreos/dex/schema/adminschema"
|
||||||
"github.com/coreos/dex/server"
|
"github.com/coreos/dex/server"
|
||||||
"github.com/coreos/dex/user"
|
"github.com/coreos/dex/user"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -24,6 +27,7 @@ const (
|
||||||
type adminAPITestFixtures struct {
|
type adminAPITestFixtures struct {
|
||||||
ur user.UserRepo
|
ur user.UserRepo
|
||||||
pwr user.PasswordInfoRepo
|
pwr user.PasswordInfoRepo
|
||||||
|
cr client.ClientRepo
|
||||||
adAPI *admin.AdminAPI
|
adAPI *admin.AdminAPI
|
||||||
adSrv *server.AdminServer
|
adSrv *server.AdminServer
|
||||||
hSrv *httptest.Server
|
hSrv *httptest.Server
|
||||||
|
@ -78,9 +82,17 @@ func makeAdminAPITestFixtures() *adminAPITestFixtures {
|
||||||
f := &adminAPITestFixtures{}
|
f := &adminAPITestFixtures{}
|
||||||
|
|
||||||
dbMap, ur, pwr, um := makeUserObjects(adminUsers, adminPasswords)
|
dbMap, ur, pwr, um := makeUserObjects(adminUsers, adminPasswords)
|
||||||
|
|
||||||
|
var cliCount int
|
||||||
|
secGen := func() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf("client_%v", cliCount)), nil
|
||||||
|
}
|
||||||
|
cr := db.NewClientRepoWithSecretGenerator(dbMap, secGen)
|
||||||
|
|
||||||
|
f.cr = cr
|
||||||
f.ur = ur
|
f.ur = ur
|
||||||
f.pwr = pwr
|
f.pwr = pwr
|
||||||
f.adAPI = admin.NewAdminAPI(dbMap, um, "local")
|
f.adAPI = admin.NewAdminAPI(ur, pwr, cr, um, "local")
|
||||||
f.adSrv = server.NewAdminServer(f.adAPI, nil, adminAPITestSecret)
|
f.adSrv = server.NewAdminServer(f.adAPI, nil, adminAPITestSecret)
|
||||||
f.hSrv = httptest.NewServer(f.adSrv.HTTPHandler())
|
f.hSrv = httptest.NewServer(f.adSrv.HTTPHandler())
|
||||||
f.hc = &http.Client{
|
f.hc = &http.Client{
|
||||||
|
@ -256,47 +268,147 @@ func TestCreateAdmin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateClient(t *testing.T) {
|
func TestCreateClient(t *testing.T) {
|
||||||
|
oldGen := admin.ClientIDGenerator
|
||||||
|
admin.ClientIDGenerator = func(hostport string) (string, error) {
|
||||||
|
return fmt.Sprintf("client_%v", hostport), nil
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
admin.ClientIDGenerator = oldGen
|
||||||
|
}()
|
||||||
|
|
||||||
|
mustParseURL := func(s string) *url.URL {
|
||||||
|
u, err := url.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("couldn't parse URL: %v", err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
addIDAndSecret := func(cli adminschema.Client) *adminschema.Client {
|
||||||
|
cli.Id = "client_auth.example.com"
|
||||||
|
cli.Secret = base64.URLEncoding.EncodeToString([]byte("client_0"))
|
||||||
|
return &cli
|
||||||
|
}
|
||||||
|
|
||||||
|
adminClientGood := adminschema.Client{
|
||||||
|
RedirectURIs: []string{"https://auth.example.com/"},
|
||||||
|
}
|
||||||
|
clientGood := client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "client_auth.example.com",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{*mustParseURL("https://auth.example.com/")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
adminAdminClient := adminClientGood
|
||||||
|
adminAdminClient.IsAdmin = true
|
||||||
|
clientGoodAdmin := clientGood
|
||||||
|
clientGoodAdmin.Admin = true
|
||||||
|
|
||||||
|
adminMultiRedirect := adminClientGood
|
||||||
|
adminMultiRedirect.RedirectURIs = []string{"https://auth.example.com/", "https://auth2.example.com/"}
|
||||||
|
clientMultiRedirect := clientGoodAdmin
|
||||||
|
clientMultiRedirect.Metadata.RedirectURIs = append(
|
||||||
|
clientMultiRedirect.Metadata.RedirectURIs,
|
||||||
|
*mustParseURL("https://auth2.example.com/"))
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
client oidc.ClientMetadata
|
req adminschema.ClientCreateRequest
|
||||||
wantError bool
|
want adminschema.ClientCreateResponse
|
||||||
|
wantClient client.Client
|
||||||
|
wantError int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
client: oidc.ClientMetadata{},
|
req: adminschema.ClientCreateRequest{},
|
||||||
wantError: true,
|
wantError: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
client: oidc.ClientMetadata{
|
req: adminschema.ClientCreateRequest{
|
||||||
RedirectURIs: []url.URL{
|
Client: &adminschema.Client{
|
||||||
{Scheme: "https", Host: "auth.example.com", Path: "/"},
|
IsAdmin: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
wantError: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: adminschema.ClientCreateRequest{
|
||||||
|
Client: &adminschema.Client{
|
||||||
|
RedirectURIs: []string{"909090"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantError: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: adminschema.ClientCreateRequest{
|
||||||
|
Client: &adminClientGood,
|
||||||
|
},
|
||||||
|
want: adminschema.ClientCreateResponse{
|
||||||
|
Client: addIDAndSecret(adminClientGood),
|
||||||
|
},
|
||||||
|
wantClient: clientGood,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: adminschema.ClientCreateRequest{
|
||||||
|
Client: &adminAdminClient,
|
||||||
|
},
|
||||||
|
want: adminschema.ClientCreateResponse{
|
||||||
|
Client: addIDAndSecret(adminAdminClient),
|
||||||
|
},
|
||||||
|
wantClient: clientGoodAdmin,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: adminschema.ClientCreateRequest{
|
||||||
|
Client: &adminMultiRedirect,
|
||||||
|
},
|
||||||
|
want: adminschema.ClientCreateResponse{
|
||||||
|
Client: addIDAndSecret(adminMultiRedirect),
|
||||||
|
},
|
||||||
|
wantClient: clientMultiRedirect,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
err := func() error {
|
if i != 3 {
|
||||||
f := makeAdminAPITestFixtures()
|
continue
|
||||||
req := &adminschema.ClientCreateRequestClient{}
|
}
|
||||||
for _, redirectURI := range tt.client.RedirectURIs {
|
f := makeAdminAPITestFixtures()
|
||||||
req.Redirect_uris = append(req.Redirect_uris, redirectURI.String())
|
|
||||||
|
resp, err := f.adClient.Client.Create(&tt.req).Do()
|
||||||
|
if tt.wantError != 0 {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("case %d: want non-nil error.", i)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
resp, err := f.adClient.Client.Create(&adminschema.ClientCreateRequest{Client: req}).Do()
|
|
||||||
if err != nil {
|
aErr, ok := err.(*googleapi.Error)
|
||||||
if tt.wantError {
|
if !ok {
|
||||||
return nil
|
t.Errorf("case %d: could not assert as adminSchema.Error: %v", i, err)
|
||||||
}
|
continue
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if resp.Client_id == "" {
|
if aErr.Code != tt.wantError {
|
||||||
return errors.New("no client id returned")
|
t.Errorf("case %d: want aErr.Code=%v, got %v", i, tt.wantError, aErr.Code)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if resp.Client_secret == "" {
|
continue
|
||||||
return errors.New("no client secret returned")
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: %v", i, err)
|
t.Errorf("case %d: unexpected error creating client: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := pretty.Compare(tt.want, resp); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got) = %v", i, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoClient, err := f.cr.Get(resp.Client.Id)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: Unexpected error getting client: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := pretty.Compare(tt.wantClient, repoClient); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(wantClient, repoClient) = %v", i, diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,13 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
schema "github.com/coreos/dex/schema/workerschema"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClientCreate(t *testing.T) {
|
func TestClientCreate(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "72de74a9",
|
ID: "72de74a9",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
||||||
|
@ -23,7 +24,7 @@ func TestClientCreate(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cis := []oidc.ClientIdentity{ci}
|
cis := []client.Client{ci}
|
||||||
|
|
||||||
srv, err := mockServer(cis)
|
srv, err := mockServer(cis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -72,7 +73,7 @@ func TestClientCreate(t *testing.T) {
|
||||||
t.Error("Expected non-empty Client Secret")
|
t.Error("Expected non-empty Client Secret")
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := srv.ClientIdentityRepo.Metadata(newClient.Id)
|
meta, err := srv.ClientRepo.Metadata(newClient.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error looking up client metadata: %v", err)
|
t.Errorf("Error looking up client metadata: %v", err)
|
||||||
} else if meta == nil {
|
} else if meta == nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
phttp "github.com/coreos/dex/pkg/http"
|
phttp "github.com/coreos/dex/pkg/http"
|
||||||
|
@ -22,7 +23,7 @@ import (
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mockServer(cis []oidc.ClientIdentity) (*server.Server, error) {
|
func mockServer(cis []client.Client) (*server.Server, error) {
|
||||||
dbMap := db.NewMemDB()
|
dbMap := db.NewMemDB()
|
||||||
k, err := key.GeneratePrivateKey()
|
k, err := key.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,23 +35,23 @@ func mockServer(cis []oidc.ClientIdentity) (*server.Server, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
clientIdentityRepo, err := db.NewClientIdentityRepoFromClients(dbMap, cis)
|
clientRepo, err := db.NewClientRepoFromClients(dbMap, cis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := manager.NewSessionManager(db.NewSessionRepo(dbMap), db.NewSessionKeyRepo(dbMap))
|
sm := manager.NewSessionManager(db.NewSessionRepo(dbMap), db.NewSessionKeyRepo(dbMap))
|
||||||
srv := &server.Server{
|
srv := &server.Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
ClientIdentityRepo: clientIdentityRepo,
|
ClientRepo: clientRepo,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
}
|
}
|
||||||
|
|
||||||
return srv, nil
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockClient(srv *server.Server, ci oidc.ClientIdentity) (*oidc.Client, error) {
|
func mockClient(srv *server.Server, ci client.Client) (*oidc.Client, error) {
|
||||||
hdlr := srv.HTTPHandler()
|
hdlr := srv.HTTPHandler()
|
||||||
sClient := &phttp.HandlerClient{Handler: hdlr}
|
sClient := &phttp.HandlerClient{Handler: hdlr}
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ func mockClient(srv *server.Server, ci oidc.ClientIdentity) (*oidc.Client, error
|
||||||
return oidc.NewClient(ccfg)
|
return oidc.NewClient(ccfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyUserClaims(claims jose.Claims, ci *oidc.ClientIdentity, user *user.User, issuerURL url.URL) error {
|
func verifyUserClaims(claims jose.Claims, ci *client.Client, user *user.User, issuerURL url.URL) error {
|
||||||
expectedSub, expectedName := ci.Credentials.ID, ci.Credentials.ID
|
expectedSub, expectedName := ci.Credentials.ID, ci.Credentials.ID
|
||||||
if user != nil {
|
if user != nil {
|
||||||
expectedSub, expectedName = user.ID, user.DisplayName
|
expectedSub, expectedName = user.ID, user.DisplayName
|
||||||
|
@ -116,7 +117,7 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
||||||
ID: "local",
|
ID: "local",
|
||||||
}
|
}
|
||||||
|
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "72de74a9",
|
ID: "72de74a9",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
||||||
|
@ -124,7 +125,7 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dbMap := db.NewMemDB()
|
dbMap := db.NewMemDB()
|
||||||
cir, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{ci})
|
cir, err := db.NewClientRepoFromClients(dbMap, []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: " + err.Error())
|
t.Fatalf("Failed to create client identity repo: " + err.Error())
|
||||||
}
|
}
|
||||||
|
@ -160,15 +161,15 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
||||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||||
|
|
||||||
srv := &server.Server{
|
srv := &server.Server{
|
||||||
IssuerURL: issuerURL,
|
IssuerURL: issuerURL,
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: cir,
|
ClientRepo: cir,
|
||||||
Templates: template.New(connector.LoginPageTemplateName),
|
Templates: template.New(connector.LoginPageTemplateName),
|
||||||
Connectors: []connector.Connector{},
|
Connectors: []connector.Connector{},
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
PasswordInfoRepo: passwordInfoRepo,
|
PasswordInfoRepo: passwordInfoRepo,
|
||||||
RefreshTokenRepo: refreshTokenRepo,
|
RefreshTokenRepo: refreshTokenRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = srv.AddConnector(cfg); err != nil {
|
if err = srv.AddConnector(cfg); err != nil {
|
||||||
|
@ -262,13 +263,13 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPClientCredsToken(t *testing.T) {
|
func TestHTTPClientCredsToken(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "72de74a9",
|
ID: "72de74a9",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cis := []oidc.ClientIdentity{ci}
|
cis := []client.Client{ci}
|
||||||
|
|
||||||
srv, err := mockServer(cis)
|
srv, err := mockServer(cis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -101,9 +101,9 @@ func makeUserAPITestFixtures() *userAPITestFixtures {
|
||||||
f := &userAPITestFixtures{}
|
f := &userAPITestFixtures{}
|
||||||
|
|
||||||
dbMap, _, _, um := makeUserObjects(userUsers, userPasswords)
|
dbMap, _, _, um := makeUserObjects(userUsers, userPasswords)
|
||||||
cir := func() client.ClientIdentityRepo {
|
cir := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{
|
repo, err := db.NewClientRepoFromClients(dbMap, []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: testClientID,
|
ID: testClientID,
|
||||||
Secret: testClientSecret,
|
Secret: testClientSecret,
|
||||||
|
@ -114,7 +114,7 @@ func makeUserAPITestFixtures() *userAPITestFixtures {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: userBadClientID,
|
ID: userBadClientID,
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/dex/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -54,5 +54,5 @@ type RefreshTokenRepo interface {
|
||||||
RevokeTokensForClient(userID, clientID string) error
|
RevokeTokensForClient(userID, clientID string) error
|
||||||
|
|
||||||
// ClientsWithRefreshTokens returns a list of all clients the user has an outstanding client with.
|
// ClientsWithRefreshTokens returns a list of all clients the user has an outstanding client with.
|
||||||
ClientsWithRefreshTokens(userID string) ([]oidc.ClientIdentity, error)
|
ClientsWithRefreshTokens(userID string) ([]client.Client, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,32 +20,41 @@ __Version:__ v1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Client
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
clientName: string // OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
||||||
|
clientURI: string // OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
||||||
|
id: string // The client ID. Ignored in client create requests.,
|
||||||
|
isAdmin: boolean,
|
||||||
|
logoURI: string // OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
||||||
|
redirectURIs: [
|
||||||
|
string
|
||||||
|
],
|
||||||
|
secret: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### ClientCreateRequest
|
### ClientCreateRequest
|
||||||
|
|
||||||
A request to register a client with dex.
|
A request to register a client with dex.
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
client: {
|
client: Client
|
||||||
client_name: string // OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
|
||||||
client_uri: string // OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
|
||||||
logo_uri: string // OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) .,
|
|
||||||
redirect_uris: [
|
|
||||||
string
|
|
||||||
]
|
|
||||||
},
|
|
||||||
isAdmin: boolean
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### ClientRegistrationResponse
|
### ClientCreateResponse
|
||||||
|
|
||||||
Upon successful registration, an ID and secret is assigned to the client.
|
Upon successful registration, an ID and secret is assigned to the client.
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
client_id: string,
|
client: Client
|
||||||
client_secret: string
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -137,7 +146,7 @@ Upon successful registration, an ID and secret is assigned to the client.
|
||||||
|
|
||||||
> |Code|Description|Type|
|
> |Code|Description|Type|
|
||||||
|:-----|:-----|:-----|
|
|:-----|:-----|:-----|
|
||||||
| 200 | | [ClientRegistrationResponse](#clientregistrationresponse) |
|
| 200 | | [ClientCreateResponse](#clientcreateresponse) |
|
||||||
| default | Unexpected error | |
|
| default | Unexpected error | |
|
||||||
|
|
||||||
|
|
||||||
|
|
83
schema/adminschema/mapper.go
Normal file
83
schema/adminschema/mapper.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package adminschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
|
"github.com/coreos/go-oidc/oidc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorNoRedirectURI = errors.New("No Redirect URIs")
|
||||||
|
ErrorInvalidRedirectURI = errors.New("Invalid Redirect URI")
|
||||||
|
ErrorInvalidLogoURI = errors.New("Invalid Logo URI")
|
||||||
|
ErrorInvalidClientURI = errors.New("Invalid Client URI")
|
||||||
|
)
|
||||||
|
|
||||||
|
func MapSchemaClientToClient(sc Client) (client.Client, error) {
|
||||||
|
c := client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: sc.Id,
|
||||||
|
Secret: sc.Secret,
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: make([]url.URL, len(sc.RedirectURIs)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, ru := range sc.RedirectURIs {
|
||||||
|
if ru == "" {
|
||||||
|
return client.Client{}, ErrorNoRedirectURI
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(ru)
|
||||||
|
if err != nil {
|
||||||
|
return client.Client{}, ErrorInvalidRedirectURI
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Metadata.RedirectURIs[i] = *u
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Metadata.ClientName = sc.ClientName
|
||||||
|
|
||||||
|
if sc.LogoURI != "" {
|
||||||
|
logoURI, err := url.Parse(sc.LogoURI)
|
||||||
|
if err != nil {
|
||||||
|
return client.Client{}, ErrorInvalidLogoURI
|
||||||
|
}
|
||||||
|
c.Metadata.LogoURI = logoURI
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc.ClientURI != "" {
|
||||||
|
clientURI, err := url.Parse(sc.ClientURI)
|
||||||
|
if err != nil {
|
||||||
|
return client.Client{}, ErrorInvalidClientURI
|
||||||
|
}
|
||||||
|
c.Metadata.ClientURI = clientURI
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Admin = sc.IsAdmin
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapClientToSchemaClient(c client.Client) Client {
|
||||||
|
cl := Client{
|
||||||
|
Id: c.Credentials.ID,
|
||||||
|
Secret: c.Credentials.Secret,
|
||||||
|
RedirectURIs: make([]string, len(c.Metadata.RedirectURIs)),
|
||||||
|
}
|
||||||
|
for i, u := range c.Metadata.RedirectURIs {
|
||||||
|
cl.RedirectURIs[i] = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
cl.ClientName = c.Metadata.ClientName
|
||||||
|
|
||||||
|
if c.Metadata.LogoURI != nil {
|
||||||
|
cl.LogoURI = c.Metadata.LogoURI.String()
|
||||||
|
}
|
||||||
|
if c.Metadata.ClientURI != nil {
|
||||||
|
cl.ClientURI = c.Metadata.ClientURI.String()
|
||||||
|
}
|
||||||
|
cl.IsAdmin = c.Admin
|
||||||
|
return cl
|
||||||
|
}
|
129
schema/adminschema/mapper_test.go
Normal file
129
schema/adminschema/mapper_test.go
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package adminschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/oidc"
|
||||||
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMapSchemaClientToClient(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
sc Client
|
||||||
|
want client.Client
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
sc: Client{
|
||||||
|
Id: "123",
|
||||||
|
Secret: "sec_123",
|
||||||
|
RedirectURIs: []string{
|
||||||
|
"https://client.example.com",
|
||||||
|
"https://client2.example.com",
|
||||||
|
},
|
||||||
|
ClientName: "Bill",
|
||||||
|
LogoURI: "https://logo.example.com",
|
||||||
|
ClientURI: "https://clientURI.example.com",
|
||||||
|
},
|
||||||
|
want: client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "123",
|
||||||
|
Secret: "sec_123",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
*mustParseURL(t, "https://client.example.com"),
|
||||||
|
*mustParseURL(t, "https://client2.example.com"),
|
||||||
|
},
|
||||||
|
ClientName: "Bill",
|
||||||
|
LogoURI: mustParseURL(t, "https://logo.example.com"),
|
||||||
|
ClientURI: mustParseURL(t, "https://clientURI.example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sc: Client{
|
||||||
|
Id: "123",
|
||||||
|
Secret: "sec_123",
|
||||||
|
RedirectURIs: []string{
|
||||||
|
"ht.d://p * * *",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
got, err := MapSchemaClientToClient(tt.sc)
|
||||||
|
if tt.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("case %d: want non-nil error", i)
|
||||||
|
t.Logf(pretty.Sprint(got))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: unexpected error mapping: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := pretty.Compare(tt.want, got); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got): %v", i, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapClientToClientSchema(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
c client.Client
|
||||||
|
want Client
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
want: Client{
|
||||||
|
Id: "123",
|
||||||
|
Secret: "sec_123",
|
||||||
|
RedirectURIs: []string{
|
||||||
|
"https://client.example.com",
|
||||||
|
"https://client2.example.com",
|
||||||
|
},
|
||||||
|
ClientName: "Bill",
|
||||||
|
LogoURI: "https://logo.example.com",
|
||||||
|
ClientURI: "https://clientURI.example.com",
|
||||||
|
},
|
||||||
|
c: client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: "123",
|
||||||
|
Secret: "sec_123",
|
||||||
|
},
|
||||||
|
Metadata: oidc.ClientMetadata{
|
||||||
|
RedirectURIs: []url.URL{
|
||||||
|
*mustParseURL(t, "https://client.example.com"),
|
||||||
|
*mustParseURL(t, "https://client2.example.com"),
|
||||||
|
},
|
||||||
|
ClientName: "Bill",
|
||||||
|
LogoURI: mustParseURL(t, "https://logo.example.com"),
|
||||||
|
ClientURI: mustParseURL(t, "https://clientURI.example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
got := MapClientToSchemaClient(tt.c)
|
||||||
|
|
||||||
|
if diff := pretty.Compare(tt.want, got); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got): %v", i, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseURL(t *testing.T, s string) *url.URL {
|
||||||
|
u, err := url.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot parse %v as url: %v", s, err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
|
@ -97,49 +97,52 @@ type Admin struct {
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientCreateRequest struct {
|
type Client struct {
|
||||||
Client *ClientCreateRequestClient `json:"client,omitempty"`
|
// ClientName: OPTIONAL. Name of the Client to be presented to the
|
||||||
|
|
||||||
IsAdmin bool `json:"isAdmin,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientCreateRequestClient struct {
|
|
||||||
// Client_name: OPTIONAL. Name of the Client to be presented to the
|
|
||||||
// End-User. If desired, representation of this Claim in different
|
// End-User. If desired, representation of this Claim in different
|
||||||
// languages and scripts is represented as described in Section 2.1 (
|
// languages and scripts is represented as described in Section 2.1 (
|
||||||
// Metadata Languages and Scripts ) .
|
// Metadata Languages and Scripts ) .
|
||||||
Client_name string `json:"client_name,omitempty"`
|
ClientName string `json:"clientName,omitempty"`
|
||||||
|
|
||||||
// Client_uri: OPTIONAL. URL of the home page of the Client. The value
|
// ClientURI: OPTIONAL. URL of the home page of the Client. The value of
|
||||||
// of this field MUST point to a valid Web page. If present, the server
|
// this field MUST point to a valid Web page. If present, the server
|
||||||
// SHOULD display this URL to the End-User in a followable fashion. If
|
// SHOULD display this URL to the End-User in a followable fashion. If
|
||||||
// desired, representation of this Claim in different languages and
|
// desired, representation of this Claim in different languages and
|
||||||
// scripts is represented as described in Section 2.1 ( Metadata
|
// scripts is represented as described in Section 2.1 ( Metadata
|
||||||
// Languages and Scripts ) .
|
// Languages and Scripts ) .
|
||||||
Client_uri string `json:"client_uri,omitempty"`
|
ClientURI string `json:"clientURI,omitempty"`
|
||||||
|
|
||||||
// Logo_uri: OPTIONAL. URL that references a logo for the Client
|
// Id: The client ID. Ignored in client create requests.
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
IsAdmin bool `json:"isAdmin,omitempty"`
|
||||||
|
|
||||||
|
// LogoURI: OPTIONAL. URL that references a logo for the Client
|
||||||
// application. If present, the server SHOULD display this image to the
|
// application. If present, the server SHOULD display this image to the
|
||||||
// End-User during approval. The value of this field MUST point to a
|
// End-User during approval. The value of this field MUST point to a
|
||||||
// valid image file. If desired, representation of this Claim in
|
// valid image file. If desired, representation of this Claim in
|
||||||
// different languages and scripts is represented as described in
|
// different languages and scripts is represented as described in
|
||||||
// Section 2.1 ( Metadata Languages and Scripts ) .
|
// Section 2.1 ( Metadata Languages and Scripts ) .
|
||||||
Logo_uri string `json:"logo_uri,omitempty"`
|
LogoURI string `json:"logoURI,omitempty"`
|
||||||
|
|
||||||
// Redirect_uris: REQUIRED. Array of Redirection URI values used by the
|
// RedirectURIs: REQUIRED. Array of Redirection URI values used by the
|
||||||
// Client. One of these registered Redirection URI values MUST exactly
|
// Client. One of these registered Redirection URI values MUST exactly
|
||||||
// match the redirect_uri parameter value used in each Authorization
|
// match the redirect_uri parameter value used in each Authorization
|
||||||
// Request, with the matching performed as described in Section 6.2.1 of
|
// Request, with the matching performed as described in Section 6.2.1 of
|
||||||
// [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter,
|
// [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter,
|
||||||
// “Uniform Resource Identifier (URI): Generic Syntax,” January
|
// “Uniform Resource Identifier (URI): Generic Syntax,” January
|
||||||
// 2005. ) (Simple String Comparison).
|
// 2005. ) (Simple String Comparison).
|
||||||
Redirect_uris []string `json:"redirect_uris,omitempty"`
|
RedirectURIs []string `json:"redirectURIs,omitempty"`
|
||||||
|
|
||||||
|
Secret string `json:"secret,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientRegistrationResponse struct {
|
type ClientCreateRequest struct {
|
||||||
Client_id string `json:"client_id,omitempty"`
|
Client *Client `json:"client,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
Client_secret string `json:"client_secret,omitempty"`
|
type ClientCreateResponse struct {
|
||||||
|
Client *Client `json:"client,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
|
@ -310,7 +313,7 @@ func (c *ClientCreateCall) Fields(s ...googleapi.Field) *ClientCreateCall {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClientCreateCall) Do() (*ClientRegistrationResponse, error) {
|
func (c *ClientCreateCall) Do() (*ClientCreateResponse, error) {
|
||||||
var body io.Reader = nil
|
var body io.Reader = nil
|
||||||
body, err := googleapi.WithoutDataWrapper.JSONReader(c.clientcreaterequest)
|
body, err := googleapi.WithoutDataWrapper.JSONReader(c.clientcreaterequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -336,7 +339,7 @@ func (c *ClientCreateCall) Do() (*ClientRegistrationResponse, error) {
|
||||||
if err := googleapi.CheckResponse(res); err != nil {
|
if err := googleapi.CheckResponse(res); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ret *ClientRegistrationResponse
|
var ret *ClientCreateResponse
|
||||||
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
|
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -350,7 +353,7 @@ func (c *ClientCreateCall) Do() (*ClientRegistrationResponse, error) {
|
||||||
// "$ref": "ClientCreateRequest"
|
// "$ref": "ClientCreateRequest"
|
||||||
// },
|
// },
|
||||||
// "response": {
|
// "response": {
|
||||||
// "$ref": "ClientRegistrationResponse"
|
// "$ref": "ClientCreateResponse"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package adminschema
|
package adminschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
@ -51,53 +52,66 @@ const DiscoveryJSON = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ClientCreateRequest": {
|
"Client": {
|
||||||
"id": "ClientCreateRequest",
|
"id": "Client",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A request to register a client with dex.",
|
"properties": {
|
||||||
"properties": {
|
"id": {
|
||||||
"isAdmin": {
|
"type": "string",
|
||||||
"type": "boolean"
|
"description": "The client ID. Ignored in client create requests."
|
||||||
},
|
},
|
||||||
"client": {
|
"secret": {
|
||||||
"type": "object",
|
"type": "string",
|
||||||
"properties": {
|
"description": "The client secret. Ignored in client create requests."
|
||||||
"redirect_uris": {
|
},
|
||||||
"type": "array",
|
"secret": {
|
||||||
"items": {
|
"type": "string",
|
||||||
"type": "string"
|
"format": "byte"
|
||||||
},
|
},
|
||||||
"description": "REQUIRED. Array of Redirection URI values used by the Client. One of these registered Redirection URI values MUST exactly match the redirect_uri parameter value used in each Authorization Request, with the matching performed as described in Section 6.2.1 of [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005. ) (Simple String Comparison)."
|
"isAdmin": {
|
||||||
},
|
"type": "boolean"
|
||||||
"client_name": {
|
},
|
||||||
"type": "string",
|
"redirectURIs": {
|
||||||
"description": "OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"logo_uri": {
|
"type": "string"
|
||||||
"type": "string",
|
},
|
||||||
"description": "OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"description": "REQUIRED. Array of Redirection URI values used by the Client. One of these registered Redirection URI values MUST exactly match the redirect_uri parameter value used in each Authorization Request, with the matching performed as described in Section 6.2.1 of [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005. ) (Simple String Comparison)."
|
||||||
},
|
},
|
||||||
"client_uri": {
|
"clientName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"description": "OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
}
|
},
|
||||||
}
|
"logoURI": {
|
||||||
}
|
"type": "string",
|
||||||
|
"description": "OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
|
},
|
||||||
|
"clientURI": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ClientRegistrationResponse": {
|
"ClientCreateRequest": {
|
||||||
"id": "ClientRegistrationResponse",
|
"id": "ClientCreateRequest",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Upon successful registration, an ID and secret is assigned to the client.",
|
"description": "A request to register a client with dex.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"client_id": {
|
"client": {
|
||||||
"type": "string"
|
"$ref": "Client"
|
||||||
},
|
}
|
||||||
"client_secret": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ClientCreateResponse": {
|
||||||
|
"id": "ClientCreateResponse",
|
||||||
|
"type": "object",
|
||||||
|
"description": "Upon successful registration, an ID and secret is assigned to the client.",
|
||||||
|
"properties": {
|
||||||
|
"client":{
|
||||||
|
"$ref": "Client"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"Admin": {
|
"Admin": {
|
||||||
|
@ -160,7 +174,7 @@ const DiscoveryJSON = `{
|
||||||
"$ref": "ClientCreateRequest"
|
"$ref": "ClientCreateRequest"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"$ref": "ClientRegistrationResponse"
|
"$ref": "ClientCreateResponse"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,53 +45,62 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ClientCreateRequest": {
|
"Client": {
|
||||||
"id": "ClientCreateRequest",
|
"id": "Client",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A request to register a client with dex.",
|
"properties": {
|
||||||
"properties": {
|
"id": {
|
||||||
"isAdmin": {
|
"type": "string",
|
||||||
"type": "boolean"
|
"description": "The client ID. Ignored in client create requests."
|
||||||
},
|
},
|
||||||
"client": {
|
"secret": {
|
||||||
"type": "object",
|
"type": "string",
|
||||||
"properties": {
|
"description": "The client secret. Ignored in client create requests."
|
||||||
"redirect_uris": {
|
},
|
||||||
"type": "array",
|
"isAdmin": {
|
||||||
"items": {
|
"type": "boolean"
|
||||||
"type": "string"
|
},
|
||||||
},
|
"redirectURIs": {
|
||||||
"description": "REQUIRED. Array of Redirection URI values used by the Client. One of these registered Redirection URI values MUST exactly match the redirect_uri parameter value used in each Authorization Request, with the matching performed as described in Section 6.2.1 of [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005. ) (Simple String Comparison)."
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"client_name": {
|
"type": "string"
|
||||||
"type": "string",
|
},
|
||||||
"description": "OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"description": "REQUIRED. Array of Redirection URI values used by the Client. One of these registered Redirection URI values MUST exactly match the redirect_uri parameter value used in each Authorization Request, with the matching performed as described in Section 6.2.1 of [RFC3986] ( Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005. ) (Simple String Comparison)."
|
||||||
},
|
},
|
||||||
"logo_uri": {
|
"clientName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"description": "OPTIONAL. Name of the Client to be presented to the End-User. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
},
|
},
|
||||||
"client_uri": {
|
"logoURI": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
"description": "OPTIONAL. URL that references a logo for the Client application. If present, the server SHOULD display this image to the End-User during approval. The value of this field MUST point to a valid image file. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
}
|
},
|
||||||
}
|
"clientURI": {
|
||||||
}
|
"type": "string",
|
||||||
|
"description": "OPTIONAL. URL of the home page of the Client. The value of this field MUST point to a valid Web page. If present, the server SHOULD display this URL to the End-User in a followable fashion. If desired, representation of this Claim in different languages and scripts is represented as described in Section 2.1 ( Metadata Languages and Scripts ) ."
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ClientRegistrationResponse": {
|
"ClientCreateRequest": {
|
||||||
"id": "ClientRegistrationResponse",
|
"id": "ClientCreateRequest",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Upon successful registration, an ID and secret is assigned to the client.",
|
"description": "A request to register a client with dex.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"client_id": {
|
"client": {
|
||||||
"type": "string"
|
"$ref": "Client"
|
||||||
},
|
}
|
||||||
"client_secret": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ClientCreateResponse": {
|
||||||
|
"id": "ClientCreateResponse",
|
||||||
|
"type": "object",
|
||||||
|
"description": "Upon successful registration, an ID and secret is assigned to the client.",
|
||||||
|
"properties": {
|
||||||
|
"client":{
|
||||||
|
"$ref": "Client"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"Admin": {
|
"Admin": {
|
||||||
|
@ -154,7 +163,7 @@
|
||||||
"$ref": "ClientCreateRequest"
|
"$ref": "ClientCreateRequest"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"$ref": "ClientRegistrationResponse"
|
"$ref": "ClientCreateResponse"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MapSchemaClientToClientIdentity(sc Client) (oidc.ClientIdentity, error) {
|
func MapSchemaClientToClient(sc Client) (client.Client, error) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: sc.Id,
|
ID: sc.Id,
|
||||||
},
|
},
|
||||||
|
@ -19,12 +20,12 @@ func MapSchemaClientToClientIdentity(sc Client) (oidc.ClientIdentity, error) {
|
||||||
|
|
||||||
for i, ru := range sc.RedirectURIs {
|
for i, ru := range sc.RedirectURIs {
|
||||||
if ru == "" {
|
if ru == "" {
|
||||||
return oidc.ClientIdentity{}, errors.New("redirect URL empty")
|
return client.Client{}, errors.New("redirect URL empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(ru)
|
u, err := url.Parse(ru)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oidc.ClientIdentity{}, errors.New("redirect URL invalid")
|
return client.Client{}, errors.New("redirect URL invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
ci.Metadata.RedirectURIs[i] = *u
|
ci.Metadata.RedirectURIs[i] = *u
|
||||||
|
@ -33,7 +34,7 @@ func MapSchemaClientToClientIdentity(sc Client) (oidc.ClientIdentity, error) {
|
||||||
return ci, nil
|
return ci, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapClientIdentityToSchemaClient(c oidc.ClientIdentity) Client {
|
func MapClientToSchemaClient(c client.Client) Client {
|
||||||
cl := Client{
|
cl := Client{
|
||||||
Id: c.Credentials.ID,
|
Id: c.Credentials.ID,
|
||||||
RedirectURIs: make([]string, len(c.Metadata.RedirectURIs)),
|
RedirectURIs: make([]string, len(c.Metadata.RedirectURIs)),
|
||||||
|
@ -44,7 +45,7 @@ func MapClientIdentityToSchemaClient(c oidc.ClientIdentity) Client {
|
||||||
return cl
|
return cl
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapClientIdentityToSchemaClientWithSecret(c oidc.ClientIdentity) ClientWithSecret {
|
func MapClientToSchemaClientWithSecret(c client.Client) ClientWithSecret {
|
||||||
cl := ClientWithSecret{
|
cl := ClientWithSecret{
|
||||||
Id: c.Credentials.ID,
|
Id: c.Credentials.ID,
|
||||||
Secret: c.Credentials.Secret,
|
Secret: c.Credentials.Secret,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package workerschema
|
package workerschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
|
|
@ -116,7 +116,7 @@ func (s *AdminServer) getState(w http.ResponseWriter, r *http.Request, ps httpro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AdminServer) createClient(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
func (s *AdminServer) createClient(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
var req admin.ClientRegistrationRequest
|
var req = adminschema.ClientCreateRequest{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
writeInvalidRequest(w, "cannot parse JSON body")
|
writeInvalidRequest(w, "cannot parse JSON body")
|
||||||
return
|
return
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
type clientTokenMiddleware struct {
|
type clientTokenMiddleware struct {
|
||||||
issuerURL string
|
issuerURL string
|
||||||
ciRepo client.ClientIdentityRepo
|
ciRepo client.ClientRepo
|
||||||
keysFunc func() ([]key.PublicKey, error)
|
keysFunc func() ([]key.PublicKey, error)
|
||||||
next http.Handler
|
next http.Handler
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func (c *clientTokenMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ciRepo == nil {
|
if c.ciRepo == nil {
|
||||||
log.Errorf("Misconfigured clientTokenMiddleware, ClientIdentityRepo is not set")
|
log.Errorf("Misconfigured clientTokenMiddleware, ClientRepo is not set")
|
||||||
respondError()
|
respondError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func TestClientToken(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
tomorrow := now.Add(24 * time.Hour)
|
tomorrow := now.Add(24 * time.Hour)
|
||||||
validClientID := "valid-client"
|
validClientID := "valid-client"
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: validClientID,
|
ID: validClientID,
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),
|
||||||
|
@ -37,7 +37,7 @@ func TestClientToken(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: %v", err)
|
t.Fatalf("Failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func TestClientToken(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
keys []key.PublicKey
|
keys []key.PublicKey
|
||||||
repo client.ClientIdentityRepo
|
repo client.ClientRepo
|
||||||
header string
|
header string
|
||||||
wantCode int
|
wantCode int
|
||||||
}{
|
}{
|
||||||
|
@ -114,7 +114,7 @@ func TestClientToken(t *testing.T) {
|
||||||
// empty repo
|
// empty repo
|
||||||
{
|
{
|
||||||
keys: []key.PublicKey{pubKey},
|
keys: []key.PublicKey{pubKey},
|
||||||
repo: db.NewClientIdentityRepo(db.NewMemDB()),
|
repo: db.NewClientRepo(db.NewMemDB()),
|
||||||
header: fmt.Sprintf("BEARER %s", validJWT),
|
header: fmt.Sprintf("BEARER %s", validJWT),
|
||||||
wantCode: http.StatusUnauthorized,
|
wantCode: http.StatusUnauthorized,
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/pkg/log"
|
"github.com/coreos/dex/pkg/log"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/oauth2"
|
"github.com/coreos/go-oidc/oauth2"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
)
|
)
|
||||||
|
@ -43,7 +45,12 @@ func (s *Server) handleClientRegistrationRequest(r *http.Request) (*oidc.ClientR
|
||||||
return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata")
|
return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := s.ClientIdentityRepo.New(id, clientMetadata, false)
|
creds, err := s.ClientRepo.New(client.Client{
|
||||||
|
Credentials: oidc.ClientCredentials{
|
||||||
|
ID: id,
|
||||||
|
},
|
||||||
|
Metadata: clientMetadata,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to create new client identity: %v", err)
|
log.Errorf("Failed to create new client identity: %v", err)
|
||||||
return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata")
|
return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata")
|
||||||
|
|
|
@ -143,7 +143,7 @@ func TestClientRegistration(t *testing.T) {
|
||||||
return fmt.Errorf("no client id in registration response")
|
return fmt.Errorf("no client id in registration response")
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := fixtures.clientIdentityRepo.Metadata(r.ClientID)
|
metadata, err := fixtures.clientRepo.Metadata(r.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to lookup client id after creation")
|
return fmt.Errorf("failed to lookup client id after creation")
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type clientResource struct {
|
type clientResource struct {
|
||||||
repo client.ClientIdentityRepo
|
repo client.ClientRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerClientResource(prefix string, repo client.ClientIdentityRepo) (string, http.Handler) {
|
func registerClientResource(prefix string, repo client.ClientRepo) (string, http.Handler) {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
c := &clientResource{
|
c := &clientResource{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
|
@ -49,7 +49,7 @@ func (c *clientResource) list(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
scs := make([]*schema.Client, len(cs))
|
scs := make([]*schema.Client, len(cs))
|
||||||
for i, ci := range cs {
|
for i, ci := range cs {
|
||||||
sc := schema.MapClientIdentityToSchemaClient(ci)
|
sc := schema.MapClientToSchemaClient(ci)
|
||||||
scs[i] = &sc
|
scs[i] = &sc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ci, err := schema.MapSchemaClientToClientIdentity(sc)
|
ci, err := schema.MapSchemaClientToClient(sc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Invalid request data: %v", err)
|
log.Debugf("Invalid request data: %v", err)
|
||||||
writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, "missing or invalid field: redirectURIs"))
|
writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, "missing or invalid field: redirectURIs"))
|
||||||
|
@ -96,7 +96,9 @@ func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := c.repo.New(clientID, ci.Metadata, false)
|
ci.Credentials.ID = clientID
|
||||||
|
creds, err := c.repo.New(ci)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed creating client: %v", err)
|
log.Errorf("Failed creating client: %v", err)
|
||||||
writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to create client"))
|
writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to create client"))
|
||||||
|
@ -104,7 +106,7 @@ func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
ci.Credentials = *creds
|
ci.Credentials = *creds
|
||||||
|
|
||||||
ssc := schema.MapClientIdentityToSchemaClientWithSecret(ci)
|
ssc := schema.MapClientToSchemaClientWithSecret(ci)
|
||||||
w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
|
w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
|
||||||
writeResponseWithBody(w, http.StatusCreated, ssc)
|
writeResponseWithBody(w, http.StatusCreated, ssc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
schema "github.com/coreos/dex/schema/workerschema"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
"github.com/coreos/go-oidc/oidc"
|
||||||
|
@ -27,7 +28,7 @@ func makeBody(s string) io.ReadCloser {
|
||||||
func TestCreateInvalidRequest(t *testing.T) {
|
func TestCreateInvalidRequest(t *testing.T) {
|
||||||
u := &url.URL{Scheme: "http", Host: "example.com", Path: "clients"}
|
u := &url.URL{Scheme: "http", Host: "example.com", Path: "clients"}
|
||||||
h := http.Header{"Content-Type": []string{"application/json"}}
|
h := http.Header{"Content-Type": []string{"application/json"}}
|
||||||
repo := db.NewClientIdentityRepo(db.NewMemDB())
|
repo := db.NewClientRepo(db.NewMemDB())
|
||||||
res := &clientResource{repo: repo}
|
res := &clientResource{repo: repo}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
req *http.Request
|
req *http.Request
|
||||||
|
@ -118,7 +119,7 @@ func TestCreateInvalidRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
repo := db.NewClientIdentityRepo(db.NewMemDB())
|
repo := db.NewClientRepo(db.NewMemDB())
|
||||||
res := &clientResource{repo: repo}
|
res := &clientResource{repo: repo}
|
||||||
tests := [][]string{
|
tests := [][]string{
|
||||||
[]string{"http://example.com"},
|
[]string{"http://example.com"},
|
||||||
|
@ -177,7 +178,7 @@ func TestList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
cs []oidc.ClientIdentity
|
cs []client.Client
|
||||||
want []*schema.Client
|
want []*schema.Client
|
||||||
}{
|
}{
|
||||||
// empty repo
|
// empty repo
|
||||||
|
@ -187,8 +188,8 @@ func TestList(t *testing.T) {
|
||||||
},
|
},
|
||||||
// single client
|
// single client
|
||||||
{
|
{
|
||||||
cs: []oidc.ClientIdentity{
|
cs: []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
|
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
|
||||||
Metadata: oidc.ClientMetadata{
|
Metadata: oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -206,8 +207,8 @@ func TestList(t *testing.T) {
|
||||||
},
|
},
|
||||||
// multi client
|
// multi client
|
||||||
{
|
{
|
||||||
cs: []oidc.ClientIdentity{
|
cs: []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
|
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
|
||||||
Metadata: oidc.ClientMetadata{
|
Metadata: oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -215,7 +216,7 @@ func TestList(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{ID: "biz", Secret: b64Encode("bang")},
|
Credentials: oidc.ClientCredentials{ID: "biz", Secret: b64Encode("bang")},
|
||||||
Metadata: oidc.ClientMetadata{
|
Metadata: oidc.ClientMetadata{
|
||||||
RedirectURIs: []url.URL{
|
RedirectURIs: []url.URL{
|
||||||
|
@ -238,7 +239,7 @@ func TestList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), tt.cs)
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), tt.cs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -13,10 +13,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/key"
|
"github.com/coreos/go-oidc/key"
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
"github.com/coreos/pkg/health"
|
"github.com/coreos/pkg/health"
|
||||||
"github.com/go-gorp/gorp"
|
"github.com/go-gorp/gorp"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
"github.com/coreos/dex/email"
|
"github.com/coreos/dex/email"
|
||||||
|
@ -114,7 +114,7 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to read clients from file %s: %v", cfg.ClientsFile, err)
|
return fmt.Errorf("unable to read clients from file %s: %v", cfg.ClientsFile, err)
|
||||||
}
|
}
|
||||||
ciRepo, err := db.NewClientIdentityRepoFromClients(dbMap, clients)
|
ciRepo, err := db.NewClientRepoFromClients(dbMap, clients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create client identity repo: %v", err)
|
return fmt.Errorf("failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error {
|
||||||
|
|
||||||
txnFactory := db.TransactionFactory(dbMap)
|
txnFactory := db.TransactionFactory(dbMap)
|
||||||
userManager := usermanager.NewUserManager(userRepo, pwiRepo, cfgRepo, txnFactory, usermanager.ManagerOptions{})
|
userManager := usermanager.NewUserManager(userRepo, pwiRepo, cfgRepo, txnFactory, usermanager.ManagerOptions{})
|
||||||
srv.ClientIdentityRepo = ciRepo
|
srv.ClientRepo = ciRepo
|
||||||
srv.KeySetRepo = kRepo
|
srv.KeySetRepo = kRepo
|
||||||
srv.ConnectorConfigRepo = cfgRepo
|
srv.ConnectorConfigRepo = cfgRepo
|
||||||
srv.UserRepo = userRepo
|
srv.UserRepo = userRepo
|
||||||
|
@ -214,47 +214,14 @@ func loadUsersFromReader(r io.Reader) (users []user.UserWithRemoteIdentities, pw
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadClients parses the clients.json file and returns the clients to be created.
|
// loadClients parses the clients.json file and returns a list of clients.
|
||||||
func loadClients(filepath string) ([]oidc.ClientIdentity, error) {
|
func loadClients(filepath string) ([]client.Client, error) {
|
||||||
f, err := os.Open(filepath)
|
f, err := os.Open(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
return loadClientsFromReader(f)
|
return client.ClientsFromReader(f)
|
||||||
}
|
|
||||||
|
|
||||||
func loadClientsFromReader(r io.Reader) ([]oidc.ClientIdentity, error) {
|
|
||||||
var c []struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Secret string `json:"secret"`
|
|
||||||
RedirectURLs []string `json:"redirectURLs"`
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(r).Decode(&c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
clients := make([]oidc.ClientIdentity, len(c))
|
|
||||||
for i, client := range c {
|
|
||||||
redirectURIs := make([]url.URL, len(client.RedirectURLs))
|
|
||||||
for j, u := range client.RedirectURLs {
|
|
||||||
uri, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
redirectURIs[j] = *uri
|
|
||||||
}
|
|
||||||
|
|
||||||
clients[i] = oidc.ClientIdentity{
|
|
||||||
Credentials: oidc.ClientCredentials{
|
|
||||||
ID: client.ID,
|
|
||||||
Secret: client.Secret,
|
|
||||||
},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: redirectURIs,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clients, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *MultiServerConfig) Configure(srv *Server) error {
|
func (cfg *MultiServerConfig) Configure(srv *Server) error {
|
||||||
|
@ -279,7 +246,7 @@ func (cfg *MultiServerConfig) Configure(srv *Server) error {
|
||||||
return fmt.Errorf("unable to create PrivateKeySetRepo: %v", err)
|
return fmt.Errorf("unable to create PrivateKeySetRepo: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ciRepo := db.NewClientIdentityRepo(dbc)
|
ciRepo := db.NewClientRepo(dbc)
|
||||||
sRepo := db.NewSessionRepo(dbc)
|
sRepo := db.NewSessionRepo(dbc)
|
||||||
skRepo := db.NewSessionKeyRepo(dbc)
|
skRepo := db.NewSessionKeyRepo(dbc)
|
||||||
cfgRepo := db.NewConnectorConfigRepo(dbc)
|
cfgRepo := db.NewConnectorConfigRepo(dbc)
|
||||||
|
@ -290,7 +257,7 @@ func (cfg *MultiServerConfig) Configure(srv *Server) error {
|
||||||
|
|
||||||
sm := sessionmanager.NewSessionManager(sRepo, skRepo)
|
sm := sessionmanager.NewSessionManager(sRepo, skRepo)
|
||||||
|
|
||||||
srv.ClientIdentityRepo = ciRepo
|
srv.ClientRepo = ciRepo
|
||||||
srv.KeySetRepo = kRepo
|
srv.KeySetRepo = kRepo
|
||||||
srv.ConnectorConfigRepo = cfgRepo
|
srv.ConnectorConfigRepo = cfgRepo
|
||||||
srv.UserRepo = userRepo
|
srv.UserRepo = userRepo
|
||||||
|
|
|
@ -28,7 +28,7 @@ func handleVerifyEmailResendFunc(
|
||||||
srvKeysFunc func() ([]key.PublicKey, error),
|
srvKeysFunc func() ([]key.PublicKey, error),
|
||||||
emailer *useremail.UserEmailer,
|
emailer *useremail.UserEmailer,
|
||||||
userRepo user.UserRepo,
|
userRepo user.UserRepo,
|
||||||
clientIdentityRepo client.ClientIdentityRepo) http.HandlerFunc {
|
clientRepo client.ClientRepo) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
var params struct {
|
var params struct {
|
||||||
|
@ -57,7 +57,7 @@ func handleVerifyEmailResendFunc(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cm, err := clientIdentityRepo.Metadata(clientID)
|
cm, err := clientRepo.Metadata(clientID)
|
||||||
if err == client.ErrorNotFound {
|
if err == client.ErrorNotFound {
|
||||||
log.Errorf("No such client: %v", err)
|
log.Errorf("No such client: %v", err)
|
||||||
writeAPIError(w, http.StatusBadRequest,
|
writeAPIError(w, http.StatusBadRequest,
|
||||||
|
|
|
@ -130,7 +130,7 @@ func TestHandleVerifyEmailResend(t *testing.T) {
|
||||||
keysFunc,
|
keysFunc,
|
||||||
f.srv.UserEmailer,
|
f.srv.UserEmailer,
|
||||||
f.userRepo,
|
f.userRepo,
|
||||||
f.clientIdentityRepo)
|
f.clientRepo)
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
u := "http://example.com"
|
u := "http://example.com"
|
||||||
|
|
|
@ -78,9 +78,9 @@ func TestHandleAuthFuncResponsesSingleRedirectURL(t *testing.T) {
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
|
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
|
||||||
ClientIdentityRepo: func() client.ClientIdentityRepo {
|
ClientRepo: func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
||||||
|
@ -230,9 +230,9 @@ func TestHandleAuthFuncResponsesMultipleRedirectURLs(t *testing.T) {
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
|
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
|
||||||
ClientIdentityRepo: func() client.ClientIdentityRepo {
|
ClientRepo: func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
||||||
|
|
|
@ -29,7 +29,7 @@ type SendResetPasswordEmailHandler struct {
|
||||||
tpl *template.Template
|
tpl *template.Template
|
||||||
emailer *useremail.UserEmailer
|
emailer *useremail.UserEmailer
|
||||||
sm *sessionmanager.SessionManager
|
sm *sessionmanager.SessionManager
|
||||||
cr client.ClientIdentityRepo
|
cr client.ClientRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SendResetPasswordEmailHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *SendResetPasswordEmailHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -267,7 +267,7 @@ func TestSendResetPasswordEmailHandler(t *testing.T) {
|
||||||
tpl: f.srv.SendResetPasswordEmailTemplate,
|
tpl: f.srv.SendResetPasswordEmailTemplate,
|
||||||
emailer: f.srv.UserEmailer,
|
emailer: f.srv.UserEmailer,
|
||||||
sm: f.sessionManager,
|
sm: f.sessionManager,
|
||||||
cr: f.clientIdentityRepo,
|
cr: f.clientRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
|
@ -60,7 +60,7 @@ type Server struct {
|
||||||
KeyManager key.PrivateKeyManager
|
KeyManager key.PrivateKeyManager
|
||||||
KeySetRepo key.PrivateKeySetRepo
|
KeySetRepo key.PrivateKeySetRepo
|
||||||
SessionManager *sessionmanager.SessionManager
|
SessionManager *sessionmanager.SessionManager
|
||||||
ClientIdentityRepo client.ClientIdentityRepo
|
ClientRepo client.ClientRepo
|
||||||
ConnectorConfigRepo connector.ConnectorConfigRepo
|
ConnectorConfigRepo connector.ConnectorConfigRepo
|
||||||
Templates *template.Template
|
Templates *template.Template
|
||||||
LoginTemplate *template.Template
|
LoginTemplate *template.Template
|
||||||
|
@ -213,13 +213,13 @@ func (s *Server) HTTPHandler() http.Handler {
|
||||||
s.KeyManager.PublicKeys,
|
s.KeyManager.PublicKeys,
|
||||||
s.UserEmailer,
|
s.UserEmailer,
|
||||||
s.UserRepo,
|
s.UserRepo,
|
||||||
s.ClientIdentityRepo)))
|
s.ClientRepo)))
|
||||||
|
|
||||||
mux.Handle(httpPathSendResetPassword, &SendResetPasswordEmailHandler{
|
mux.Handle(httpPathSendResetPassword, &SendResetPasswordEmailHandler{
|
||||||
tpl: s.SendResetPasswordEmailTemplate,
|
tpl: s.SendResetPasswordEmailTemplate,
|
||||||
emailer: s.UserEmailer,
|
emailer: s.UserEmailer,
|
||||||
sm: s.SessionManager,
|
sm: s.SessionManager,
|
||||||
cr: s.ClientIdentityRepo,
|
cr: s.ClientRepo,
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle(httpPathResetPassword, &ResetPasswordHandler{
|
mux.Handle(httpPathResetPassword, &ResetPasswordHandler{
|
||||||
|
@ -256,11 +256,11 @@ func (s *Server) HTTPHandler() http.Handler {
|
||||||
apiBasePath := path.Join(httpPathAPI, APIVersion)
|
apiBasePath := path.Join(httpPathAPI, APIVersion)
|
||||||
registerDiscoveryResource(apiBasePath, mux)
|
registerDiscoveryResource(apiBasePath, mux)
|
||||||
|
|
||||||
clientPath, clientHandler := registerClientResource(apiBasePath, s.ClientIdentityRepo)
|
clientPath, clientHandler := registerClientResource(apiBasePath, s.ClientRepo)
|
||||||
mux.Handle(path.Join(apiBasePath, clientPath), s.NewClientTokenAuthHandler(clientHandler))
|
mux.Handle(path.Join(apiBasePath, clientPath), s.NewClientTokenAuthHandler(clientHandler))
|
||||||
|
|
||||||
usersAPI := usersapi.NewUsersAPI(s.dbMap, s.UserManager, s.UserEmailer, s.localConnectorID)
|
usersAPI := usersapi.NewUsersAPI(s.dbMap, s.UserManager, s.UserEmailer, s.localConnectorID)
|
||||||
handler := NewUserMgmtServer(usersAPI, s.JWTVerifierFactory(), s.UserManager, s.ClientIdentityRepo).HTTPHandler()
|
handler := NewUserMgmtServer(usersAPI, s.JWTVerifierFactory(), s.UserManager, s.ClientRepo).HTTPHandler()
|
||||||
|
|
||||||
mux.Handle(apiBasePath+"/", handler)
|
mux.Handle(apiBasePath+"/", handler)
|
||||||
|
|
||||||
|
@ -271,14 +271,14 @@ func (s *Server) HTTPHandler() http.Handler {
|
||||||
func (s *Server) NewClientTokenAuthHandler(handler http.Handler) http.Handler {
|
func (s *Server) NewClientTokenAuthHandler(handler http.Handler) http.Handler {
|
||||||
return &clientTokenMiddleware{
|
return &clientTokenMiddleware{
|
||||||
issuerURL: s.IssuerURL.String(),
|
issuerURL: s.IssuerURL.String(),
|
||||||
ciRepo: s.ClientIdentityRepo,
|
ciRepo: s.ClientRepo,
|
||||||
keysFunc: s.KeyManager.PublicKeys,
|
keysFunc: s.KeyManager.PublicKeys,
|
||||||
next: handler,
|
next: handler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ClientMetadata(clientID string) (*oidc.ClientMetadata, error) {
|
func (s *Server) ClientMetadata(clientID string) (*oidc.ClientMetadata, error) {
|
||||||
return s.ClientIdentityRepo.Metadata(clientID)
|
return s.ClientRepo.Metadata(clientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) NewSession(ipdcID, clientID, clientState string, redirectURL url.URL, nonce string, register bool, scope []string) (string, error) {
|
func (s *Server) NewSession(ipdcID, clientID, clientState string, redirectURL url.URL, nonce string, register bool, scope []string) (string, error) {
|
||||||
|
@ -365,7 +365,7 @@ func (s *Server) Login(ident oidc.Identity, key string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ClientCredsToken(creds oidc.ClientCredentials) (*jose.JWT, error) {
|
func (s *Server) ClientCredsToken(creds oidc.ClientCredentials) (*jose.JWT, error) {
|
||||||
ok, err := s.ClientIdentityRepo.Authenticate(creds)
|
ok, err := s.ClientRepo.Authenticate(creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
||||||
return nil, oauth2.NewError(oauth2.ErrorServerError)
|
return nil, oauth2.NewError(oauth2.ErrorServerError)
|
||||||
|
@ -397,7 +397,7 @@ func (s *Server) ClientCredsToken(creds oidc.ClientCredentials) (*jose.JWT, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) CodeToken(creds oidc.ClientCredentials, sessionKey string) (*jose.JWT, string, error) {
|
func (s *Server) CodeToken(creds oidc.ClientCredentials, sessionKey string) (*jose.JWT, string, error) {
|
||||||
ok, err := s.ClientIdentityRepo.Authenticate(creds)
|
ok, err := s.ClientRepo.Authenticate(creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
||||||
return nil, "", oauth2.NewError(oauth2.ErrorServerError)
|
return nil, "", oauth2.NewError(oauth2.ErrorServerError)
|
||||||
|
@ -466,7 +466,7 @@ func (s *Server) CodeToken(creds oidc.ClientCredentials, sessionKey string) (*jo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RefreshToken(creds oidc.ClientCredentials, token string) (*jose.JWT, error) {
|
func (s *Server) RefreshToken(creds oidc.ClientCredentials, token string) (*jose.JWT, error) {
|
||||||
ok, err := s.ClientIdentityRepo.Authenticate(creds)
|
ok, err := s.ClientRepo.Authenticate(creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err)
|
||||||
return nil, oauth2.NewError(oauth2.ErrorServerError)
|
return nil, oauth2.NewError(oauth2.ErrorServerError)
|
||||||
|
|
|
@ -130,7 +130,7 @@ func TestServerNewSession(t *testing.T) {
|
||||||
|
|
||||||
state := "pants"
|
state := "pants"
|
||||||
nonce := "oncenay"
|
nonce := "oncenay"
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: "secrete",
|
Secret: "secrete",
|
||||||
|
@ -179,7 +179,7 @@ func TestServerNewSession(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerLogin(t *testing.T) {
|
func TestServerLogin(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: clientTestSecret,
|
Secret: clientTestSecret,
|
||||||
|
@ -194,8 +194,8 @@ func TestServerLogin(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ciRepo := func() client.ClientIdentityRepo {
|
ciRepo := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: %v", err)
|
t.Fatalf("Failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -219,11 +219,11 @@ func TestServerLogin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
ident := oidc.Identity{ID: "YYY", Name: "elroy", Email: "elroy@example.com"}
|
ident := oidc.Identity{ID: "YYY", Name: "elroy", Email: "elroy@example.com"}
|
||||||
|
@ -244,9 +244,9 @@ func TestServerLogin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
|
func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
|
||||||
ciRepo := func() client.ClientIdentityRepo {
|
ciRepo := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX", Secret: clientTestSecret,
|
ID: "XXX", Secret: clientTestSecret,
|
||||||
},
|
},
|
||||||
|
@ -263,10 +263,10 @@ func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
sm := manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB()))
|
sm := manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB()))
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
ident := oidc.Identity{ID: "YYY", Name: "elroy", Email: "elroy@example.com"}
|
ident := oidc.Identity{ID: "YYY", Name: "elroy", Email: "elroy@example.com"}
|
||||||
|
@ -281,7 +281,7 @@ func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerLoginDisabledUser(t *testing.T) {
|
func TestServerLoginDisabledUser(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: clientTestSecret,
|
Secret: clientTestSecret,
|
||||||
|
@ -296,8 +296,8 @@ func TestServerLoginDisabledUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ciRepo := func() client.ClientIdentityRepo {
|
ciRepo := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: %v", err)
|
t.Fatalf("Failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -335,11 +335,11 @@ func TestServerLoginDisabledUser(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
ident := oidc.Identity{ID: "disabled-connector-id", Name: "elroy", Email: "elroy@example.com"}
|
ident := oidc.Identity{ID: "disabled-connector-id", Name: "elroy", Email: "elroy@example.com"}
|
||||||
|
@ -355,14 +355,14 @@ func TestServerLoginDisabledUser(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerCodeToken(t *testing.T) {
|
func TestServerCodeToken(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: clientTestSecret,
|
Secret: clientTestSecret,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ciRepo := func() client.ClientIdentityRepo {
|
ciRepo := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: %v", err)
|
t.Fatalf("Failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -381,12 +381,12 @@ func TestServerCodeToken(t *testing.T) {
|
||||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
RefreshTokenRepo: refreshTokenRepo,
|
RefreshTokenRepo: refreshTokenRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -441,14 +441,14 @@ func TestServerCodeToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerTokenUnrecognizedKey(t *testing.T) {
|
func TestServerTokenUnrecognizedKey(t *testing.T) {
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: clientTestSecret,
|
Secret: clientTestSecret,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ciRepo := func() client.ClientIdentityRepo {
|
ciRepo := func() client.ClientRepo {
|
||||||
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
|
repo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{ci})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create client identity repo: %v", err)
|
t.Fatalf("Failed to create client identity repo: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -460,10 +460,10 @@ func TestServerTokenUnrecognizedKey(t *testing.T) {
|
||||||
sm := manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB()))
|
sm := manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB()))
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionID, err := sm.NewSession("connector_id", ci.Credentials.ID, "bogus", url.URL{}, "", false, []string{"openid", "offline_access"})
|
sessionID, err := sm.NewSession("connector_id", ci.Credentials.ID, "bogus", url.URL{}, "", false, []string{"openid", "offline_access"})
|
||||||
|
@ -569,8 +569,8 @@ func TestServerTokenFail(t *testing.T) {
|
||||||
km := &StaticKeyManager{
|
km := &StaticKeyManager{
|
||||||
signer: tt.signer,
|
signer: tt.signer,
|
||||||
}
|
}
|
||||||
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
ciRepo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{Credentials: ccFixture},
|
client.Client{Credentials: ccFixture},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
||||||
|
@ -590,12 +590,12 @@ func TestServerTokenFail(t *testing.T) {
|
||||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: issuerURL,
|
IssuerURL: issuerURL,
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
SessionManager: sm,
|
SessionManager: sm,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
RefreshTokenRepo: refreshTokenRepo,
|
RefreshTokenRepo: refreshTokenRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sm.NewSessionKey(sessionID)
|
_, err = sm.NewSessionKey(sessionID)
|
||||||
|
@ -731,9 +731,9 @@ func TestServerRefreshToken(t *testing.T) {
|
||||||
signer: tt.signer,
|
signer: tt.signer,
|
||||||
}
|
}
|
||||||
|
|
||||||
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
ciRepo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{Credentials: credXXX},
|
client.Client{Credentials: credXXX},
|
||||||
oidc.ClientIdentity{Credentials: credYYY},
|
client.Client{Credentials: credYYY},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
|
||||||
|
@ -748,11 +748,11 @@ func TestServerRefreshToken(t *testing.T) {
|
||||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: issuerURL,
|
IssuerURL: issuerURL,
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
RefreshTokenRepo: refreshTokenRepo,
|
RefreshTokenRepo: refreshTokenRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := refreshTokenRepo.Create("testid-1", tt.clientID); err != nil {
|
if _, err := refreshTokenRepo.Create("testid-1", tt.clientID); err != nil {
|
||||||
|
@ -784,9 +784,9 @@ func TestServerRefreshToken(t *testing.T) {
|
||||||
signer: signerFixture,
|
signer: signerFixture,
|
||||||
}
|
}
|
||||||
|
|
||||||
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
ciRepo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{Credentials: credXXX},
|
client.Client{Credentials: credXXX},
|
||||||
oidc.ClientIdentity{Credentials: credYYY},
|
client.Client{Credentials: credYYY},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create client identity repo: %v", err)
|
t.Fatalf("failed to create client identity repo: %v", err)
|
||||||
|
@ -808,11 +808,11 @@ func TestServerRefreshToken(t *testing.T) {
|
||||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: issuerURL,
|
IssuerURL: issuerURL,
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
ClientIdentityRepo: ciRepo,
|
ClientRepo: ciRepo,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
RefreshTokenRepo: refreshTokenRepo,
|
RefreshTokenRepo: refreshTokenRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := refreshTokenRepo.Create("testid-2", credXXX.ID); err != nil {
|
if _, err := refreshTokenRepo.Create("testid-2", credXXX.ID); err != nil {
|
||||||
|
|
|
@ -73,12 +73,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type testFixtures struct {
|
type testFixtures struct {
|
||||||
srv *Server
|
srv *Server
|
||||||
userRepo user.UserRepo
|
userRepo user.UserRepo
|
||||||
sessionManager *sessionmanager.SessionManager
|
sessionManager *sessionmanager.SessionManager
|
||||||
emailer *email.TemplatizedEmailer
|
emailer *email.TemplatizedEmailer
|
||||||
redirectURL url.URL
|
redirectURL url.URL
|
||||||
clientIdentityRepo client.ClientIdentityRepo
|
clientRepo client.ClientRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func sequentialGenerateCodeFunc() sessionmanager.GenerateCodeFunc {
|
func sequentialGenerateCodeFunc() sessionmanager.GenerateCodeFunc {
|
||||||
|
@ -136,8 +136,8 @@ func makeTestFixtures() (*testFixtures, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientIdentityRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
|
clientRepo, err := db.NewClientRepoFromClients(db.NewMemDB(), []client.Client{
|
||||||
oidc.ClientIdentity{
|
client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
||||||
|
@ -167,14 +167,14 @@ func makeTestFixtures() (*testFixtures, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
IssuerURL: testIssuerURL,
|
IssuerURL: testIssuerURL,
|
||||||
SessionManager: sessionManager,
|
SessionManager: sessionManager,
|
||||||
ClientIdentityRepo: clientIdentityRepo,
|
ClientRepo: clientRepo,
|
||||||
Templates: tpl,
|
Templates: tpl,
|
||||||
UserRepo: userRepo,
|
UserRepo: userRepo,
|
||||||
PasswordInfoRepo: pwRepo,
|
PasswordInfoRepo: pwRepo,
|
||||||
UserManager: manager,
|
UserManager: manager,
|
||||||
KeyManager: km,
|
KeyManager: km,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setTemplates(srv, tpl)
|
err = setTemplates(srv, tpl)
|
||||||
|
@ -201,11 +201,11 @@ func makeTestFixtures() (*testFixtures, error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
return &testFixtures{
|
return &testFixtures{
|
||||||
srv: srv,
|
srv: srv,
|
||||||
redirectURL: testRedirectURL,
|
redirectURL: testRedirectURL,
|
||||||
userRepo: userRepo,
|
userRepo: userRepo,
|
||||||
sessionManager: sessionManager,
|
sessionManager: sessionManager,
|
||||||
emailer: emailer,
|
emailer: emailer,
|
||||||
clientIdentityRepo: clientIdentityRepo,
|
clientRepo: clientRepo,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,10 @@ type UserMgmtServer struct {
|
||||||
api *api.UsersAPI
|
api *api.UsersAPI
|
||||||
jwtvFactory JWTVerifierFactory
|
jwtvFactory JWTVerifierFactory
|
||||||
um *manager.UserManager
|
um *manager.UserManager
|
||||||
cir client.ClientIdentityRepo
|
cir client.ClientRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserMgmtServer(userMgmtAPI *api.UsersAPI, jwtvFactory JWTVerifierFactory, um *manager.UserManager, cir client.ClientIdentityRepo) *UserMgmtServer {
|
func NewUserMgmtServer(userMgmtAPI *api.UsersAPI, jwtvFactory JWTVerifierFactory, um *manager.UserManager, cir client.ClientRepo) *UserMgmtServer {
|
||||||
return &UserMgmtServer{
|
return &UserMgmtServer{
|
||||||
api: userMgmtAPI,
|
api: userMgmtAPI,
|
||||||
jwtvFactory: jwtvFactory,
|
jwtvFactory: jwtvFactory,
|
||||||
|
|
|
@ -88,11 +88,11 @@ func (e Error) Error() string {
|
||||||
// calling User. It is assumed that the clientID has already validated as an
|
// calling User. It is assumed that the clientID has already validated as an
|
||||||
// admin app before calling.
|
// admin app before calling.
|
||||||
type UsersAPI struct {
|
type UsersAPI struct {
|
||||||
manager *manager.UserManager
|
manager *manager.UserManager
|
||||||
localConnectorID string
|
localConnectorID string
|
||||||
clientIdentityRepo client.ClientIdentityRepo
|
clientRepo client.ClientRepo
|
||||||
refreshRepo refresh.RefreshTokenRepo
|
refreshRepo refresh.RefreshTokenRepo
|
||||||
emailer Emailer
|
emailer Emailer
|
||||||
}
|
}
|
||||||
|
|
||||||
type Emailer interface {
|
type Emailer interface {
|
||||||
|
@ -107,11 +107,11 @@ type Creds struct {
|
||||||
// TODO(ericchiang): Don't pass a dbMap. See #385.
|
// TODO(ericchiang): Don't pass a dbMap. See #385.
|
||||||
func NewUsersAPI(dbMap *gorp.DbMap, userManager *manager.UserManager, emailer Emailer, localConnectorID string) *UsersAPI {
|
func NewUsersAPI(dbMap *gorp.DbMap, userManager *manager.UserManager, emailer Emailer, localConnectorID string) *UsersAPI {
|
||||||
return &UsersAPI{
|
return &UsersAPI{
|
||||||
manager: userManager,
|
manager: userManager,
|
||||||
refreshRepo: db.NewRefreshTokenRepo(dbMap),
|
refreshRepo: db.NewRefreshTokenRepo(dbMap),
|
||||||
clientIdentityRepo: db.NewClientIdentityRepo(dbMap),
|
clientRepo: db.NewClientRepo(dbMap),
|
||||||
localConnectorID: localConnectorID,
|
localConnectorID: localConnectorID,
|
||||||
emailer: emailer,
|
emailer: emailer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ func (u *UsersAPI) CreateUser(creds Creds, usr schema.User, redirURL url.URL) (s
|
||||||
return schema.UserCreateResponse{}, mapError(err)
|
return schema.UserCreateResponse{}, mapError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := u.clientIdentityRepo.Metadata(creds.ClientID)
|
metadata, err := u.clientRepo.Metadata(creds.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return schema.UserCreateResponse{}, mapError(err)
|
return schema.UserCreateResponse{}, mapError(err)
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ func (u *UsersAPI) ResendEmailInvitation(creds Creds, userID string, redirURL ur
|
||||||
return schema.ResendEmailInvitationResponse{}, ErrorUnauthorized
|
return schema.ResendEmailInvitationResponse{}, ErrorUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := u.clientIdentityRepo.Metadata(creds.ClientID)
|
metadata, err := u.clientRepo.Metadata(creds.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return schema.ResendEmailInvitationResponse{}, mapError(err)
|
return schema.ResendEmailInvitationResponse{}, mapError(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/jonboulle/clockwork"
|
"github.com/jonboulle/clockwork"
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
|
||||||
|
"github.com/coreos/dex/client"
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/db"
|
"github.com/coreos/dex/db"
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
schema "github.com/coreos/dex/schema/workerschema"
|
||||||
|
@ -155,7 +156,7 @@ func makeTestFixtures() (*UsersAPI, *testEmailer) {
|
||||||
|
|
||||||
mgr := manager.NewUserManager(ur, pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
mgr := manager.NewUserManager(ur, pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
||||||
mgr.Clock = clock
|
mgr.Clock = clock
|
||||||
ci := oidc.ClientIdentity{
|
ci := client.Client{
|
||||||
Credentials: oidc.ClientCredentials{
|
Credentials: oidc.ClientCredentials{
|
||||||
ID: "XXX",
|
ID: "XXX",
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
|
||||||
|
@ -166,8 +167,8 @@ func makeTestFixtures() (*UsersAPI, *testEmailer) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if _, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{ci}); err != nil {
|
if _, err := db.NewClientRepoFromClients(dbMap, []client.Client{ci}); err != nil {
|
||||||
panic("Failed to create client identity repo: " + err.Error())
|
panic("Failed to create client repo: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in TestRevokeRefreshToken test.
|
// Used in TestRevokeRefreshToken test.
|
||||||
|
|
Loading…
Reference in a new issue