forked from mystiq/dex
parent
adbf486246
commit
35ea3d9ae1
6 changed files with 219 additions and 18 deletions
37
admin/api.go
37
admin/api.go
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/coreos/dex/client"
|
||||
clientmanager "github.com/coreos/dex/client/manager"
|
||||
"github.com/coreos/dex/connector"
|
||||
"github.com/coreos/dex/schema/adminschema"
|
||||
"github.com/coreos/dex/user"
|
||||
usermanager "github.com/coreos/dex/user/manager"
|
||||
|
@ -13,25 +14,27 @@ import (
|
|||
|
||||
// AdminAPI provides the logic necessary to implement the Admin API.
|
||||
type AdminAPI struct {
|
||||
userManager *usermanager.UserManager
|
||||
userRepo user.UserRepo
|
||||
passwordInfoRepo user.PasswordInfoRepo
|
||||
clientRepo client.ClientRepo
|
||||
clientManager *clientmanager.ClientManager
|
||||
localConnectorID string
|
||||
userManager *usermanager.UserManager
|
||||
userRepo user.UserRepo
|
||||
passwordInfoRepo user.PasswordInfoRepo
|
||||
connectorConfigRepo connector.ConnectorConfigRepo
|
||||
clientRepo client.ClientRepo
|
||||
clientManager *clientmanager.ClientManager
|
||||
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 == "" {
|
||||
panic("must specify non-blank localConnectorID")
|
||||
}
|
||||
return &AdminAPI{
|
||||
userManager: userManager,
|
||||
userRepo: userRepo,
|
||||
passwordInfoRepo: pwiRepo,
|
||||
clientRepo: clientRepo,
|
||||
clientManager: clientManager,
|
||||
localConnectorID: localConnectorID,
|
||||
userManager: userManager,
|
||||
userRepo: userRepo,
|
||||
passwordInfoRepo: pwiRepo,
|
||||
clientRepo: clientRepo,
|
||||
clientManager: clientManager,
|
||||
connectorConfigRepo: connectorConfigRepo,
|
||||
localConnectorID: localConnectorID,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +153,14 @@ func (a *AdminAPI) CreateClient(req adminschema.ClientCreateRequest) (adminschem
|
|||
}, 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 {
|
||||
if mapped, ok := errorMap[e]; ok {
|
||||
return mapped(e)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
type testFixtures struct {
|
||||
ur user.UserRepo
|
||||
pwr user.PasswordInfoRepo
|
||||
ccr connector.ConnectorConfigRepo
|
||||
cr client.ClientRepo
|
||||
cm *clientmanager.ClientManager
|
||||
mgr *manager.UserManager
|
||||
|
@ -63,7 +64,7 @@ func makeTestFixtures() *testFixtures {
|
|||
return repo
|
||||
}()
|
||||
|
||||
ccr := func() connector.ConnectorConfigRepo {
|
||||
f.ccr = func() connector.ConnectorConfigRepo {
|
||||
c := []connector.ConnectorConfig{&connector.LocalConnectorConfig{ID: "local"}}
|
||||
repo := db.NewConnectorConfigRepo(dbMap)
|
||||
if err := repo.Set(c); err != nil {
|
||||
|
@ -72,9 +73,9 @@ func makeTestFixtures() *testFixtures {
|
|||
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.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
|
||||
}
|
||||
|
@ -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,
|
||||
pwiRepo, connCfgRepo, db.TransactionFactory(dbc), manager.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()...)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
|
|
|
@ -63,6 +63,7 @@ type ConnectorConfig interface {
|
|||
type ConnectorConfigRepo interface {
|
||||
All() ([]ConnectorConfig, error)
|
||||
GetConnectorByID(repo.Transaction, string) (ConnectorConfig, error)
|
||||
Set(cfgs []ConnectorConfig) error
|
||||
}
|
||||
|
||||
type IdentityProvider interface {
|
||||
|
|
|
@ -93,11 +93,12 @@ func makeAdminAPITestFixtures() *adminAPITestFixtures {
|
|||
return fmt.Sprintf("client_%v", hostport), nil
|
||||
}
|
||||
cm := manager.NewClientManager(cr, db.TransactionFactory(dbMap), manager.ManagerOptions{SecretGenerator: secGen, ClientIDGenerator: clientIDGenerator})
|
||||
ccr := db.NewConnectorConfigRepo(dbMap)
|
||||
|
||||
f.cr = cr
|
||||
f.ur = ur
|
||||
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.hSrv = httptest.NewServer(f.adSrv.HTTPHandler())
|
||||
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) {
|
||||
mustParseURL := func(s string) *url.URL {
|
||||
u, err := url.Parse(s)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"path"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/coreos/dex/admin"
|
||||
"github.com/coreos/dex/connector"
|
||||
"github.com/coreos/dex/pkg/log"
|
||||
"github.com/coreos/dex/schema/adminschema"
|
||||
"github.com/coreos/go-oidc/key"
|
||||
|
@ -24,6 +26,7 @@ var (
|
|||
AdminCreateEndpoint = addBasePath("/admin")
|
||||
AdminGetStateEndpoint = addBasePath("/state")
|
||||
AdminCreateClientEndpoint = addBasePath("/client")
|
||||
AdminConnectorsEndpoint = addBasePath("/connectors")
|
||||
)
|
||||
|
||||
// AdminServer serves the admin API.
|
||||
|
@ -53,6 +56,8 @@ func (s *AdminServer) HTTPHandler() http.Handler {
|
|||
r.POST(AdminCreateClientEndpoint, s.createClient)
|
||||
r.Handler("GET", httpPathHealth, s.checker)
|
||||
r.HandlerFunc("GET", httpPathDebugVars, health.ExpvarHandler)
|
||||
r.PUT(AdminConnectorsEndpoint, s.setConnectors)
|
||||
r.GET(AdminConnectorsEndpoint, s.getConnectors)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
log.Errorf("Error calling admin API: %v: ", err)
|
||||
if adminErr, ok := err.(admin.Error); ok {
|
||||
|
|
Loading…
Reference in a new issue