111 lines
3.1 KiB
Go
111 lines
3.1 KiB
Go
|
package server
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"path"
|
||
|
|
||
|
"github.com/coreos/dex/client"
|
||
|
phttp "github.com/coreos/dex/pkg/http"
|
||
|
"github.com/coreos/dex/pkg/log"
|
||
|
schema "github.com/coreos/dex/schema/workerschema"
|
||
|
"github.com/coreos/go-oidc/oidc"
|
||
|
)
|
||
|
|
||
|
type clientResource struct {
|
||
|
repo client.ClientIdentityRepo
|
||
|
}
|
||
|
|
||
|
func registerClientResource(prefix string, repo client.ClientIdentityRepo) (string, http.Handler) {
|
||
|
mux := http.NewServeMux()
|
||
|
c := &clientResource{
|
||
|
repo: repo,
|
||
|
}
|
||
|
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.repo.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.MapClientIdentityToSchemaClient(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.MapSchemaClientToClientIdentity(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
|
||
|
}
|
||
|
|
||
|
clientID, err := oidc.GenClientID(ci.Metadata.RedirectURLs[0].Host)
|
||
|
if err != nil {
|
||
|
log.Errorf("Failed generating ID for new client: %v", err)
|
||
|
writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to generate client ID"))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
creds, err := c.repo.New(clientID, ci.Metadata)
|
||
|
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.MapClientIdentityToSchemaClientWithSecret(ci)
|
||
|
w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
|
||
|
writeResponseWithBody(w, http.StatusCreated, ssc)
|
||
|
}
|