forked from mystiq/dex
client: add public client to data model
This commit is contained in:
parent
a530cc8d7c
commit
09e889e7bc
6 changed files with 92 additions and 9 deletions
|
@ -15,13 +15,26 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrorInvalidClientID = errors.New("not a valid client ID")
|
||||
ErrorInvalidRedirectURL = errors.New("not a valid redirect url for the given client")
|
||||
ErrorCantChooseRedirectURL = errors.New("must provide a redirect url; client has many")
|
||||
ErrorNoValidRedirectURLs = errors.New("no valid redirect URLs for this client.")
|
||||
ErrorNotFound = errors.New("no data found")
|
||||
ErrorInvalidClientID = errors.New("not a valid client ID")
|
||||
ErrorInvalidRedirectURL = errors.New("not a valid redirect url for the given client")
|
||||
ErrorCantChooseRedirectURL = errors.New("must provide a redirect url; client has many")
|
||||
ErrorNoValidRedirectURLs = errors.New("no valid redirect URLs for this client.")
|
||||
ErrorPublicClientRedirectURIs = errors.New("native clients cannot have redirect URIs")
|
||||
ErrorPublicClientMissingName = errors.New("native clients must have a name")
|
||||
|
||||
ErrorMissingRedirectURI = errors.New("no client redirect url given")
|
||||
|
||||
ErrorNotFound = errors.New("no data found")
|
||||
)
|
||||
|
||||
type ValidationError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (v ValidationError) Error() string {
|
||||
return v.Err.Error()
|
||||
}
|
||||
|
||||
const (
|
||||
bcryptHashCost = 10
|
||||
)
|
||||
|
@ -44,6 +57,7 @@ type Client struct {
|
|||
Credentials oidc.ClientCredentials
|
||||
Metadata oidc.ClientMetadata
|
||||
Admin bool
|
||||
Public bool
|
||||
}
|
||||
|
||||
type ClientRepo interface {
|
||||
|
@ -106,6 +120,7 @@ func ClientsFromReader(r io.Reader) ([]LoadableClient, error) {
|
|||
Secret string `json:"secret"`
|
||||
RedirectURLs []string `json:"redirectURLs"`
|
||||
Admin bool `json:"admin"`
|
||||
Public bool `json:"public"`
|
||||
TrustedPeers []string `json:"trustedPeers"`
|
||||
}
|
||||
if err := json.NewDecoder(r).Decode(&c); err != nil {
|
||||
|
@ -137,7 +152,8 @@ func ClientsFromReader(r io.Reader) ([]LoadableClient, error) {
|
|||
Metadata: oidc.ClientMetadata{
|
||||
RedirectURIs: redirectURIs,
|
||||
},
|
||||
Admin: client.Admin,
|
||||
Admin: client.Admin,
|
||||
Public: client.Public,
|
||||
},
|
||||
TrustedPeers: client.TrustedPeers,
|
||||
}
|
||||
|
|
|
@ -35,6 +35,13 @@ var (
|
|||
"trustedPeers":["goodClient1", "goodClient2"]
|
||||
}`
|
||||
|
||||
publicClient = `{
|
||||
"id": "public_client",
|
||||
"secret": "` + goodSecret3 + `",
|
||||
"redirectURLs": ["http://localhost:8080","urn:ietf:wg:oauth:2.0:oob"],
|
||||
"public": true
|
||||
}`
|
||||
|
||||
badURLClient = `{
|
||||
"id": "my_id",
|
||||
"secret": "` + goodSecret1 + `",
|
||||
|
@ -139,6 +146,26 @@ func TestClientsFromReader(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: "[" + publicClient + "]",
|
||||
want: []LoadableClient{
|
||||
{
|
||||
Client: Client{
|
||||
Credentials: oidc.ClientCredentials{
|
||||
ID: "public_client",
|
||||
Secret: goodSecret3,
|
||||
},
|
||||
Metadata: oidc.ClientMetadata{
|
||||
RedirectURIs: []url.URL{
|
||||
mustParseURL(t, "http://localhost:8080"),
|
||||
mustParseURL(t, "urn:ietf:wg:oauth:2.0:oob"),
|
||||
},
|
||||
},
|
||||
Public: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: "[" + badURLClient + "]",
|
||||
wantErr: true,
|
||||
|
|
33
db/client.go
33
db/client.go
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
||||
"github.com/coreos/go-oidc/oidc"
|
||||
|
@ -23,6 +24,10 @@ const (
|
|||
pgErrorCodeUniqueViolation = "23505" // unique_violation
|
||||
)
|
||||
|
||||
var (
|
||||
localHostRedirectURL = mustParseURL("http://localhost:0")
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(table{
|
||||
name: clientTableName,
|
||||
|
@ -44,6 +49,16 @@ func newClientModel(cli client.Client) (*clientModel, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cli.Public {
|
||||
// Metadata.Valid(), and therefore json.Unmarshal(metadata) complains
|
||||
// when there's no RedirectURIs, so we set them to a fixed value here,
|
||||
// and remove it when translating back to a client.Client
|
||||
cli.Metadata.RedirectURIs = []url.URL{
|
||||
localHostRedirectURL,
|
||||
}
|
||||
}
|
||||
|
||||
bmeta, err := json.Marshal(&cli.Metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -54,6 +69,7 @@ func newClientModel(cli client.Client) (*clientModel, error) {
|
|||
Secret: hashed,
|
||||
Metadata: string(bmeta),
|
||||
DexAdmin: cli.Admin,
|
||||
Public: cli.Public,
|
||||
}
|
||||
|
||||
return &cim, nil
|
||||
|
@ -64,6 +80,7 @@ type clientModel struct {
|
|||
Secret []byte `db:"secret"`
|
||||
Metadata string `db:"metadata"`
|
||||
DexAdmin bool `db:"dex_admin"`
|
||||
Public bool `db:"public"`
|
||||
}
|
||||
|
||||
type trustedPeerModel struct {
|
||||
|
@ -76,13 +93,18 @@ func (m *clientModel) Client() (*client.Client, error) {
|
|||
Credentials: oidc.ClientCredentials{
|
||||
ID: m.ID,
|
||||
},
|
||||
Admin: m.DexAdmin,
|
||||
Admin: m.DexAdmin,
|
||||
Public: m.Public,
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(m.Metadata), &ci.Metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ci.Public {
|
||||
ci.Metadata.RedirectURIs = []url.URL{}
|
||||
}
|
||||
|
||||
return &ci, nil
|
||||
}
|
||||
|
||||
|
@ -168,7 +190,6 @@ func isAlreadyExistsErr(err error) bool {
|
|||
|
||||
func (r *clientRepo) New(tx repo.Transaction, cli client.Client) (*oidc.ClientCredentials, error) {
|
||||
cim, err := newClientModel(cli)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -328,3 +349,11 @@ func (r *clientRepo) SetTrustedPeers(tx repo.Transaction, clientID string, clien
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mustParseURL(s string) url.URL {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return *u
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ CREATE TABLE client_identity (
|
|||
id text NOT NULL UNIQUE,
|
||||
secret blob,
|
||||
metadata text,
|
||||
dex_admin integer
|
||||
dex_admin integer,
|
||||
public integer
|
||||
);
|
||||
|
||||
CREATE TABLE connector_config (
|
||||
|
|
4
db/migrations/0013_add_public_clients.sql
Normal file
4
db/migrations/0013_add_public_clients.sql
Normal file
|
@ -0,0 +1,4 @@
|
|||
-- +migrate Up
|
||||
ALTER TABLE client_identity ADD COLUMN "public" boolean;
|
||||
|
||||
UPDATE "client_identity" SET "public" = false;
|
|
@ -78,6 +78,12 @@ var PostgresMigrations migrate.MigrationSource = &migrate.MemoryMigrationSource{
|
|||
"-- +migrate Up\nCREATE TABLE IF NOT EXISTS \"trusted_peers\" (\n \"client_id\" text not null,\n \"trusted_client_id\" text not null,\n primary key (\"client_id\", \"trusted_client_id\")) ;\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "0013_add_public_clients.sql",
|
||||
Up: []string{
|
||||
"-- +migrate Up\nALTER TABLE client_identity ADD COLUMN \"public\" boolean;\n\nUPDATE \"client_identity\" SET \"public\" = false;\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "0013_add_scopes_to_refresh_tokens.sql",
|
||||
Up: []string{
|
||||
|
|
Loading…
Reference in a new issue