server: remove client_resource api
...and dependent code.
This commit is contained in:
parent
adb2ccf872
commit
8942a49702
5 changed files with 0 additions and 538 deletions
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
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)
|
||||
handler := NewUserMgmtServer(usersAPI, s.JWTVerifierFactory(), s.UserManager, s.ClientManager).HTTPHandler()
|
||||
|
||||
|
|
Reference in a new issue