mirror of https://github.com/dexidp/dex.git
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] } |
||||
Loading…
Reference in new issue