Merge pull request #468 from bobbyrullo/remove_apis
Remove old client_resource api
This commit is contained in:
commit
ce7214657c
15 changed files with 10 additions and 1059 deletions
|
@ -1,71 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/connector"
|
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newAPIDriver(pcfg oidc.ProviderConfig, creds oidc.ClientCredentials) (driver, error) {
|
|
||||||
ccfg := oidc.ClientConfig{
|
|
||||||
ProviderConfig: pcfg,
|
|
||||||
Credentials: creds,
|
|
||||||
}
|
|
||||||
oc, err := oidc.NewClient(ccfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
trans := &oidc.AuthenticatedTransport{
|
|
||||||
TokenRefresher: &oidc.ClientCredsTokenRefresher{
|
|
||||||
Issuer: pcfg.Issuer.String(),
|
|
||||||
OIDCClient: oc,
|
|
||||||
},
|
|
||||||
RoundTripper: http.DefaultTransport,
|
|
||||||
}
|
|
||||||
hc := &http.Client{Transport: trans}
|
|
||||||
svc, err := schema.NewWithBasePath(hc, pcfg.Issuer.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &apiDriver{svc: svc}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiDriver struct {
|
|
||||||
svc *schema.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *apiDriver) NewClient(meta oidc.ClientMetadata) (*oidc.ClientCredentials, error) {
|
|
||||||
sc := &schema.Client{
|
|
||||||
RedirectURIs: make([]string, len(meta.RedirectURIs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, u := range meta.RedirectURIs {
|
|
||||||
sc.RedirectURIs[i] = u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
call := d.svc.Clients.Create(sc)
|
|
||||||
scs, err := call.Do()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
creds := &oidc.ClientCredentials{
|
|
||||||
ID: scs.Id,
|
|
||||||
Secret: scs.Secret,
|
|
||||||
}
|
|
||||||
|
|
||||||
return creds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *apiDriver) ConnectorConfigs() ([]connector.ConnectorConfig, error) {
|
|
||||||
return nil, errors.New("unable to get connector configs from HTTP API")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *apiDriver) SetConnectorConfigs(cfgs []connector.ConnectorConfig) error {
|
|
||||||
return errors.New("unable to set connector configs through HTTP API")
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -44,7 +43,6 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
global struct {
|
global struct {
|
||||||
endpoint string
|
|
||||||
creds oidc.ClientCredentials
|
creds oidc.ClientCredentials
|
||||||
dbURL string
|
dbURL string
|
||||||
help bool
|
help bool
|
||||||
|
@ -55,9 +53,6 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
log.EnableTimestamps()
|
log.EnableTimestamps()
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVar(&global.endpoint, "endpoint", "", "URL of dex API")
|
|
||||||
rootCmd.PersistentFlags().StringVar(&global.creds.ID, "client-id", "", "dex API user ID")
|
|
||||||
rootCmd.PersistentFlags().StringVar(&global.creds.Secret, "client-secret", "", "dex API user password")
|
|
||||||
rootCmd.PersistentFlags().StringVar(&global.dbURL, "db-url", "", "DSN-formatted database connection string")
|
rootCmd.PersistentFlags().StringVar(&global.dbURL, "db-url", "", "DSN-formatted database connection string")
|
||||||
rootCmd.PersistentFlags().BoolVar(&global.logDebug, "log-debug", false, "Log debug-level information")
|
rootCmd.PersistentFlags().BoolVar(&global.logDebug, "log-debug", false, "Log debug-level information")
|
||||||
}
|
}
|
||||||
|
@ -79,19 +74,8 @@ func getDriver() (drv driver) {
|
||||||
switch {
|
switch {
|
||||||
case len(global.dbURL) > 0:
|
case len(global.dbURL) > 0:
|
||||||
drv, err = newDBDriver(global.dbURL)
|
drv, err = newDBDriver(global.dbURL)
|
||||||
case len(global.endpoint) > 0:
|
|
||||||
if len(global.creds.ID) == 0 || len(global.creds.Secret) == 0 {
|
|
||||||
err = errors.New("--client-id/--client-secret flags unset")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pcfg, err := oidc.FetchProviderConfig(http.DefaultClient, global.endpoint)
|
|
||||||
if err != nil {
|
|
||||||
stderr("Unable to fetch provider config: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
drv, err = newAPIDriver(pcfg, global.creds)
|
|
||||||
default:
|
default:
|
||||||
err = errors.New("--endpoint/--db-url flags unset")
|
err = errors.New("--db-url flag unset")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
package integration
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"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 := client.Client{
|
|
||||||
// Credentials are for reference, they are actually generated by the client manager
|
|
||||||
Credentials: oidc.ClientCredentials{
|
|
||||||
ID: "authn.example.com",
|
|
||||||
Secret: base64.URLEncoding.EncodeToString([]byte("secret")),
|
|
||||||
},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: []url.URL{
|
|
||||||
{Scheme: "https://", Host: "authn.example.com", Path: "/callback"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cis := []client.LoadableClient{{Client: ci}}
|
|
||||||
|
|
||||||
srv, err := mockServer(cis)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error setting up server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oidcClient, err := mockClient(srv, ci)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error setting up OIDC client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tok, err := oidcClient.ClientCredsToken([]string{"openid"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed getting client token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackURL := "http://example.com/oidc/callback"
|
|
||||||
trans := &tokenHandlerTransport{
|
|
||||||
Handler: srv.HTTPHandler(),
|
|
||||||
Token: tok.Encode(),
|
|
||||||
}
|
|
||||||
hc := &http.Client{
|
|
||||||
Transport: trans,
|
|
||||||
}
|
|
||||||
iss := srv.IssuerURL.String()
|
|
||||||
svc, err := schema.NewWithBasePath(hc, iss)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed creating API service client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
newClientInput := &schema.Client{
|
|
||||||
RedirectURIs: []string{callbackURL, "http://example.com"},
|
|
||||||
}
|
|
||||||
|
|
||||||
call := svc.Clients.Create(newClientInput)
|
|
||||||
newClient, err := call.Do()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Call to create client API failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if newClient.Id == "" {
|
|
||||||
t.Error("Expected non-empty Client ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
if newClient.Secret == "" {
|
|
||||||
t.Error("Expected non-empty Client Secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := srv.ClientManager.Metadata(newClient.Id)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error looking up client metadata: %v", err)
|
|
||||||
} else if meta == nil {
|
|
||||||
t.Error("Expected new client to exist in repo")
|
|
||||||
}
|
|
||||||
|
|
||||||
gotURLs := make([]string, len(meta.RedirectURIs))
|
|
||||||
for i, u := range meta.RedirectURIs {
|
|
||||||
gotURLs[i] = u.String()
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(newClientInput.RedirectURIs, gotURLs) {
|
|
||||||
t.Errorf("Callback URL mismatch, want=%s, got=%s", newClientInput.RedirectURIs, gotURLs)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,7 +48,7 @@ func TestMapSchemaClientToClient(t *testing.T) {
|
||||||
Id: "123",
|
Id: "123",
|
||||||
Secret: "sec_123",
|
Secret: "sec_123",
|
||||||
RedirectURIs: []string{
|
RedirectURIs: []string{
|
||||||
"ht.d://p * * *",
|
"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package adminschema
|
package adminschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
|
|
@ -73,3 +73,5 @@ GOPATH=${PWD}/gopath ./bin/google-api-go-generator \
|
||||||
|
|
||||||
# Finally, fix the import in the bindings to refer to the vendored google-api package
|
# Finally, fix the import in the bindings to refer to the vendored google-api package
|
||||||
goimports -w ${GEN}
|
goimports -w ${GEN}
|
||||||
|
|
||||||
|
gofmt -w schema/${GOPKG}
|
||||||
|
|
|
@ -8,46 +8,6 @@ __Version:__ v1
|
||||||
## Models
|
## Models
|
||||||
|
|
||||||
|
|
||||||
### Client
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
id: string,
|
|
||||||
redirectURIs: [
|
|
||||||
string
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ClientPage
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
clients: [
|
|
||||||
Client
|
|
||||||
],
|
|
||||||
nextPageToken: string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ClientWithSecret
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
id: string,
|
|
||||||
redirectURIs: [
|
|
||||||
string
|
|
||||||
],
|
|
||||||
secret: string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Error
|
### Error
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,8 +192,8 @@ A client with associated public metadata.
|
||||||
|
|
||||||
> |Name|Located in|Description|Required|Type|
|
> |Name|Located in|Description|Required|Type|
|
||||||
|:-----|:-----|:-----|:-----|:-----|
|
|:-----|:-----|:-----|:-----|:-----|
|
||||||
| clientid | path | | Yes | string |
|
|
||||||
| userid | path | | Yes | string |
|
| userid | path | | Yes | string |
|
||||||
|
| clientid | path | | Yes | string |
|
||||||
|
|
||||||
|
|
||||||
> __Responses__
|
> __Responses__
|
||||||
|
@ -243,58 +203,6 @@ A client with associated public metadata.
|
||||||
| default | Unexpected error | |
|
| default | Unexpected error | |
|
||||||
|
|
||||||
|
|
||||||
### GET /clients
|
|
||||||
|
|
||||||
> __Summary__
|
|
||||||
|
|
||||||
> List Clients
|
|
||||||
|
|
||||||
> __Description__
|
|
||||||
|
|
||||||
> Retrieve a page of Client objects.
|
|
||||||
|
|
||||||
|
|
||||||
> __Parameters__
|
|
||||||
|
|
||||||
> |Name|Located in|Description|Required|Type|
|
|
||||||
|:-----|:-----|:-----|:-----|:-----|
|
|
||||||
| nextPageToken | query | | No | string |
|
|
||||||
|
|
||||||
|
|
||||||
> __Responses__
|
|
||||||
|
|
||||||
> |Code|Description|Type|
|
|
||||||
|:-----|:-----|:-----|
|
|
||||||
| 200 | | [ClientPage](#clientpage) |
|
|
||||||
| default | Unexpected error | |
|
|
||||||
|
|
||||||
|
|
||||||
### POST /clients
|
|
||||||
|
|
||||||
> __Summary__
|
|
||||||
|
|
||||||
> Create Clients
|
|
||||||
|
|
||||||
> __Description__
|
|
||||||
|
|
||||||
> Register a new Client.
|
|
||||||
|
|
||||||
|
|
||||||
> __Parameters__
|
|
||||||
|
|
||||||
> |Name|Located in|Description|Required|Type|
|
|
||||||
|:-----|:-----|:-----|:-----|:-----|
|
|
||||||
| | body | | Yes | [Client](#client) |
|
|
||||||
|
|
||||||
|
|
||||||
> __Responses__
|
|
||||||
|
|
||||||
> |Code|Description|Type|
|
|
||||||
|:-----|:-----|:-----|
|
|
||||||
| 200 | | [ClientWithSecret](#clientwithsecret) |
|
|
||||||
| default | Unexpected error | |
|
|
||||||
|
|
||||||
|
|
||||||
### GET /users
|
### GET /users
|
||||||
|
|
||||||
> __Summary__
|
> __Summary__
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
package workerschema
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/client"
|
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MapSchemaClientToClient(sc Client) (client.Client, error) {
|
|
||||||
ci := client.Client{
|
|
||||||
Credentials: oidc.ClientCredentials{
|
|
||||||
ID: sc.Id,
|
|
||||||
},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: make([]url.URL, len(sc.RedirectURIs)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, ru := range sc.RedirectURIs {
|
|
||||||
if ru == "" {
|
|
||||||
return client.Client{}, errors.New("redirect URL empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(ru)
|
|
||||||
if err != nil {
|
|
||||||
return client.Client{}, errors.New("redirect URL invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
ci.Metadata.RedirectURIs[i] = *u
|
|
||||||
}
|
|
||||||
|
|
||||||
return ci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapClientToSchemaClient(c client.Client) Client {
|
|
||||||
cl := Client{
|
|
||||||
Id: c.Credentials.ID,
|
|
||||||
RedirectURIs: make([]string, len(c.Metadata.RedirectURIs)),
|
|
||||||
}
|
|
||||||
for i, u := range c.Metadata.RedirectURIs {
|
|
||||||
cl.RedirectURIs[i] = u.String()
|
|
||||||
}
|
|
||||||
return cl
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapClientToSchemaClientWithSecret(c client.Client) ClientWithSecret {
|
|
||||||
cl := ClientWithSecret{
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
return cl
|
|
||||||
}
|
|
|
@ -45,7 +45,6 @@ func New(client *http.Client) (*Service, error) {
|
||||||
return nil, errors.New("client is nil")
|
return nil, errors.New("client is nil")
|
||||||
}
|
}
|
||||||
s := &Service{client: client, BasePath: basePath}
|
s := &Service{client: client, BasePath: basePath}
|
||||||
s.Clients = NewClientsService(s)
|
|
||||||
s.RefreshClient = NewRefreshClientService(s)
|
s.RefreshClient = NewRefreshClientService(s)
|
||||||
s.Users = NewUsersService(s)
|
s.Users = NewUsersService(s)
|
||||||
return s, nil
|
return s, nil
|
||||||
|
@ -55,22 +54,11 @@ type Service struct {
|
||||||
client *http.Client
|
client *http.Client
|
||||||
BasePath string // API endpoint base URL
|
BasePath string // API endpoint base URL
|
||||||
|
|
||||||
Clients *ClientsService
|
|
||||||
|
|
||||||
RefreshClient *RefreshClientService
|
RefreshClient *RefreshClientService
|
||||||
|
|
||||||
Users *UsersService
|
Users *UsersService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientsService(s *Service) *ClientsService {
|
|
||||||
rs := &ClientsService{s: s}
|
|
||||||
return rs
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientsService struct {
|
|
||||||
s *Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRefreshClientService(s *Service) *RefreshClientService {
|
func NewRefreshClientService(s *Service) *RefreshClientService {
|
||||||
rs := &RefreshClientService{s: s}
|
rs := &RefreshClientService{s: s}
|
||||||
return rs
|
return rs
|
||||||
|
@ -89,26 +77,6 @@ type UsersService struct {
|
||||||
s *Service
|
s *Service
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Id string `json:"id,omitempty"`
|
|
||||||
|
|
||||||
RedirectURIs []string `json:"redirectURIs,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientPage struct {
|
|
||||||
Clients []*Client `json:"clients,omitempty"`
|
|
||||||
|
|
||||||
NextPageToken string `json:"nextPageToken,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientWithSecret struct {
|
|
||||||
Id string `json:"id,omitempty"`
|
|
||||||
|
|
||||||
RedirectURIs []string `json:"redirectURIs,omitempty"`
|
|
||||||
|
|
||||||
Secret string `json:"secret,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
|
|
||||||
|
@ -192,148 +160,6 @@ type UsersResponse struct {
|
||||||
Users []*User `json:"users,omitempty"`
|
Users []*User `json:"users,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// method id "dex.Client.Create":
|
|
||||||
|
|
||||||
type ClientsCreateCall struct {
|
|
||||||
s *Service
|
|
||||||
client *Client
|
|
||||||
opt_ map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create: Register a new Client.
|
|
||||||
func (r *ClientsService) Create(client *Client) *ClientsCreateCall {
|
|
||||||
c := &ClientsCreateCall{s: r.s, opt_: make(map[string]interface{})}
|
|
||||||
c.client = client
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fields allows partial responses to be retrieved.
|
|
||||||
// See https://developers.google.com/gdata/docs/2.0/basics#PartialResponse
|
|
||||||
// for more information.
|
|
||||||
func (c *ClientsCreateCall) Fields(s ...googleapi.Field) *ClientsCreateCall {
|
|
||||||
c.opt_["fields"] = googleapi.CombineFields(s)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ClientsCreateCall) Do() (*ClientWithSecret, error) {
|
|
||||||
var body io.Reader = nil
|
|
||||||
body, err := googleapi.WithoutDataWrapper.JSONReader(c.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ctype := "application/json"
|
|
||||||
params := make(url.Values)
|
|
||||||
params.Set("alt", "json")
|
|
||||||
if v, ok := c.opt_["fields"]; ok {
|
|
||||||
params.Set("fields", fmt.Sprintf("%v", v))
|
|
||||||
}
|
|
||||||
urls := googleapi.ResolveRelative(c.s.BasePath, "clients")
|
|
||||||
urls += "?" + params.Encode()
|
|
||||||
req, _ := http.NewRequest("POST", urls, body)
|
|
||||||
googleapi.SetOpaque(req.URL)
|
|
||||||
req.Header.Set("Content-Type", ctype)
|
|
||||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
|
||||||
res, err := c.s.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer googleapi.CloseBody(res)
|
|
||||||
if err := googleapi.CheckResponse(res); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var ret *ClientWithSecret
|
|
||||||
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
// {
|
|
||||||
// "description": "Register a new Client.",
|
|
||||||
// "httpMethod": "POST",
|
|
||||||
// "id": "dex.Client.Create",
|
|
||||||
// "path": "clients",
|
|
||||||
// "request": {
|
|
||||||
// "$ref": "Client"
|
|
||||||
// },
|
|
||||||
// "response": {
|
|
||||||
// "$ref": "ClientWithSecret"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// method id "dex.Client.List":
|
|
||||||
|
|
||||||
type ClientsListCall struct {
|
|
||||||
s *Service
|
|
||||||
opt_ map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// List: Retrieve a page of Client objects.
|
|
||||||
func (r *ClientsService) List() *ClientsListCall {
|
|
||||||
c := &ClientsListCall{s: r.s, opt_: make(map[string]interface{})}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextPageToken sets the optional parameter "nextPageToken":
|
|
||||||
func (c *ClientsListCall) NextPageToken(nextPageToken string) *ClientsListCall {
|
|
||||||
c.opt_["nextPageToken"] = nextPageToken
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fields allows partial responses to be retrieved.
|
|
||||||
// See https://developers.google.com/gdata/docs/2.0/basics#PartialResponse
|
|
||||||
// for more information.
|
|
||||||
func (c *ClientsListCall) Fields(s ...googleapi.Field) *ClientsListCall {
|
|
||||||
c.opt_["fields"] = googleapi.CombineFields(s)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ClientsListCall) Do() (*ClientPage, error) {
|
|
||||||
var body io.Reader = nil
|
|
||||||
params := make(url.Values)
|
|
||||||
params.Set("alt", "json")
|
|
||||||
if v, ok := c.opt_["nextPageToken"]; ok {
|
|
||||||
params.Set("nextPageToken", fmt.Sprintf("%v", v))
|
|
||||||
}
|
|
||||||
if v, ok := c.opt_["fields"]; ok {
|
|
||||||
params.Set("fields", fmt.Sprintf("%v", v))
|
|
||||||
}
|
|
||||||
urls := googleapi.ResolveRelative(c.s.BasePath, "clients")
|
|
||||||
urls += "?" + params.Encode()
|
|
||||||
req, _ := http.NewRequest("GET", urls, body)
|
|
||||||
googleapi.SetOpaque(req.URL)
|
|
||||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
|
||||||
res, err := c.s.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer googleapi.CloseBody(res)
|
|
||||||
if err := googleapi.CheckResponse(res); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var ret *ClientPage
|
|
||||||
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
// {
|
|
||||||
// "description": "Retrieve a page of Client objects.",
|
|
||||||
// "httpMethod": "GET",
|
|
||||||
// "id": "dex.Client.List",
|
|
||||||
// "parameters": {
|
|
||||||
// "nextPageToken": {
|
|
||||||
// "location": "query",
|
|
||||||
// "type": "string"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "path": "clients",
|
|
||||||
// "response": {
|
|
||||||
// "$ref": "ClientPage"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// method id "dex.RefreshClient.List":
|
// method id "dex.RefreshClient.List":
|
||||||
|
|
||||||
type RefreshClientListCall struct {
|
type RefreshClientListCall struct {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package workerschema
|
package workerschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
@ -39,22 +40,6 @@ const DiscoveryJSON = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Client": {
|
|
||||||
"id": "Client",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"redirectURIs": {
|
|
||||||
"required": true,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RefreshClient": {
|
"RefreshClient": {
|
||||||
"id": "Client",
|
"id": "Client",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -86,40 +71,6 @@ const DiscoveryJSON = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ClientWithSecret": {
|
|
||||||
"id": "Client",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"secret": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"redirectURIs": {
|
|
||||||
"required": true,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ClientPage": {
|
|
||||||
"id": "ClientPage",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"clients": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "Client"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nextPageToken": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"User": {
|
"User": {
|
||||||
"id": "User",
|
"id": "User",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -244,37 +195,6 @@ const DiscoveryJSON = `{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"Clients": {
|
|
||||||
"methods": {
|
|
||||||
"List": {
|
|
||||||
"id": "dex.Client.List",
|
|
||||||
"description": "Retrieve a page of Client objects.",
|
|
||||||
"httpMethod": "GET",
|
|
||||||
"path": "clients",
|
|
||||||
"parameters": {
|
|
||||||
"nextPageToken": {
|
|
||||||
"type": "string",
|
|
||||||
"location": "query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"$ref": "ClientPage"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Create": {
|
|
||||||
"id": "dex.Client.Create",
|
|
||||||
"description": "Register a new Client.",
|
|
||||||
"httpMethod": "POST",
|
|
||||||
"path": "clients",
|
|
||||||
"request": {
|
|
||||||
"$ref": "Client"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"$ref": "ClientWithSecret"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Users": {
|
"Users": {
|
||||||
"methods": {
|
"methods": {
|
||||||
"List": {
|
"List": {
|
||||||
|
|
|
@ -33,22 +33,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Client": {
|
|
||||||
"id": "Client",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"redirectURIs": {
|
|
||||||
"required": true,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RefreshClient": {
|
"RefreshClient": {
|
||||||
"id": "Client",
|
"id": "Client",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -80,40 +64,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ClientWithSecret": {
|
|
||||||
"id": "Client",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"secret": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"redirectURIs": {
|
|
||||||
"required": true,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ClientPage": {
|
|
||||||
"id": "ClientPage",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"clients": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "Client"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nextPageToken": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"User": {
|
"User": {
|
||||||
"id": "User",
|
"id": "User",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -238,37 +188,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"Clients": {
|
|
||||||
"methods": {
|
|
||||||
"List": {
|
|
||||||
"id": "dex.Client.List",
|
|
||||||
"description": "Retrieve a page of Client objects.",
|
|
||||||
"httpMethod": "GET",
|
|
||||||
"path": "clients",
|
|
||||||
"parameters": {
|
|
||||||
"nextPageToken": {
|
|
||||||
"type": "string",
|
|
||||||
"location": "query"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"$ref": "ClientPage"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Create": {
|
|
||||||
"id": "dex.Client.Create",
|
|
||||||
"description": "Register a new Client.",
|
|
||||||
"httpMethod": "POST",
|
|
||||||
"path": "clients",
|
|
||||||
"request": {
|
|
||||||
"$ref": "Client"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"$ref": "ClientWithSecret"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Users": {
|
"Users": {
|
||||||
"methods": {
|
"methods": {
|
||||||
"List": {
|
"List": {
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/client/manager"
|
|
||||||
phttp "github.com/coreos/dex/pkg/http"
|
|
||||||
"github.com/coreos/dex/pkg/log"
|
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clientResource struct {
|
|
||||||
manager *manager.ClientManager
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerClientResource(prefix string, manager *manager.ClientManager) (string, http.Handler) {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
c := &clientResource{
|
|
||||||
manager: manager,
|
|
||||||
}
|
|
||||||
relPath := "clients"
|
|
||||||
absPath := path.Join(prefix, relPath)
|
|
||||||
mux.Handle(absPath, c)
|
|
||||||
return relPath, mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *clientResource) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.Method {
|
|
||||||
case "GET":
|
|
||||||
c.list(w, r)
|
|
||||||
case "POST":
|
|
||||||
c.create(w, r)
|
|
||||||
default:
|
|
||||||
msg := fmt.Sprintf("HTTP %s method not supported for this resource", r.Method)
|
|
||||||
writeAPIError(w, http.StatusMethodNotAllowed, newAPIError(errorInvalidRequest, msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *clientResource) list(w http.ResponseWriter, r *http.Request) {
|
|
||||||
cs, err := c.manager.All()
|
|
||||||
if err != nil {
|
|
||||||
writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "error listing clients"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
scs := make([]*schema.Client, len(cs))
|
|
||||||
for i, ci := range cs {
|
|
||||||
sc := schema.MapClientToSchemaClient(ci)
|
|
||||||
scs[i] = &sc
|
|
||||||
}
|
|
||||||
|
|
||||||
page := schema.ClientPage{
|
|
||||||
Clients: scs,
|
|
||||||
}
|
|
||||||
writeResponseWithBody(w, http.StatusOK, page)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ct := r.Header.Get("content-type")
|
|
||||||
if ct != "application/json" {
|
|
||||||
log.Debugf("Unsupported request content-type: %v", ct)
|
|
||||||
writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unsupported content-type"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var sc schema.Client
|
|
||||||
dec := json.NewDecoder(r.Body)
|
|
||||||
err := dec.Decode(&sc)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("Error decoding request body: %v", err)
|
|
||||||
writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unable to decode request body"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ci.Metadata.Valid(); err != nil {
|
|
||||||
log.Debugf("ClientMetadata invalid: %v", err)
|
|
||||||
writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
creds, err := c.manager.New(ci, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed creating client: %v", err)
|
|
||||||
writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to create client"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ci.Credentials = *creds
|
|
||||||
|
|
||||||
ssc := schema.MapClientToSchemaClientWithSecret(ci)
|
|
||||||
w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
|
|
||||||
writeResponseWithBody(w, http.StatusCreated, ssc)
|
|
||||||
}
|
|
|
@ -1,284 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/client"
|
|
||||||
"github.com/coreos/dex/client/manager"
|
|
||||||
"github.com/coreos/dex/db"
|
|
||||||
schema "github.com/coreos/dex/schema/workerschema"
|
|
||||||
"github.com/coreos/go-oidc/oidc"
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeBody(s string) io.ReadCloser {
|
|
||||||
return ioutil.NopCloser(strings.NewReader(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateInvalidRequest(t *testing.T) {
|
|
||||||
u := &url.URL{Scheme: "http", Host: "example.com", Path: "clients"}
|
|
||||||
h := http.Header{"Content-Type": []string{"application/json"}}
|
|
||||||
dbm := db.NewMemDB()
|
|
||||||
repo := db.NewClientRepo(dbm)
|
|
||||||
manager := manager.NewClientManager(repo, db.TransactionFactory(dbm), manager.ManagerOptions{})
|
|
||||||
res := &clientResource{manager: manager}
|
|
||||||
tests := []struct {
|
|
||||||
req *http.Request
|
|
||||||
wantCode int
|
|
||||||
wantBody string
|
|
||||||
}{
|
|
||||||
// invalid content-type
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: http.Header{"Content-Type": []string{"application/xml"}}},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"unsupported content-type"}`,
|
|
||||||
},
|
|
||||||
// invalid method
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "DELETE", URL: u, Header: h},
|
|
||||||
wantCode: http.StatusMethodNotAllowed,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"HTTP DELETE method not supported for this resource"}`,
|
|
||||||
},
|
|
||||||
// invalid method
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "PUT", URL: u, Header: h},
|
|
||||||
wantCode: http.StatusMethodNotAllowed,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"HTTP PUT method not supported for this resource"}`,
|
|
||||||
},
|
|
||||||
// invalid method
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "HEAD", URL: u, Header: h},
|
|
||||||
wantCode: http.StatusMethodNotAllowed,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"HTTP HEAD method not supported for this resource"}`,
|
|
||||||
},
|
|
||||||
// unserializable body
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody("asdf")},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"unable to decode request body"}`,
|
|
||||||
},
|
|
||||||
// empty body
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody("")},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_request","error_description":"unable to decode request body"}`,
|
|
||||||
},
|
|
||||||
// missing url field
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody(`{"id":"foo"}`)},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_client_metadata","error_description":"zero redirect URLs"}`,
|
|
||||||
},
|
|
||||||
// empty url array
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody(`{"redirectURIs":[]}`)},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_client_metadata","error_description":"zero redirect URLs"}`,
|
|
||||||
},
|
|
||||||
// array with empty string
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody(`{"redirectURIs":[""]}`)},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_client_metadata","error_description":"missing or invalid field: redirectURIs"}`,
|
|
||||||
},
|
|
||||||
// uri with unusable scheme
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody(`{"redirectURIs":["asdf.com"]}`)},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_client_metadata","error_description":"no host for uri field redirect_uris"}`,
|
|
||||||
},
|
|
||||||
// uri missing host
|
|
||||||
{
|
|
||||||
req: &http.Request{Method: "POST", URL: u, Header: h, Body: makeBody(`{"redirectURIs":["http://"]}`)},
|
|
||||||
wantCode: http.StatusBadRequest,
|
|
||||||
wantBody: `{"error":"invalid_client_metadata","error_description":"no host for uri field redirect_uris"}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
res.ServeHTTP(w, tt.req)
|
|
||||||
|
|
||||||
if w.Code != tt.wantCode {
|
|
||||||
t.Errorf("case %d: invalid response code, want=%d, got=%d", i, tt.wantCode, w.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
gotBody := w.Body.String()
|
|
||||||
if gotBody != tt.wantBody {
|
|
||||||
t.Errorf("case %d: invalid response body, want=%s, got=%s", i, tt.wantBody, gotBody)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
|
||||||
dbm := db.NewMemDB()
|
|
||||||
repo := db.NewClientRepo(dbm)
|
|
||||||
manager := manager.NewClientManager(repo, db.TransactionFactory(dbm), manager.ManagerOptions{})
|
|
||||||
res := &clientResource{manager: manager}
|
|
||||||
tests := [][]string{
|
|
||||||
[]string{"http://example.com"},
|
|
||||||
[]string{"https://example.com"},
|
|
||||||
[]string{"http://example.com/foo"},
|
|
||||||
[]string{"http://example.com/bar", "http://example.com/foo"},
|
|
||||||
}
|
|
||||||
endpoint := "http://example.com/clients"
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
body := strings.NewReader(fmt.Sprintf(`{"redirectURIs":["%s"]}`, strings.Join(tt, `","`)))
|
|
||||||
r, err := http.NewRequest("POST", endpoint, body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed creating http.Request: %v", err)
|
|
||||||
}
|
|
||||||
r.Header.Set("content-type", "application/json")
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
res.ServeHTTP(w, r)
|
|
||||||
|
|
||||||
if w.Code != http.StatusCreated {
|
|
||||||
t.Errorf("case %d: invalid response code, want=%d, got=%d", i, http.StatusCreated, w.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
var client schema.ClientWithSecret
|
|
||||||
if err := json.Unmarshal(w.Body.Bytes(), &client); err != nil {
|
|
||||||
t.Errorf("case %d: unexpected error=%v", i, err)
|
|
||||||
}
|
|
||||||
if len(client.RedirectURIs) != len(tt) {
|
|
||||||
t.Errorf("case %d: unexpected number of redirect URIs, want=%d, got=%d", i, len(tt), len(client.RedirectURIs))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tt, client.RedirectURIs) {
|
|
||||||
t.Errorf("case %d: unexpected client redirect URIs: want=%v got=%v", i, tt, client.RedirectURIs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.Id == "" {
|
|
||||||
t.Errorf("case %d: empty client ID in response", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.Secret == "" {
|
|
||||||
t.Errorf("case %d: empty client secret in response", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
wantLoc := fmt.Sprintf("%s/%s", endpoint, client.Id)
|
|
||||||
gotLoc := w.Header().Get("Location")
|
|
||||||
if gotLoc != wantLoc {
|
|
||||||
t.Errorf("case %d: invalid location header, want=%v, got=%v", i, wantLoc, gotLoc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestList(t *testing.T) {
|
|
||||||
|
|
||||||
b64Encode := func(s string) string {
|
|
||||||
return base64.URLEncoding.EncodeToString([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
cs []client.Client
|
|
||||||
want []*schema.Client
|
|
||||||
}{
|
|
||||||
// empty repo
|
|
||||||
{
|
|
||||||
cs: []client.Client{},
|
|
||||||
want: nil,
|
|
||||||
},
|
|
||||||
// single client
|
|
||||||
{
|
|
||||||
cs: []client.Client{
|
|
||||||
client.Client{
|
|
||||||
Credentials: oidc.ClientCredentials{ID: "example.com", Secret: b64Encode("secret")},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: []url.URL{
|
|
||||||
url.URL{Scheme: "http", Host: "example.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: []*schema.Client{
|
|
||||||
&schema.Client{
|
|
||||||
Id: "example.com",
|
|
||||||
RedirectURIs: []string{"http://example.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// multi client
|
|
||||||
{
|
|
||||||
cs: []client.Client{
|
|
||||||
client.Client{
|
|
||||||
Credentials: oidc.ClientCredentials{ID: "example.com", Secret: b64Encode("secret")},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: []url.URL{
|
|
||||||
url.URL{Scheme: "http", Host: "example.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
client.Client{
|
|
||||||
Credentials: oidc.ClientCredentials{ID: "example2.com", Secret: b64Encode("secret")},
|
|
||||||
Metadata: oidc.ClientMetadata{
|
|
||||||
RedirectURIs: []url.URL{
|
|
||||||
url.URL{Scheme: "https", Host: "example2.com", Path: "one/two/three"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: []*schema.Client{
|
|
||||||
&schema.Client{
|
|
||||||
Id: "example2.com",
|
|
||||||
RedirectURIs: []string{"https://example2.com/one/two/three"},
|
|
||||||
},
|
|
||||||
&schema.Client{
|
|
||||||
Id: "example.com",
|
|
||||||
RedirectURIs: []string{"http://example.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
f, err := makeTestFixturesWithOptions(testFixtureOptions{
|
|
||||||
clients: clientsToLoadableClients(tt.cs),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error making test fixtures: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res := &clientResource{manager: f.clientManager}
|
|
||||||
|
|
||||||
r, err := http.NewRequest("GET", "http://example.com/clients", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed creating http.Request: %v", err)
|
|
||||||
}
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
res.ServeHTTP(w, r)
|
|
||||||
|
|
||||||
if w.Code != http.StatusOK {
|
|
||||||
t.Errorf("case %d: invalid response code, want=%d, got=%d", i, http.StatusOK, w.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resp schema.ClientPage
|
|
||||||
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
||||||
t.Errorf("case %d: unexpected error=%v", i, err)
|
|
||||||
}
|
|
||||||
sort.Sort(byClientId(tt.want))
|
|
||||||
sort.Sort(byClientId(resp.Clients))
|
|
||||||
|
|
||||||
if diff := pretty.Compare(tt.want, resp.Clients); diff != "" {
|
|
||||||
t.Errorf("case %d: invalid response body: %s", i, diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type byClientId []*schema.Client
|
|
||||||
|
|
||||||
func (b byClientId) Len() int { return len(b) }
|
|
||||||
func (b byClientId) Less(i, j int) bool { return b[i].Id < b[j].Id }
|
|
||||||
func (b byClientId) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
|
|
@ -265,9 +265,6 @@ 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.ClientManager)
|
|
||||||
mux.Handle(path.Join(apiBasePath, clientPath), s.NewClientTokenAuthHandler(clientHandler))
|
|
||||||
|
|
||||||
usersAPI := usersapi.NewUsersAPI(s.UserManager, s.ClientManager, s.RefreshTokenRepo, s.UserEmailer, s.localConnectorID)
|
usersAPI := usersapi.NewUsersAPI(s.UserManager, s.ClientManager, s.RefreshTokenRepo, s.UserEmailer, s.localConnectorID)
|
||||||
handler := NewUserMgmtServer(usersAPI, s.JWTVerifierFactory(), s.UserManager, s.ClientManager).HTTPHandler()
|
handler := NewUserMgmtServer(usersAPI, s.JWTVerifierFactory(), s.UserManager, s.ClientManager).HTTPHandler()
|
||||||
|
|
||||||
|
|
2
test
2
test
|
@ -18,7 +18,7 @@ if [ ! -d $GOPATH/pkg ]; then
|
||||||
echo "WARNING: No cached builds detected. Please run the ./build script to speed up future tests."
|
echo "WARNING: No cached builds detected. Please run the ./build script to speed up future tests."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TESTABLE="admin client client/manager connector db email functional/repo integration pkg/crypto pkg/flag pkg/http pkg/time pkg/html server session session/manager user user/api user/manager user/email"
|
TESTABLE="admin client client/manager connector db email functional/repo integration pkg/crypto pkg/flag pkg/http pkg/time pkg/html schema/adminschema server session session/manager user user/api user/manager user/email"
|
||||||
FORMATTABLE="$TESTABLE cmd/dexctl cmd/dex-worker cmd/dex-overlord examples/app functional pkg/log"
|
FORMATTABLE="$TESTABLE cmd/dexctl cmd/dex-worker cmd/dex-overlord examples/app functional pkg/log"
|
||||||
|
|
||||||
# user has not provided PKG override
|
# user has not provided PKG override
|
||||||
|
|
Reference in a new issue