Merge pull request #449 from ericchiang/add-connectors-to-api
Set and list connectors from admin API
This commit is contained in:
commit
4440b3a085
15 changed files with 889 additions and 311 deletions
13
admin/api.go
13
admin/api.go
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/dex/client"
|
"github.com/coreos/dex/client"
|
||||||
clientmanager "github.com/coreos/dex/client/manager"
|
clientmanager "github.com/coreos/dex/client/manager"
|
||||||
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/schema/adminschema"
|
"github.com/coreos/dex/schema/adminschema"
|
||||||
"github.com/coreos/dex/user"
|
"github.com/coreos/dex/user"
|
||||||
usermanager "github.com/coreos/dex/user/manager"
|
usermanager "github.com/coreos/dex/user/manager"
|
||||||
|
@ -16,12 +17,13 @@ type AdminAPI struct {
|
||||||
userManager *usermanager.UserManager
|
userManager *usermanager.UserManager
|
||||||
userRepo user.UserRepo
|
userRepo user.UserRepo
|
||||||
passwordInfoRepo user.PasswordInfoRepo
|
passwordInfoRepo user.PasswordInfoRepo
|
||||||
|
connectorConfigRepo connector.ConnectorConfigRepo
|
||||||
clientRepo client.ClientRepo
|
clientRepo client.ClientRepo
|
||||||
clientManager *clientmanager.ClientManager
|
clientManager *clientmanager.ClientManager
|
||||||
localConnectorID string
|
localConnectorID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAdminAPI(userRepo user.UserRepo, pwiRepo user.PasswordInfoRepo, clientRepo client.ClientRepo, userManager *usermanager.UserManager, clientManager *clientmanager.ClientManager, localConnectorID string) *AdminAPI {
|
func NewAdminAPI(userRepo user.UserRepo, pwiRepo user.PasswordInfoRepo, clientRepo client.ClientRepo, connectorConfigRepo connector.ConnectorConfigRepo, userManager *usermanager.UserManager, clientManager *clientmanager.ClientManager, localConnectorID string) *AdminAPI {
|
||||||
if localConnectorID == "" {
|
if localConnectorID == "" {
|
||||||
panic("must specify non-blank localConnectorID")
|
panic("must specify non-blank localConnectorID")
|
||||||
}
|
}
|
||||||
|
@ -31,6 +33,7 @@ func NewAdminAPI(userRepo user.UserRepo, pwiRepo user.PasswordInfoRepo, clientRe
|
||||||
passwordInfoRepo: pwiRepo,
|
passwordInfoRepo: pwiRepo,
|
||||||
clientRepo: clientRepo,
|
clientRepo: clientRepo,
|
||||||
clientManager: clientManager,
|
clientManager: clientManager,
|
||||||
|
connectorConfigRepo: connectorConfigRepo,
|
||||||
localConnectorID: localConnectorID,
|
localConnectorID: localConnectorID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +153,14 @@ func (a *AdminAPI) CreateClient(req adminschema.ClientCreateRequest) (adminschem
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AdminAPI) SetConnectors(connectorConfigs []connector.ConnectorConfig) error {
|
||||||
|
return a.connectorConfigRepo.Set(connectorConfigs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AdminAPI) GetConnectors() ([]connector.ConnectorConfig, error) {
|
||||||
|
return a.connectorConfigRepo.All()
|
||||||
|
}
|
||||||
|
|
||||||
func mapError(e error) error {
|
func mapError(e error) error {
|
||||||
if mapped, ok := errorMap[e]; ok {
|
if mapped, ok := errorMap[e]; ok {
|
||||||
return mapped(e)
|
return mapped(e)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
type testFixtures struct {
|
type testFixtures struct {
|
||||||
ur user.UserRepo
|
ur user.UserRepo
|
||||||
pwr user.PasswordInfoRepo
|
pwr user.PasswordInfoRepo
|
||||||
|
ccr connector.ConnectorConfigRepo
|
||||||
cr client.ClientRepo
|
cr client.ClientRepo
|
||||||
cm *clientmanager.ClientManager
|
cm *clientmanager.ClientManager
|
||||||
mgr *manager.UserManager
|
mgr *manager.UserManager
|
||||||
|
@ -63,7 +64,7 @@ func makeTestFixtures() *testFixtures {
|
||||||
return repo
|
return repo
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ccr := func() connector.ConnectorConfigRepo {
|
f.ccr = func() connector.ConnectorConfigRepo {
|
||||||
c := []connector.ConnectorConfig{&connector.LocalConnectorConfig{ID: "local"}}
|
c := []connector.ConnectorConfig{&connector.LocalConnectorConfig{ID: "local"}}
|
||||||
repo := db.NewConnectorConfigRepo(dbMap)
|
repo := db.NewConnectorConfigRepo(dbMap)
|
||||||
if err := repo.Set(c); err != nil {
|
if err := repo.Set(c); err != nil {
|
||||||
|
@ -72,9 +73,9 @@ func makeTestFixtures() *testFixtures {
|
||||||
return repo
|
return repo
|
||||||
}()
|
}()
|
||||||
|
|
||||||
f.mgr = manager.NewUserManager(f.ur, f.pwr, ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
f.mgr = manager.NewUserManager(f.ur, f.pwr, f.ccr, db.TransactionFactory(dbMap), manager.ManagerOptions{})
|
||||||
f.cm = clientmanager.NewClientManager(f.cr, db.TransactionFactory(dbMap), clientmanager.ManagerOptions{})
|
f.cm = clientmanager.NewClientManager(f.cr, db.TransactionFactory(dbMap), clientmanager.ManagerOptions{})
|
||||||
f.adAPI = NewAdminAPI(f.ur, f.pwr, f.cr, f.mgr, f.cm, "local")
|
f.adAPI = NewAdminAPI(f.ur, f.pwr, f.cr, f.ccr, f.mgr, f.cm, "local")
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
@ -252,3 +253,51 @@ func TestGetState(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetConnectors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
connectors []connector.ConnectorConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
connectors: []connector.ConnectorConfig{
|
||||||
|
&connector.GitHubConnectorConfig{
|
||||||
|
ID: "github",
|
||||||
|
ClientID: "foo",
|
||||||
|
ClientSecret: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
connectors: []connector.ConnectorConfig{
|
||||||
|
&connector.GitHubConnectorConfig{
|
||||||
|
ID: "github",
|
||||||
|
ClientID: "foo",
|
||||||
|
ClientSecret: "bar",
|
||||||
|
},
|
||||||
|
&connector.LocalConnectorConfig{
|
||||||
|
ID: "local",
|
||||||
|
},
|
||||||
|
&connector.BitbucketConnectorConfig{
|
||||||
|
ID: "bitbucket",
|
||||||
|
ClientID: "foo",
|
||||||
|
ClientSecret: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
f := makeTestFixtures()
|
||||||
|
if err := f.adAPI.SetConnectors(tt.connectors); err != nil {
|
||||||
|
t.Errorf("case %d: failed to set connectors: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
got, err := f.adAPI.GetConnectors()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: failed to get connectors: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tt.connectors, got); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got) = %v", i, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -121,8 +121,9 @@ func main() {
|
||||||
userManager := manager.NewUserManager(userRepo,
|
userManager := manager.NewUserManager(userRepo,
|
||||||
pwiRepo, connCfgRepo, db.TransactionFactory(dbc), manager.ManagerOptions{})
|
pwiRepo, connCfgRepo, db.TransactionFactory(dbc), manager.ManagerOptions{})
|
||||||
clientManager := clientmanager.NewClientManager(clientRepo, db.TransactionFactory(dbc), clientmanager.ManagerOptions{})
|
clientManager := clientmanager.NewClientManager(clientRepo, db.TransactionFactory(dbc), clientmanager.ManagerOptions{})
|
||||||
|
connectorConfigRepo := db.NewConnectorConfigRepo(dbc)
|
||||||
|
|
||||||
adminAPI := admin.NewAdminAPI(userRepo, pwiRepo, clientRepo, userManager, clientManager, *localConnectorID)
|
adminAPI := admin.NewAdminAPI(userRepo, pwiRepo, clientRepo, connectorConfigRepo, userManager, clientManager, *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())
|
||||||
|
|
|
@ -63,6 +63,7 @@ type ConnectorConfig interface {
|
||||||
type ConnectorConfigRepo interface {
|
type ConnectorConfigRepo interface {
|
||||||
All() ([]ConnectorConfig, error)
|
All() ([]ConnectorConfig, error)
|
||||||
GetConnectorByID(repo.Transaction, string) (ConnectorConfig, error)
|
GetConnectorByID(repo.Transaction, string) (ConnectorConfig, error)
|
||||||
|
Set(cfgs []ConnectorConfig) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type IdentityProvider interface {
|
type IdentityProvider interface {
|
||||||
|
|
|
@ -93,11 +93,12 @@ func makeAdminAPITestFixtures() *adminAPITestFixtures {
|
||||||
return fmt.Sprintf("client_%v", hostport), nil
|
return fmt.Sprintf("client_%v", hostport), nil
|
||||||
}
|
}
|
||||||
cm := manager.NewClientManager(cr, db.TransactionFactory(dbMap), manager.ManagerOptions{SecretGenerator: secGen, ClientIDGenerator: clientIDGenerator})
|
cm := manager.NewClientManager(cr, db.TransactionFactory(dbMap), manager.ManagerOptions{SecretGenerator: secGen, ClientIDGenerator: clientIDGenerator})
|
||||||
|
ccr := db.NewConnectorConfigRepo(dbMap)
|
||||||
|
|
||||||
f.cr = cr
|
f.cr = cr
|
||||||
f.ur = ur
|
f.ur = ur
|
||||||
f.pwr = pwr
|
f.pwr = pwr
|
||||||
f.adAPI = admin.NewAdminAPI(ur, pwr, cr, um, cm, "local")
|
f.adAPI = admin.NewAdminAPI(ur, pwr, cr, ccr, um, cm, "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{
|
||||||
|
@ -272,6 +273,104 @@ func TestCreateAdmin(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConnectors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
req adminschema.ConnectorsSetRequest
|
||||||
|
want adminschema.ConnectorsGetResponse
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
req: adminschema.ConnectorsSetRequest{
|
||||||
|
Connectors: []interface{}{
|
||||||
|
map[string]string{
|
||||||
|
"type": "local",
|
||||||
|
"id": "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: adminschema.ConnectorsGetResponse{
|
||||||
|
Connectors: []interface{}{
|
||||||
|
map[string]string{
|
||||||
|
"id": "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: adminschema.ConnectorsSetRequest{
|
||||||
|
Connectors: []interface{}{
|
||||||
|
map[string]string{
|
||||||
|
"type": "github",
|
||||||
|
"id": "github",
|
||||||
|
"clientID": "foo",
|
||||||
|
"clientSecret": "bar",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"type": "oidc",
|
||||||
|
"id": "oidc",
|
||||||
|
"issuerURL": "https://auth.example.com",
|
||||||
|
"clientID": "foo",
|
||||||
|
"clientSecret": "bar",
|
||||||
|
"trustedEmailProvider": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: adminschema.ConnectorsGetResponse{
|
||||||
|
Connectors: []interface{}{
|
||||||
|
map[string]string{
|
||||||
|
"id": "github",
|
||||||
|
"clientID": "foo",
|
||||||
|
"clientSecret": "bar",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"id": "oidc",
|
||||||
|
"issuerURL": "https://auth.example.com",
|
||||||
|
"clientID": "foo",
|
||||||
|
"clientSecret": "bar",
|
||||||
|
"trustedEmailProvider": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Missing "type" argument
|
||||||
|
req: adminschema.ConnectorsSetRequest{
|
||||||
|
Connectors: []interface{}{
|
||||||
|
map[string]string{
|
||||||
|
"id": "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
f := makeAdminAPITestFixtures()
|
||||||
|
if err := f.adClient.Connectors.Set(&tt.req).Do(); err != nil {
|
||||||
|
if !tt.wantErr {
|
||||||
|
t.Errorf("case %d: failed to set connectors: %v", i, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tt.wantErr {
|
||||||
|
t.Errorf("case %d: expected error setting connectors", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := f.adClient.Connectors.Get().Do()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: failed toget connectors: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tt.want, resp); diff != "" {
|
||||||
|
t.Errorf("case %d: Compare(want, got) = %s", i, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateClient(t *testing.T) {
|
func TestCreateClient(t *testing.T) {
|
||||||
mustParseURL := func(s string) *url.URL {
|
mustParseURL := func(s string) *url.URL {
|
||||||
u, err := url.Parse(s)
|
u, err := url.Parse(s)
|
||||||
|
|
|
@ -34,7 +34,7 @@ __Version:__ v1
|
||||||
redirectURIs: [
|
redirectURIs: [
|
||||||
string
|
string
|
||||||
],
|
],
|
||||||
secret: string
|
secret: string // The client secret. Ignored in client create requests.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -58,6 +58,38 @@ Upon successful registration, an ID and secret is assigned to the client.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Connector
|
||||||
|
|
||||||
|
An object which describes a federating identity strategy. For documentation see Documentation/connectors-configuration.md. Since different connectors expect different object fields the scheme is omitted here.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### ConnectorsGetResponse
|
||||||
|
|
||||||
|
A list of all connector responses.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
connectors: [
|
||||||
|
Connector
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ConnectorsSetRequest
|
||||||
|
|
||||||
|
A request to set all the connectors in the dex database.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
connectors: [
|
||||||
|
Connector
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### State
|
### State
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,6 +182,50 @@ Upon successful registration, an ID and secret is assigned to the client.
|
||||||
| default | Unexpected error | |
|
| default | Unexpected error | |
|
||||||
|
|
||||||
|
|
||||||
|
### GET /connectors
|
||||||
|
|
||||||
|
> __Summary__
|
||||||
|
|
||||||
|
> Get Connectors
|
||||||
|
|
||||||
|
> __Description__
|
||||||
|
|
||||||
|
> Return a list of the connectors for the dex system.
|
||||||
|
|
||||||
|
|
||||||
|
> __Responses__
|
||||||
|
|
||||||
|
> |Code|Description|Type|
|
||||||
|
|:-----|:-----|:-----|
|
||||||
|
| 200 | | [ConnectorsGetResponse](#connectorsgetresponse) |
|
||||||
|
| default | Unexpected error | |
|
||||||
|
|
||||||
|
|
||||||
|
### PUT /connectors
|
||||||
|
|
||||||
|
> __Summary__
|
||||||
|
|
||||||
|
> Set Connectors
|
||||||
|
|
||||||
|
> __Description__
|
||||||
|
|
||||||
|
> Set the list of connectors for the dex system, overwriting all previous connectors. A 200 status code indicates the action was successful.
|
||||||
|
|
||||||
|
|
||||||
|
> __Parameters__
|
||||||
|
|
||||||
|
> |Name|Located in|Description|Required|Type|
|
||||||
|
|:-----|:-----|:-----|:-----|:-----|
|
||||||
|
| | body | | Yes | [ConnectorsSetRequest](#connectorssetrequest) |
|
||||||
|
|
||||||
|
|
||||||
|
> __Responses__
|
||||||
|
|
||||||
|
> |Code|Description|Type|
|
||||||
|
|:-----|:-----|:-----|
|
||||||
|
| default | Unexpected error | |
|
||||||
|
|
||||||
|
|
||||||
### GET /state
|
### GET /state
|
||||||
|
|
||||||
> __Summary__
|
> __Summary__
|
||||||
|
|
|
@ -47,6 +47,7 @@ func New(client *http.Client) (*Service, error) {
|
||||||
s := &Service{client: client, BasePath: basePath}
|
s := &Service{client: client, BasePath: basePath}
|
||||||
s.Admin = NewAdminService(s)
|
s.Admin = NewAdminService(s)
|
||||||
s.Client = NewClientService(s)
|
s.Client = NewClientService(s)
|
||||||
|
s.Connectors = NewConnectorsService(s)
|
||||||
s.State = NewStateService(s)
|
s.State = NewStateService(s)
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
@ -59,6 +60,8 @@ type Service struct {
|
||||||
|
|
||||||
Client *ClientService
|
Client *ClientService
|
||||||
|
|
||||||
|
Connectors *ConnectorsService
|
||||||
|
|
||||||
State *StateService
|
State *StateService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +83,15 @@ type ClientService struct {
|
||||||
s *Service
|
s *Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewConnectorsService(s *Service) *ConnectorsService {
|
||||||
|
rs := &ConnectorsService{s: s}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectorsService struct {
|
||||||
|
s *Service
|
||||||
|
}
|
||||||
|
|
||||||
func NewStateService(s *Service) *StateService {
|
func NewStateService(s *Service) *StateService {
|
||||||
rs := &StateService{s: s}
|
rs := &StateService{s: s}
|
||||||
return rs
|
return rs
|
||||||
|
@ -134,6 +146,7 @@ type Client struct {
|
||||||
// 2005. ) (Simple String Comparison).
|
// 2005. ) (Simple String Comparison).
|
||||||
RedirectURIs []string `json:"redirectURIs,omitempty"`
|
RedirectURIs []string `json:"redirectURIs,omitempty"`
|
||||||
|
|
||||||
|
// Secret: The client secret. Ignored in client create requests.
|
||||||
Secret string `json:"secret,omitempty"`
|
Secret string `json:"secret,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +158,16 @@ type ClientCreateResponse struct {
|
||||||
Client *Client `json:"client,omitempty"`
|
Client *Client `json:"client,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Connector interface{}
|
||||||
|
|
||||||
|
type ConnectorsGetResponse struct {
|
||||||
|
Connectors []interface{} `json:"connectors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectorsSetRequest struct {
|
||||||
|
Connectors []interface{} `json:"connectors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
AdminUserCreated bool `json:"AdminUserCreated,omitempty"`
|
AdminUserCreated bool `json:"AdminUserCreated,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -359,6 +382,128 @@ func (c *ClientCreateCall) Do() (*ClientCreateResponse, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// method id "dex.admin.Connector.Get":
|
||||||
|
|
||||||
|
type ConnectorsGetCall struct {
|
||||||
|
s *Service
|
||||||
|
opt_ map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get: Return a list of the connectors for the dex system.
|
||||||
|
func (r *ConnectorsService) Get() *ConnectorsGetCall {
|
||||||
|
c := &ConnectorsGetCall{s: r.s, opt_: make(map[string]interface{})}
|
||||||
|
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 *ConnectorsGetCall) Fields(s ...googleapi.Field) *ConnectorsGetCall {
|
||||||
|
c.opt_["fields"] = googleapi.CombineFields(s)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnectorsGetCall) Do() (*ConnectorsGetResponse, error) {
|
||||||
|
var body io.Reader = nil
|
||||||
|
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, "connectors")
|
||||||
|
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 *ConnectorsGetResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
// {
|
||||||
|
// "description": "Return a list of the connectors for the dex system.",
|
||||||
|
// "httpMethod": "GET",
|
||||||
|
// "id": "dex.admin.Connector.Get",
|
||||||
|
// "path": "connectors",
|
||||||
|
// "response": {
|
||||||
|
// "$ref": "ConnectorsGetResponse"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// method id "dex.admin.Connector.Set":
|
||||||
|
|
||||||
|
type ConnectorsSetCall struct {
|
||||||
|
s *Service
|
||||||
|
connectorssetrequest *ConnectorsSetRequest
|
||||||
|
opt_ map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set: Set the list of connectors for the dex system, overwriting all
|
||||||
|
// previous connectors. A 200 status code indicates the action was
|
||||||
|
// successful.
|
||||||
|
func (r *ConnectorsService) Set(connectorssetrequest *ConnectorsSetRequest) *ConnectorsSetCall {
|
||||||
|
c := &ConnectorsSetCall{s: r.s, opt_: make(map[string]interface{})}
|
||||||
|
c.connectorssetrequest = connectorssetrequest
|
||||||
|
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 *ConnectorsSetCall) Fields(s ...googleapi.Field) *ConnectorsSetCall {
|
||||||
|
c.opt_["fields"] = googleapi.CombineFields(s)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnectorsSetCall) Do() error {
|
||||||
|
var body io.Reader = nil
|
||||||
|
body, err := googleapi.WithoutDataWrapper.JSONReader(c.connectorssetrequest)
|
||||||
|
if err != nil {
|
||||||
|
return 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, "connectors")
|
||||||
|
urls += "?" + params.Encode()
|
||||||
|
req, _ := http.NewRequest("PUT", 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 err
|
||||||
|
}
|
||||||
|
defer googleapi.CloseBody(res)
|
||||||
|
if err := googleapi.CheckResponse(res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
// {
|
||||||
|
// "description": "Set the list of connectors for the dex system, overwriting all previous connectors. A 200 status code indicates the action was successful.",
|
||||||
|
// "httpMethod": "PUT",
|
||||||
|
// "id": "dex.admin.Connector.Set",
|
||||||
|
// "path": "connectors",
|
||||||
|
// "request": {
|
||||||
|
// "$ref": "ConnectorsSetRequest"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// method id "dex.admin.State.Get":
|
// method id "dex.admin.State.Get":
|
||||||
|
|
||||||
type StateGetCall struct {
|
type StateGetCall struct {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
package adminschema
|
package adminschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
@ -64,10 +63,6 @@ const DiscoveryJSON = `{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The client secret. Ignored in client create requests."
|
"description": "The client secret. Ignored in client create requests."
|
||||||
},
|
},
|
||||||
"secret": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "byte"
|
|
||||||
},
|
|
||||||
"isAdmin": {
|
"isAdmin": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -111,6 +106,37 @@ const DiscoveryJSON = `{
|
||||||
"$ref": "Client"
|
"$ref": "Client"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Connector": {
|
||||||
|
"id": "Connector",
|
||||||
|
"type": "any",
|
||||||
|
"description": "An object which describes a federating identity strategy. For documentation see Documentation/connectors-configuration.md. Since different connectors expect different object fields the scheme is omitted here."
|
||||||
|
},
|
||||||
|
"ConnectorsSetRequest": {
|
||||||
|
"id": "ConnectorsSetRequest",
|
||||||
|
"type": "object",
|
||||||
|
"description": "A request to set all the connectors in the dex database.",
|
||||||
|
"properties": {
|
||||||
|
"connectors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Connector"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectorsGetResponse": {
|
||||||
|
"id": "ConnectorsGetResponse",
|
||||||
|
"type": "object",
|
||||||
|
"description": "A list of all connector responses.",
|
||||||
|
"properties": {
|
||||||
|
"connectors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Connector"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
|
@ -134,7 +160,6 @@ const DiscoveryJSON = `{
|
||||||
"response": {
|
"response": {
|
||||||
"$ref": "Admin"
|
"$ref": "Admin"
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
"Create": {
|
"Create": {
|
||||||
"id": "dex.admin.Admin.Create",
|
"id": "dex.admin.Admin.Create",
|
||||||
|
@ -178,6 +203,28 @@ const DiscoveryJSON = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Connectors": {
|
||||||
|
"methods": {
|
||||||
|
"Set": {
|
||||||
|
"id": "dex.admin.Connector.Set",
|
||||||
|
"description": "Set the list of connectors for the dex system, overwriting all previous connectors. A 200 status code indicates the action was successful.",
|
||||||
|
"httpMethod": "PUT",
|
||||||
|
"path": "connectors",
|
||||||
|
"request": {
|
||||||
|
"$ref": "ConnectorsSetRequest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Get": {
|
||||||
|
"id": "dex.admin.Connector.Get",
|
||||||
|
"description": "Return a list of the connectors for the dex system.",
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"path": "connectors",
|
||||||
|
"response": {
|
||||||
|
"$ref": "ConnectorsGetResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,37 @@
|
||||||
"$ref": "Client"
|
"$ref": "Client"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Connector": {
|
||||||
|
"id": "Connector",
|
||||||
|
"type": "any",
|
||||||
|
"description": "An object which describes a federating identity strategy. For documentation see Documentation/connectors-configuration.md. Since different connectors expect different object fields the scheme is omitted here."
|
||||||
|
},
|
||||||
|
"ConnectorsSetRequest": {
|
||||||
|
"id": "ConnectorsSetRequest",
|
||||||
|
"type": "object",
|
||||||
|
"description": "A request to set all the connectors in the dex database.",
|
||||||
|
"properties": {
|
||||||
|
"connectors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Connector"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectorsGetResponse": {
|
||||||
|
"id": "ConnectorsGetResponse",
|
||||||
|
"type": "object",
|
||||||
|
"description": "A list of all connector responses.",
|
||||||
|
"properties": {
|
||||||
|
"connectors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Connector"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
|
@ -123,7 +154,6 @@
|
||||||
"response": {
|
"response": {
|
||||||
"$ref": "Admin"
|
"$ref": "Admin"
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
"Create": {
|
"Create": {
|
||||||
"id": "dex.admin.Admin.Create",
|
"id": "dex.admin.Admin.Create",
|
||||||
|
@ -167,6 +197,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Connectors": {
|
||||||
|
"methods": {
|
||||||
|
"Set": {
|
||||||
|
"id": "dex.admin.Connector.Set",
|
||||||
|
"description": "Set the list of connectors for the dex system, overwriting all previous connectors. A 200 status code indicates the action was successful.",
|
||||||
|
"httpMethod": "PUT",
|
||||||
|
"path": "connectors",
|
||||||
|
"request": {
|
||||||
|
"$ref": "ConnectorsSetRequest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Get": {
|
||||||
|
"id": "dex.admin.Connector.Get",
|
||||||
|
"description": "Return a list of the connectors for the dex system.",
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"path": "connectors",
|
||||||
|
"response": {
|
||||||
|
"$ref": "ConnectorsGetResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ if [ ! -f $GENDOC ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
go run schema/jsonfmt.go $IN
|
||||||
|
|
||||||
$GENDOC --f $IN --o $DOC
|
$GENDOC --f $IN --o $DOC
|
||||||
|
|
||||||
# Though google-api-go-generator is a main, dex vendors the app using the same
|
# Though google-api-go-generator is a main, dex vendors the app using the same
|
||||||
|
|
54
schema/jsonfmt.go
Normal file
54
schema/jsonfmt.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetPrefix("fmtjson: ")
|
||||||
|
log.SetFlags(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 1 {
|
||||||
|
log.Fatal(`usage: go run jsonfmt.go [files...]
|
||||||
|
|
||||||
|
This is a small utility that standardizes the formatting of JSON files.
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range os.Args[1:] {
|
||||||
|
data, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("reading file %s: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
if err := json.Indent(buff, data, "", " "); err != nil {
|
||||||
|
if err, ok := err.(*json.SyntaxError); ok {
|
||||||
|
// Calculate line number and column of error.
|
||||||
|
data := data[:err.Offset]
|
||||||
|
lineNum := 1 + bytes.Count(data, []byte{'\n'})
|
||||||
|
lastIndex := bytes.LastIndex(data, []byte{'\n'})
|
||||||
|
|
||||||
|
colNum := err.Offset
|
||||||
|
if lastIndex > -1 {
|
||||||
|
colNum = int64(len(data) - lastIndex)
|
||||||
|
}
|
||||||
|
log.Fatalf("file %s: invalid json at line %d, column %d: %v", path, lineNum, colNum, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatalf("file %s: invalid json: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(path, buff.Bytes(), 0644); err != nil {
|
||||||
|
log.Fatalf("write file %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -232,8 +232,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__
|
||||||
|
@ -310,8 +310,8 @@ A client with associated public metadata.
|
||||||
|
|
||||||
> |Name|Located in|Description|Required|Type|
|
> |Name|Located in|Description|Required|Type|
|
||||||
|:-----|:-----|:-----|:-----|:-----|
|
|:-----|:-----|:-----|:-----|:-----|
|
||||||
| nextPageToken | query | | No | string |
|
|
||||||
| maxResults | query | | No | integer |
|
| maxResults | query | | No | integer |
|
||||||
|
| nextPageToken | query | | No | string |
|
||||||
|
|
||||||
|
|
||||||
> __Responses__
|
> __Responses__
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
package workerschema
|
package workerschema
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file is automatically generated by schema/generator
|
// This file is automatically generated by schema/generator
|
||||||
//
|
//
|
||||||
|
@ -280,7 +279,8 @@ const DiscoveryJSON = `{
|
||||||
"httpMethod": "DELETE",
|
"httpMethod": "DELETE",
|
||||||
"path": "account/{userid}/refresh/{clientid}",
|
"path": "account/{userid}/refresh/{clientid}",
|
||||||
"parameterOrder": [
|
"parameterOrder": [
|
||||||
"userid","clientid"
|
"userid",
|
||||||
|
"clientid"
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"clientid": {
|
"clientid": {
|
||||||
|
|
|
@ -273,7 +273,8 @@
|
||||||
"httpMethod": "DELETE",
|
"httpMethod": "DELETE",
|
||||||
"path": "account/{userid}/refresh/{clientid}",
|
"path": "account/{userid}/refresh/{clientid}",
|
||||||
"parameterOrder": [
|
"parameterOrder": [
|
||||||
"userid","clientid"
|
"userid",
|
||||||
|
"clientid"
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"clientid": {
|
"clientid": {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
@ -9,6 +10,7 @@ import (
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
|
|
||||||
"github.com/coreos/dex/admin"
|
"github.com/coreos/dex/admin"
|
||||||
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/pkg/log"
|
"github.com/coreos/dex/pkg/log"
|
||||||
"github.com/coreos/dex/schema/adminschema"
|
"github.com/coreos/dex/schema/adminschema"
|
||||||
"github.com/coreos/go-oidc/key"
|
"github.com/coreos/go-oidc/key"
|
||||||
|
@ -24,6 +26,7 @@ var (
|
||||||
AdminCreateEndpoint = addBasePath("/admin")
|
AdminCreateEndpoint = addBasePath("/admin")
|
||||||
AdminGetStateEndpoint = addBasePath("/state")
|
AdminGetStateEndpoint = addBasePath("/state")
|
||||||
AdminCreateClientEndpoint = addBasePath("/client")
|
AdminCreateClientEndpoint = addBasePath("/client")
|
||||||
|
AdminConnectorsEndpoint = addBasePath("/connectors")
|
||||||
)
|
)
|
||||||
|
|
||||||
// AdminServer serves the admin API.
|
// AdminServer serves the admin API.
|
||||||
|
@ -53,6 +56,8 @@ func (s *AdminServer) HTTPHandler() http.Handler {
|
||||||
r.POST(AdminCreateClientEndpoint, s.createClient)
|
r.POST(AdminCreateClientEndpoint, s.createClient)
|
||||||
r.Handler("GET", httpPathHealth, s.checker)
|
r.Handler("GET", httpPathHealth, s.checker)
|
||||||
r.HandlerFunc("GET", httpPathDebugVars, health.ExpvarHandler)
|
r.HandlerFunc("GET", httpPathDebugVars, health.ExpvarHandler)
|
||||||
|
r.PUT(AdminConnectorsEndpoint, s.setConnectors)
|
||||||
|
r.GET(AdminConnectorsEndpoint, s.getConnectors)
|
||||||
|
|
||||||
return authorizer(r, s.secret, httpPathHealth, httpPathDebugVars)
|
return authorizer(r, s.secret, httpPathHealth, httpPathDebugVars)
|
||||||
}
|
}
|
||||||
|
@ -130,6 +135,41 @@ func (s *AdminServer) createClient(w http.ResponseWriter, r *http.Request, ps ht
|
||||||
writeResponseWithBody(w, http.StatusOK, &resp)
|
writeResponseWithBody(w, http.StatusOK, &resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AdminServer) setConnectors(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
var req struct {
|
||||||
|
Connectors json.RawMessage `json:"connectors"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
writeInvalidRequest(w, "cannot parse JSON body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
connectorConfigs, err := connector.ReadConfigs(bytes.NewReader([]byte(req.Connectors)))
|
||||||
|
if err != nil {
|
||||||
|
writeInvalidRequest(w, "cannot parse JSON body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := s.adminAPI.SetConnectors(connectorConfigs); err != nil {
|
||||||
|
s.writeError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AdminServer) getConnectors(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
connectorConfigs, err := s.adminAPI.GetConnectors()
|
||||||
|
if err != nil {
|
||||||
|
s.writeError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var resp adminschema.ConnectorsGetResponse
|
||||||
|
resp.Connectors = make([]interface{}, len(connectorConfigs))
|
||||||
|
for i, connectorConfig := range connectorConfigs {
|
||||||
|
resp.Connectors[i] = connectorConfig
|
||||||
|
}
|
||||||
|
writeResponseWithBody(w, http.StatusOK, &resp)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AdminServer) writeError(w http.ResponseWriter, err error) {
|
func (s *AdminServer) writeError(w http.ResponseWriter, err error) {
|
||||||
log.Errorf("Error calling admin API: %v: ", err)
|
log.Errorf("Error calling admin API: %v: ", err)
|
||||||
if adminErr, ok := err.(admin.Error); ok {
|
if adminErr, ok := err.(admin.Error); ok {
|
||||||
|
|
Reference in a new issue