*: Client Repo now deals with custom Client object

This is instead of oidc.ClientIdentity. This makes it easier to add new
fields custom to dex to the client.
This commit is contained in:
Bobby Rullo 2016-04-14 15:57:53 -07:00
parent 35cefb7da9
commit 95757e8779
22 changed files with 241 additions and 156 deletions

View file

@ -116,25 +116,38 @@ func (a *AdminAPI) GetState() (adminschema.State, error) {
return state, nil
}
type ClientRegistrationRequest struct {
IsAdmin bool `json:"isAdmin"`
Client oidc.ClientMetadata `json:"client"`
}
func (a *AdminAPI) CreateClient(req adminschema.ClientCreateRequest) (adminschema.ClientCreateResponse, error) {
cli, err := adminschema.MapSchemaClientToClient(*req.Client)
if err != nil {
// TODO should be 400s
return adminschema.ClientCreateResponse{}, mapError(err)
}
func (a *AdminAPI) CreateClient(req ClientRegistrationRequest) (oidc.ClientRegistrationResponse, error) {
if err := req.Client.Valid(); err != nil {
return oidc.ClientRegistrationResponse{}, mapError(err)
if err := cli.Metadata.Valid(); err != nil {
// TODO make sure this is not 500
return adminschema.ClientCreateResponse{}, mapError(err)
}
// metadata is guarenteed to have at least one redirect_uri by earlier validation.
id, err := oidc.GenClientID(req.Client.RedirectURIs[0].Host)
id, err := oidc.GenClientID(cli.Metadata.RedirectURIs[0].Host)
if err != nil {
return oidc.ClientRegistrationResponse{}, mapError(err)
return adminschema.ClientCreateResponse{}, mapError(err)
}
c, err := a.clientIdentityRepo.New(id, req.Client, req.IsAdmin)
cli.Credentials.ID = id
creds, err := a.clientIdentityRepo.New(cli)
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
req.Client.Id = creds.ID
req.Client.Secret = creds.Secret
return adminschema.ClientCreateResponse{
Client: req.Client,
}, nil
// github.com/coreos/dex/integrationoidc.ClientRegistrationResponse{ClientID: c.ID, ClientSecret: c.Secret, ClientMetadata: req.Client.Metadata}, nil
}
func mapError(e error) error {

View file

@ -1,7 +1,9 @@
package client
import (
"encoding/json"
"errors"
"io"
"net/url"
"reflect"
@ -15,7 +17,15 @@ var (
ErrorNotFound = errors.New("no data found")
)
type Client struct {
Credentials oidc.ClientCredentials
Metadata oidc.ClientMetadata
Admin bool
}
type ClientIdentityRepo interface {
Get(clientID string) (Client, error)
// Metadata returns one matching ClientMetadata if the given client
// exists, otherwise nil. The returned error will be non-nil only
// if the repo was unable to determine client existence.
@ -28,12 +38,12 @@ type ClientIdentityRepo interface {
Authenticate(creds oidc.ClientCredentials) (bool, error)
// All returns all registered Client Identities.
All() ([]oidc.ClientIdentity, error)
All() ([]Client, error)
// New registers a ClientIdentity with the repo for the given metadata.
// An unused ID must be provided. A corresponding secret will be returned
// 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
@ -64,3 +74,36 @@ func ValidRedirectURL(rURL *url.URL, redirectURLs []url.URL) (url.URL, error) {
}
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 {
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
}

View file

@ -41,21 +41,29 @@ func init() {
})
}
func newClientIdentityModel(id string, secret []byte, meta *oidc.ClientMetadata) (*clientIdentityModel, error) {
hashed, err := bcrypt.GenerateFromPassword(secret, bcryptHashCost)
func newClientIdentityModel(cli client.Client) (*clientIdentityModel, error) {
secretBytes, err := base64.URLEncoding.DecodeString(cli.Credentials.Secret)
if err != nil {
return nil, err
}
bmeta, err := json.Marshal(meta)
hashed, err := bcrypt.GenerateFromPassword([]byte(
secretBytes),
bcryptHashCost)
if err != nil {
return nil, err
}
bmeta, err := json.Marshal(&cli.Metadata)
if err != nil {
return nil, err
}
cim := clientIdentityModel{
ID: id,
ID: cli.Credentials.ID,
Secret: hashed,
Metadata: string(bmeta),
DexAdmin: cli.Admin,
}
return &cim, nil
@ -68,12 +76,13 @@ type clientIdentityModel struct {
DexAdmin bool `db:"dex_admin"`
}
func (m *clientIdentityModel) ClientIdentity() (*oidc.ClientIdentity, error) {
ci := oidc.ClientIdentity{
func (m *clientIdentityModel) Client() (*client.Client, error) {
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: m.ID,
Secret: string(m.Secret),
},
Admin: m.DexAdmin,
}
if err := json.Unmarshal([]byte(m.Metadata), &ci.Metadata); err != nil {
@ -91,7 +100,7 @@ func newClientIdentityRepo(dbm *gorp.DbMap) *clientIdentityRepo {
return &clientIdentityRepo{db: &db{dbm}}
}
func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []oidc.ClientIdentity) (client.ClientIdentityRepo, error) {
func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []client.Client) (client.ClientIdentityRepo, error) {
repo := newClientIdentityRepo(dbm)
tx, err := repo.begin()
if err != nil {
@ -103,12 +112,7 @@ func NewClientIdentityRepoFromClients(dbm *gorp.DbMap, clients []oidc.ClientIden
if c.Credentials.Secret == "" {
return nil, fmt.Errorf("client %q has no secret", c.Credentials.ID)
}
dec, err := base64.URLEncoding.DecodeString(c.Credentials.Secret)
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)
cm, err := newClientIdentityModel(c)
if err != nil {
return nil, err
}
@ -127,27 +131,37 @@ type clientIdentityRepo struct {
*db
}
func (r *clientIdentityRepo) Metadata(clientID string) (*oidc.ClientMetadata, error) {
func (r *clientIdentityRepo) Get(clientID string) (client.Client, error) {
m, err := r.executor(nil).Get(clientIdentityModel{}, clientID)
if err == sql.ErrNoRows || m == nil {
return nil, client.ErrorNotFound
return client.Client{}, client.ErrorNotFound
}
if err != nil {
return nil, err
return client.Client{}, err
}
cim, ok := m.(*clientIdentityModel)
if !ok {
log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m))
return nil, errors.New("unrecognized model")
log.Errorf("expected clientModel but found %v", reflect.TypeOf(m))
return client.Client{}, errors.New("unrecognized model")
}
ci, err := cim.ClientIdentity()
ci, err := cim.Client()
if err != nil {
return client.Client{}, err
}
return *ci, nil
}
func (r *clientIdentityRepo) Metadata(clientID string) (*oidc.ClientMetadata, error) {
c, err := r.Get(clientID)
if err != nil {
return nil, err
}
return &ci.Metadata, nil
return &c.Metadata, nil
}
func (r *clientIdentityRepo) IsDexAdmin(clientID string) (bool, error) {
@ -238,17 +252,17 @@ func isAlreadyExistsErr(err error) bool {
return false
}
func (r *clientIdentityRepo) New(id string, meta oidc.ClientMetadata, admin bool) (*oidc.ClientCredentials, error) {
func (r *clientIdentityRepo) New(cli client.Client) (*oidc.ClientCredentials, error) {
secret, err := pcrypto.RandBytes(maxSecretLength)
if err != nil {
return nil, err
}
cim, err := newClientIdentityModel(id, secret, &meta)
cli.Credentials.Secret = base64.URLEncoding.EncodeToString(secret)
cim, err := newClientIdentityModel(cli)
if err != nil {
return nil, err
}
cim.DexAdmin = admin
if err := r.executor(nil).Insert(cim); err != nil {
if isAlreadyExistsErr(err) {
@ -258,14 +272,14 @@ func (r *clientIdentityRepo) New(id string, meta oidc.ClientMetadata, admin bool
}
cc := oidc.ClientCredentials{
ID: id,
Secret: base64.URLEncoding.EncodeToString(secret),
ID: cli.Credentials.ID,
Secret: cli.Credentials.Secret,
}
return &cc, nil
}
func (r *clientIdentityRepo) All() ([]oidc.ClientIdentity, error) {
func (r *clientIdentityRepo) All() ([]client.Client, error) {
qt := r.quote(clientIdentityTableName)
q := fmt.Sprintf("SELECT * FROM %s", qt)
objs, err := r.executor(nil).Select(&clientIdentityModel{}, q)
@ -273,14 +287,14 @@ func (r *clientIdentityRepo) All() ([]oidc.ClientIdentity, error) {
return nil, err
}
cs := make([]oidc.ClientIdentity, len(objs))
cs := make([]client.Client, len(objs))
for i, obj := range objs {
m, ok := obj.(*clientIdentityModel)
if !ok {
return nil, errors.New("unable to cast client identity to clientIdentityModel")
}
ci, err := m.ClientIdentity()
ci, err := m.Client()
if err != nil {
return nil, err
}

View file

@ -11,10 +11,10 @@ import (
"github.com/go-gorp/gorp"
"golang.org/x/crypto/bcrypt"
"github.com/coreos/dex/client"
"github.com/coreos/dex/pkg/log"
"github.com/coreos/dex/refresh"
"github.com/coreos/dex/repo"
"github.com/coreos/go-oidc/oidc"
)
const (
@ -186,7 +186,7 @@ func (r *refreshTokenRepo) RevokeTokensForClient(userID, clientID string) error
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
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))
@ -196,9 +196,9 @@ func (r *refreshTokenRepo) ClientsWithRefreshTokens(userID string) ([]oidc.Clien
return nil, err
}
c := make([]oidc.ClientIdentity, len(clients))
c := make([]client.Client, len(clients))
for i, client := range clients {
ident, err := client.ClientIdentity()
ident, err := client.Client()
if err != nil {
return nil, err
}

View file

@ -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 {
t.Fatalf(err.Error())
}
@ -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)
}
@ -237,7 +247,12 @@ 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")
}
}
@ -251,7 +266,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 {
t.Fatalf(err.Error())
}
@ -299,7 +319,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 {
t.Fatalf(err.Error())
}
@ -322,7 +347,12 @@ func TestDBClientIdentityAll(t *testing.T) {
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 {
t.Fatalf(err.Error())
}

View file

@ -14,8 +14,8 @@ import (
)
var (
testClients = []oidc.ClientIdentity{
oidc.ClientIdentity{
testClients = []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "client1",
Secret: base64.URLEncoding.EncodeToString([]byte("secret-1")),
@ -30,7 +30,7 @@ var (
},
},
},
oidc.ClientIdentity{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "client2",
Secret: base64.URLEncoding.EncodeToString([]byte("secret-2")),

View file

@ -11,12 +11,13 @@ import (
"github.com/go-gorp/gorp"
"github.com/kylelemons/godebug/pretty"
"github.com/coreos/dex/client"
"github.com/coreos/dex/db"
"github.com/coreos/dex/refresh"
"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
if dsn := os.Getenv("DEX_TEST_DSN"); dsn == "" {
dbMap = db.NewMemDB()
@ -35,7 +36,7 @@ func newRefreshRepo(t *testing.T, users []user.UserWithRemoteIdentities, clients
func TestRefreshTokenRepo(t *testing.T) {
clientID := "client1"
userID := "user1"
clients := []oidc.ClientIdentity{
clients := []client.Client{
{
Credentials: oidc.ClientCredentials{
ID: clientID,

View file

@ -276,21 +276,24 @@ func TestCreateClient(t *testing.T) {
for i, tt := range tests {
err := func() error {
f := makeAdminAPITestFixtures()
req := &adminschema.ClientCreateRequestClient{}
for _, redirectURI := range tt.client.RedirectURIs {
req.Redirect_uris = append(req.Redirect_uris, redirectURI.String())
req := &adminschema.ClientCreateRequest{
Client: &adminschema.Client{},
}
resp, err := f.adClient.Client.Create(&adminschema.ClientCreateRequest{Client: req}).Do()
for _, redirectURI := range tt.client.RedirectURIs {
req.Client.RedirectURIs = append(req.Client.RedirectURIs, redirectURI.String())
}
resp, err := f.adClient.Client.Create(req).Do()
if err != nil {
if tt.wantError {
return nil
}
return err
}
if resp.Client_id == "" {
if resp.Client.Id == "" {
return errors.New("no client id returned")
}
if resp.Client_secret == "" {
if resp.Client.Secret == "" {
return errors.New("no client secret returned")
}
return nil

View file

@ -7,12 +7,13 @@ import (
"reflect"
"testing"
"github.com/coreos/dex/client"
schema "github.com/coreos/dex/schema/workerschema"
"github.com/coreos/go-oidc/oidc"
)
func TestClientCreate(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "72de74a9",
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)
if err != nil {

View file

@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/coreos/dex/client"
"github.com/coreos/dex/connector"
"github.com/coreos/dex/db"
phttp "github.com/coreos/dex/pkg/http"
@ -22,7 +23,7 @@ import (
"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()
k, err := key.GeneratePrivateKey()
if err != nil {
@ -50,7 +51,7 @@ func mockServer(cis []oidc.ClientIdentity) (*server.Server, error) {
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()
sClient := &phttp.HandlerClient{Handler: hdlr}
@ -75,7 +76,7 @@ func mockClient(srv *server.Server, ci oidc.ClientIdentity) (*oidc.Client, error
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
if user != nil {
expectedSub, expectedName = user.ID, user.DisplayName
@ -116,7 +117,7 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
ID: "local",
}
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "72de74a9",
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
@ -124,7 +125,7 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
}
dbMap := db.NewMemDB()
cir, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{ci})
cir, err := db.NewClientIdentityRepoFromClients(dbMap, []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: " + err.Error())
}
@ -262,13 +263,13 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
}
func TestHTTPClientCredsToken(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "72de74a9",
Secret: base64.URLEncoding.EncodeToString([]byte("XXX")),
},
}
cis := []oidc.ClientIdentity{ci}
cis := []client.Client{ci}
srv, err := mockServer(cis)
if err != nil {

View file

@ -102,8 +102,8 @@ func makeUserAPITestFixtures() *userAPITestFixtures {
dbMap, _, _, um := makeUserObjects(userUsers, userPasswords)
cir := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{
oidc.ClientIdentity{
repo, err := db.NewClientIdentityRepoFromClients(dbMap, []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: testClientID,
Secret: testClientSecret,
@ -114,7 +114,7 @@ func makeUserAPITestFixtures() *userAPITestFixtures {
},
},
},
oidc.ClientIdentity{
client.Client{
Credentials: oidc.ClientCredentials{
ID: userBadClientID,
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),

View file

@ -4,7 +4,7 @@ import (
"crypto/rand"
"errors"
"github.com/coreos/go-oidc/oidc"
"github.com/coreos/dex/client"
)
const (
@ -54,5 +54,5 @@ type RefreshTokenRepo interface {
RevokeTokensForClient(userID, clientID string) error
// 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)
}

View file

@ -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) {
var req admin.ClientRegistrationRequest
var req = adminschema.ClientCreateRequest{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeInvalidRequest(w, "cannot parse JSON body")
return

View file

@ -26,7 +26,7 @@ func TestClientToken(t *testing.T) {
now := time.Now()
tomorrow := now.Add(24 * time.Hour)
validClientID := "valid-client"
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: validClientID,
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.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: %v", err)
}

View file

@ -4,7 +4,9 @@ import (
"encoding/json"
"net/http"
"github.com/coreos/dex/client"
"github.com/coreos/dex/pkg/log"
"github.com/coreos/go-oidc/oauth2"
"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")
}
creds, err := s.ClientIdentityRepo.New(id, clientMetadata, false)
creds, err := s.ClientIdentityRepo.New(client.Client{
Credentials: oidc.ClientCredentials{
ID: id,
},
Metadata: clientMetadata,
})
if err != nil {
log.Errorf("Failed to create new client identity: %v", err)
return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata")

View file

@ -49,7 +49,7 @@ func (c *clientResource) list(w http.ResponseWriter, r *http.Request) {
scs := make([]*schema.Client, len(cs))
for i, ci := range cs {
sc := schema.MapClientIdentityToSchemaClient(ci)
sc := schema.MapClientToSchemaClient(ci)
scs[i] = &sc
}
@ -76,7 +76,7 @@ func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
return
}
ci, err := schema.MapSchemaClientToClientIdentity(sc)
ci, err := schema.MapSchemaClientToClient(sc)
if err != nil {
log.Debugf("Invalid request data: %v", err)
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
}
creds, err := c.repo.New(clientID, ci.Metadata, false)
ci.Credentials.ID = clientID
creds, err := c.repo.New(ci)
if err != nil {
log.Errorf("Failed creating client: %v", err)
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
ssc := schema.MapClientIdentityToSchemaClientWithSecret(ci)
ssc := schema.MapClientToSchemaClientWithSecret(ci)
w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
writeResponseWithBody(w, http.StatusCreated, ssc)
}

View file

@ -14,6 +14,7 @@ import (
"strings"
"testing"
"github.com/coreos/dex/client"
"github.com/coreos/dex/db"
schema "github.com/coreos/dex/schema/workerschema"
"github.com/coreos/go-oidc/oidc"
@ -177,7 +178,7 @@ func TestList(t *testing.T) {
}
tests := []struct {
cs []oidc.ClientIdentity
cs []client.Client
want []*schema.Client
}{
// empty repo
@ -187,8 +188,8 @@ func TestList(t *testing.T) {
},
// single client
{
cs: []oidc.ClientIdentity{
oidc.ClientIdentity{
cs: []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
Metadata: oidc.ClientMetadata{
RedirectURIs: []url.URL{
@ -206,8 +207,8 @@ func TestList(t *testing.T) {
},
// multi client
{
cs: []oidc.ClientIdentity{
oidc.ClientIdentity{
cs: []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{ID: "foo", Secret: b64Encode("bar")},
Metadata: oidc.ClientMetadata{
RedirectURIs: []url.URL{
@ -215,7 +216,7 @@ func TestList(t *testing.T) {
},
},
},
oidc.ClientIdentity{
client.Client{
Credentials: oidc.ClientCredentials{ID: "biz", Secret: b64Encode("bang")},
Metadata: oidc.ClientMetadata{
RedirectURIs: []url.URL{

View file

@ -13,10 +13,10 @@ import (
"time"
"github.com/coreos/go-oidc/key"
"github.com/coreos/go-oidc/oidc"
"github.com/coreos/pkg/health"
"github.com/go-gorp/gorp"
"github.com/coreos/dex/client"
"github.com/coreos/dex/connector"
"github.com/coreos/dex/db"
"github.com/coreos/dex/email"
@ -214,47 +214,14 @@ func loadUsersFromReader(r io.Reader) (users []user.UserWithRemoteIdentities, pw
return
}
// loadClients parses the clients.json file and returns the clients to be created.
func loadClients(filepath string) ([]oidc.ClientIdentity, error) {
// loadClients parses the clients.json file and returns a list of clients.
func loadClients(filepath string) ([]client.Client, error) {
f, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer f.Close()
return loadClientsFromReader(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
return client.ClientsFromReader(f)
}
func (cfg *MultiServerConfig) Configure(srv *Server) error {

View file

@ -79,8 +79,8 @@ func TestHandleAuthFuncResponsesSingleRedirectURL(t *testing.T) {
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
ClientIdentityRepo: func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
@ -231,8 +231,8 @@ func TestHandleAuthFuncResponsesMultipleRedirectURLs(t *testing.T) {
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
SessionManager: manager.NewSessionManager(db.NewSessionRepo(db.NewMemDB()), db.NewSessionKeyRepo(db.NewMemDB())),
ClientIdentityRepo: func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),

View file

@ -130,7 +130,7 @@ func TestServerNewSession(t *testing.T) {
state := "pants"
nonce := "oncenay"
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: "secrete",
@ -179,7 +179,7 @@ func TestServerNewSession(t *testing.T) {
}
func TestServerLogin(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: clientTestSecret,
@ -195,7 +195,7 @@ func TestServerLogin(t *testing.T) {
},
}
ciRepo := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: %v", err)
}
@ -245,8 +245,8 @@ func TestServerLogin(t *testing.T) {
func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
ciRepo := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX", Secret: clientTestSecret,
},
@ -281,7 +281,7 @@ func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
}
func TestServerLoginDisabledUser(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: clientTestSecret,
@ -297,7 +297,7 @@ func TestServerLoginDisabledUser(t *testing.T) {
},
}
ciRepo := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: %v", err)
}
@ -355,14 +355,14 @@ func TestServerLoginDisabledUser(t *testing.T) {
}
func TestServerCodeToken(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: clientTestSecret,
},
}
ciRepo := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: %v", err)
}
@ -441,14 +441,14 @@ func TestServerCodeToken(t *testing.T) {
}
func TestServerTokenUnrecognizedKey(t *testing.T) {
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: clientTestSecret,
},
}
ciRepo := func() client.ClientIdentityRepo {
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{ci})
repo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{ci})
if err != nil {
t.Fatalf("Failed to create client identity repo: %v", err)
}
@ -569,8 +569,8 @@ func TestServerTokenFail(t *testing.T) {
km := &StaticKeyManager{
signer: tt.signer,
}
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{Credentials: ccFixture},
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{Credentials: ccFixture},
})
if err != nil {
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
@ -731,9 +731,9 @@ func TestServerRefreshToken(t *testing.T) {
signer: tt.signer,
}
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{Credentials: credXXX},
oidc.ClientIdentity{Credentials: credYYY},
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{Credentials: credXXX},
client.Client{Credentials: credYYY},
})
if err != nil {
t.Errorf("case %d: failed to create client identity repo: %v", i, err)
@ -784,9 +784,9 @@ func TestServerRefreshToken(t *testing.T) {
signer: signerFixture,
}
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{Credentials: credXXX},
oidc.ClientIdentity{Credentials: credYYY},
ciRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{Credentials: credXXX},
client.Client{Credentials: credYYY},
})
if err != nil {
t.Fatalf("failed to create client identity repo: %v", err)

View file

@ -136,8 +136,8 @@ func makeTestFixtures() (*testFixtures, error) {
return nil, err
}
clientIdentityRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []oidc.ClientIdentity{
oidc.ClientIdentity{
clientIdentityRepo, err := db.NewClientIdentityRepoFromClients(db.NewMemDB(), []client.Client{
client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),

View file

@ -11,6 +11,7 @@ import (
"github.com/jonboulle/clockwork"
"github.com/kylelemons/godebug/pretty"
"github.com/coreos/dex/client"
"github.com/coreos/dex/connector"
"github.com/coreos/dex/db"
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.Clock = clock
ci := oidc.ClientIdentity{
ci := client.Client{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: base64.URLEncoding.EncodeToString([]byte("secrete")),
@ -166,8 +167,9 @@ func makeTestFixtures() (*UsersAPI, *testEmailer) {
},
},
}
if _, err := db.NewClientIdentityRepoFromClients(dbMap, []oidc.ClientIdentity{ci}); err != nil {
panic("Failed to create client identity repo: " + err.Error())
if _, err := db.NewClientIdentityRepoFromClients(dbMap, []client.Client{ci}); err != nil {
panic("Failed to create client repo: " + err.Error())
}
// Used in TestRevokeRefreshToken test.