mirror of https://github.com/dexidp/dex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
7.7 KiB
256 lines
7.7 KiB
package server |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"io" |
|
"io/ioutil" |
|
"net/http" |
|
"net/http/httptest" |
|
"net/url" |
|
"reflect" |
|
"strings" |
|
"testing" |
|
|
|
"github.com/coreos/dex/client" |
|
schema "github.com/coreos/dex/schema/workerschema" |
|
"github.com/coreos/go-oidc/oidc" |
|
) |
|
|
|
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"}} |
|
repo := client.NewClientIdentityRepo(nil) |
|
res := &clientResource{repo: repo} |
|
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":"invalid redirect URL: scheme not http/https"}`, |
|
}, |
|
// 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":"invalid redirect URL: host empty"}`, |
|
}, |
|
} |
|
|
|
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) { |
|
repo := client.NewClientIdentityRepo(nil) |
|
res := &clientResource{repo: repo} |
|
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) { |
|
tests := []struct { |
|
cs []oidc.ClientIdentity |
|
want []*schema.Client |
|
}{ |
|
// empty repo |
|
{ |
|
cs: nil, |
|
want: nil, |
|
}, |
|
// single client |
|
{ |
|
cs: []oidc.ClientIdentity{ |
|
oidc.ClientIdentity{ |
|
Credentials: oidc.ClientCredentials{ID: "foo", Secret: "bar"}, |
|
Metadata: oidc.ClientMetadata{ |
|
RedirectURLs: []url.URL{ |
|
url.URL{Scheme: "http", Host: "example.com"}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
want: []*schema.Client{ |
|
&schema.Client{ |
|
Id: "foo", |
|
RedirectURIs: []string{"http://example.com"}, |
|
}, |
|
}, |
|
}, |
|
// multi client |
|
{ |
|
cs: []oidc.ClientIdentity{ |
|
oidc.ClientIdentity{ |
|
Credentials: oidc.ClientCredentials{ID: "foo", Secret: "bar"}, |
|
Metadata: oidc.ClientMetadata{ |
|
RedirectURLs: []url.URL{ |
|
url.URL{Scheme: "http", Host: "example.com"}, |
|
}, |
|
}, |
|
}, |
|
oidc.ClientIdentity{ |
|
Credentials: oidc.ClientCredentials{ID: "biz", Secret: "bang"}, |
|
Metadata: oidc.ClientMetadata{ |
|
RedirectURLs: []url.URL{ |
|
url.URL{Scheme: "https", Host: "example.com", Path: "one/two/three"}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
want: []*schema.Client{ |
|
&schema.Client{ |
|
Id: "biz", |
|
RedirectURIs: []string{"https://example.com/one/two/three"}, |
|
}, |
|
&schema.Client{ |
|
Id: "foo", |
|
RedirectURIs: []string{"http://example.com"}, |
|
}, |
|
}, |
|
}, |
|
} |
|
|
|
for i, tt := range tests { |
|
repo := client.NewClientIdentityRepo(tt.cs) |
|
res := &clientResource{repo: repo} |
|
|
|
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) |
|
} |
|
|
|
if !reflect.DeepEqual(tt.want, resp.Clients) { |
|
t.Errorf("case %d: invalid response body, want=%#v, got=%#v", i, tt.want, resp.Clients) |
|
} |
|
} |
|
}
|
|
|