forked from mystiq/dex
150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
// package admin provides an implementation of the API described in auth/schema/adminschema.
|
|
package admin
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/coreos/go-oidc/oidc"
|
|
"github.com/go-gorp/gorp"
|
|
|
|
"github.com/coreos/dex/client"
|
|
"github.com/coreos/dex/db"
|
|
"github.com/coreos/dex/schema/adminschema"
|
|
"github.com/coreos/dex/user"
|
|
"github.com/coreos/dex/user/manager"
|
|
)
|
|
|
|
// AdminAPI provides the logic necessary to implement the Admin API.
|
|
type AdminAPI struct {
|
|
userManager *manager.UserManager
|
|
userRepo user.UserRepo
|
|
passwordInfoRepo user.PasswordInfoRepo
|
|
clientIdentityRepo client.ClientIdentityRepo
|
|
localConnectorID string
|
|
}
|
|
|
|
// TODO(ericchiang): Swap the DbMap for a storage interface. See #278
|
|
|
|
func NewAdminAPI(dbMap *gorp.DbMap, userManager *manager.UserManager, localConnectorID string) *AdminAPI {
|
|
if localConnectorID == "" {
|
|
panic("must specify non-blank localConnectorID")
|
|
}
|
|
return &AdminAPI{
|
|
userManager: userManager,
|
|
userRepo: db.NewUserRepo(dbMap),
|
|
passwordInfoRepo: db.NewPasswordInfoRepo(dbMap),
|
|
clientIdentityRepo: db.NewClientIdentityRepo(dbMap),
|
|
localConnectorID: localConnectorID,
|
|
}
|
|
}
|
|
|
|
// Error is the error type returned by AdminAPI methods.
|
|
type Error struct {
|
|
Type string
|
|
|
|
// The HTTP Code to return for this type of error.
|
|
Code int
|
|
|
|
Desc string
|
|
|
|
// The underlying error - not to be consumed by external users.
|
|
Internal error
|
|
}
|
|
|
|
func (e Error) Error() string {
|
|
return e.Type
|
|
}
|
|
|
|
func errorMaker(typ string, desc string, code int) func(internal error) Error {
|
|
return func(internal error) Error {
|
|
return Error{
|
|
Type: typ,
|
|
Code: code,
|
|
Desc: desc,
|
|
Internal: internal,
|
|
}
|
|
}
|
|
}
|
|
|
|
var (
|
|
errorMap = map[error]func(error) Error{
|
|
user.ErrorNotFound: errorMaker("resource_not_found", "Resource could not be found.", http.StatusNotFound),
|
|
user.ErrorDuplicateEmail: errorMaker("bad_request", "Email already in use.", http.StatusBadRequest),
|
|
user.ErrorInvalidEmail: errorMaker("bad_request", "invalid email.", http.StatusBadRequest),
|
|
}
|
|
)
|
|
|
|
func (a *AdminAPI) GetAdmin(id string) (adminschema.Admin, error) {
|
|
usr, err := a.userRepo.Get(nil, id)
|
|
|
|
if err != nil {
|
|
return adminschema.Admin{}, mapError(err)
|
|
}
|
|
|
|
pwi, err := a.passwordInfoRepo.Get(nil, id)
|
|
if err != nil {
|
|
return adminschema.Admin{}, mapError(err)
|
|
}
|
|
|
|
return adminschema.Admin{
|
|
Id: id,
|
|
Email: usr.Email,
|
|
Password: string(pwi.Password),
|
|
}, nil
|
|
}
|
|
|
|
func (a *AdminAPI) CreateAdmin(admn adminschema.Admin) (string, error) {
|
|
userID, err := a.userManager.CreateUser(user.User{
|
|
Email: admn.Email,
|
|
Admin: true}, user.Password(admn.Password), a.localConnectorID)
|
|
if err != nil {
|
|
return "", mapError(err)
|
|
}
|
|
return userID, nil
|
|
}
|
|
|
|
func (a *AdminAPI) GetState() (adminschema.State, error) {
|
|
state := adminschema.State{}
|
|
|
|
admins, err := a.userRepo.GetAdminCount(nil)
|
|
if err != nil {
|
|
return adminschema.State{}, err
|
|
}
|
|
|
|
state.AdminUserCreated = admins > 0
|
|
|
|
return state, nil
|
|
}
|
|
|
|
type ClientRegistrationRequest struct {
|
|
IsAdmin bool `json:"isAdmin"`
|
|
Client oidc.ClientMetadata `json:"client"`
|
|
}
|
|
|
|
func (a *AdminAPI) CreateClient(req ClientRegistrationRequest) (oidc.ClientRegistrationResponse, error) {
|
|
if err := req.Client.Valid(); err != nil {
|
|
return oidc.ClientRegistrationResponse{}, mapError(err)
|
|
}
|
|
// metadata is guarenteed to have at least one redirect_uri by earlier validation.
|
|
id, err := oidc.GenClientID(req.Client.RedirectURIs[0].Host)
|
|
if err != nil {
|
|
return oidc.ClientRegistrationResponse{}, mapError(err)
|
|
}
|
|
c, err := a.clientIdentityRepo.New(id, req.Client, req.IsAdmin)
|
|
if err != nil {
|
|
return oidc.ClientRegistrationResponse{}, mapError(err)
|
|
}
|
|
return oidc.ClientRegistrationResponse{ClientID: c.ID, ClientSecret: c.Secret, ClientMetadata: req.Client}, nil
|
|
}
|
|
|
|
func mapError(e error) error {
|
|
if mapped, ok := errorMap[e]; ok {
|
|
return mapped(e)
|
|
}
|
|
return Error{
|
|
Code: http.StatusInternalServerError,
|
|
Type: "server_error",
|
|
Desc: "",
|
|
Internal: e,
|
|
}
|
|
}
|