9c699b1028
Extracted test cases from OAuth2Code flow tests to reuse in device flow deviceHandler unit tests to test specific device endpoints Include client secret as an optional parameter for standards compliance Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
673 lines
20 KiB
Go
673 lines
20 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/dexidp/dex/storage"
|
|
)
|
|
|
|
func TestDeviceVerificationURI(t *testing.T) {
|
|
t0 := time.Now()
|
|
|
|
now := func() time.Time { return t0 }
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
// Setup a dex server.
|
|
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
|
c.Issuer = c.Issuer + "/non-root-path"
|
|
c.Now = now
|
|
})
|
|
defer httpServer.Close()
|
|
|
|
u, err := url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
u.Path = path.Join(u.Path, "/device/auth/verify_code")
|
|
|
|
uri := s.getDeviceVerificationURI()
|
|
if uri != u.Path {
|
|
t.Errorf("Invalid verification URI. Expected %v got %v", u.Path, uri)
|
|
}
|
|
}
|
|
|
|
func TestHandleDeviceCode(t *testing.T) {
|
|
t0 := time.Now()
|
|
|
|
now := func() time.Time { return t0 }
|
|
|
|
tests := []struct {
|
|
testName string
|
|
clientID string
|
|
scopes []string
|
|
expectedResponseCode int
|
|
expectedServerResponse string
|
|
}{
|
|
{
|
|
testName: "New Valid Code",
|
|
clientID: "test",
|
|
scopes: []string{"openid", "profile", "email"},
|
|
expectedResponseCode: http.StatusOK,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Setup a dex server.
|
|
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
|
c.Issuer = c.Issuer + "/non-root-path"
|
|
c.Now = now
|
|
})
|
|
defer httpServer.Close()
|
|
|
|
u, err := url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
u.Path = path.Join(u.Path, "device/code")
|
|
|
|
data := url.Values{}
|
|
data.Set("client_id", tc.clientID)
|
|
for _, scope := range tc.scopes {
|
|
data.Add("scope", scope)
|
|
}
|
|
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
|
|
|
rr := httptest.NewRecorder()
|
|
s.ServeHTTP(rr, req)
|
|
if rr.Code != tc.expectedResponseCode {
|
|
t.Errorf("Unexpected Response Type. Expected %v got %v", tc.expectedResponseCode, rr.Code)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(rr.Body)
|
|
if err != nil {
|
|
t.Errorf("Could read token response %v", err)
|
|
}
|
|
if tc.expectedResponseCode == http.StatusOK {
|
|
var resp deviceCodeResponse
|
|
if err := json.Unmarshal(body, &resp); err != nil {
|
|
t.Errorf("Unexpected Device Code Response Format %v", string(body))
|
|
}
|
|
}
|
|
if tc.expectedResponseCode == http.StatusBadRequest || tc.expectedResponseCode == http.StatusUnauthorized {
|
|
expectErrorResponse(tc.testName, body, tc.expectedServerResponse, t)
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func TestDeviceCallback(t *testing.T) {
|
|
t0 := time.Now()
|
|
|
|
now := func() time.Time { return t0 }
|
|
|
|
type formValues struct {
|
|
state string
|
|
code string
|
|
error string
|
|
}
|
|
|
|
// Base "Control" test values
|
|
baseFormValues := formValues{
|
|
state: "XXXX-XXXX",
|
|
code: "somecode",
|
|
}
|
|
baseAuthCode := storage.AuthCode{
|
|
ID: "somecode",
|
|
ClientID: "testclient",
|
|
RedirectURI: "/device/callback",
|
|
Nonce: "",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
ConnectorID: "mock",
|
|
ConnectorData: nil,
|
|
Claims: storage.Claims{},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
}
|
|
baseDeviceRequest := storage.DeviceRequest{
|
|
UserCode: "XXXX-XXXX",
|
|
DeviceCode: "devicecode",
|
|
ClientID: "testclient",
|
|
ClientSecret: "",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
}
|
|
baseDeviceToken := storage.DeviceToken{
|
|
DeviceCode: "devicecode",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
}
|
|
|
|
tests := []struct {
|
|
testName string
|
|
expectedResponseCode int
|
|
values formValues
|
|
testAuthCode storage.AuthCode
|
|
testDeviceRequest storage.DeviceRequest
|
|
testDeviceToken storage.DeviceToken
|
|
}{
|
|
{
|
|
testName: "Missing State",
|
|
values: formValues{
|
|
state: "",
|
|
code: "somecode",
|
|
error: "",
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Missing Code",
|
|
values: formValues{
|
|
state: "XXXX-XXXX",
|
|
code: "",
|
|
error: "",
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Error During Authorization",
|
|
values: formValues{
|
|
state: "XXXX-XXXX",
|
|
code: "somecode",
|
|
error: "Error Condition",
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Expired Auth Code",
|
|
values: baseFormValues,
|
|
testAuthCode: storage.AuthCode{
|
|
ID: "somecode",
|
|
ClientID: "testclient",
|
|
RedirectURI: "/device/callback",
|
|
Nonce: "",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
ConnectorID: "pic",
|
|
ConnectorData: nil,
|
|
Claims: storage.Claims{},
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Invalid Auth Code",
|
|
values: baseFormValues,
|
|
testAuthCode: storage.AuthCode{
|
|
ID: "somecode",
|
|
ClientID: "testclient",
|
|
RedirectURI: "/device/callback",
|
|
Nonce: "",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
ConnectorID: "pic",
|
|
ConnectorData: nil,
|
|
Claims: storage.Claims{},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Expired Device Request",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "XXXX-XXXX",
|
|
DeviceCode: "devicecode",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Non-Existent User Code",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "ZZZZ-ZZZZ",
|
|
DeviceCode: "devicecode",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Bad Device Request Client",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "XXXX-XXXX",
|
|
DeviceCode: "devicecode",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
testName: "Bad Device Request Secret",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "XXXX-XXXX",
|
|
DeviceCode: "devicecode",
|
|
ClientSecret: "foobar",
|
|
Scopes: []string{"openid", "profile", "email"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
expectedResponseCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
testName: "Expired Device Token",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "devicecode",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Device Code Already Redeemed",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "devicecode",
|
|
Status: deviceTokenComplete,
|
|
Token: "",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Successful Exchange",
|
|
values: baseFormValues,
|
|
testAuthCode: baseAuthCode,
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: baseDeviceToken,
|
|
expectedResponseCode: http.StatusOK,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Setup a dex server.
|
|
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
|
//c.Issuer = c.Issuer + "/non-root-path"
|
|
c.Now = now
|
|
})
|
|
defer httpServer.Close()
|
|
|
|
if err := s.storage.CreateAuthCode(tc.testAuthCode); err != nil {
|
|
t.Errorf("failed to create auth code: %v", err)
|
|
}
|
|
|
|
if err := s.storage.CreateDeviceRequest(tc.testDeviceRequest); err != nil {
|
|
t.Errorf("failed to create device request: %v", err)
|
|
}
|
|
|
|
if err := s.storage.CreateDeviceToken(tc.testDeviceToken); err != nil {
|
|
t.Errorf("failed to create device token: %v", err)
|
|
}
|
|
|
|
client := storage.Client{
|
|
ID: "testclient",
|
|
Secret: "",
|
|
RedirectURIs: []string{"/device/callback"},
|
|
}
|
|
if err := s.storage.CreateClient(client); err != nil {
|
|
t.Fatalf("failed to create client: %v", err)
|
|
}
|
|
|
|
u, err := url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
u.Path = path.Join(u.Path, "device/callback")
|
|
q := u.Query()
|
|
q.Set("state", tc.values.state)
|
|
q.Set("code", tc.values.code)
|
|
q.Set("error", tc.values.error)
|
|
u.RawQuery = q.Encode()
|
|
req, _ := http.NewRequest("GET", u.String(), nil)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
|
|
|
rr := httptest.NewRecorder()
|
|
s.ServeHTTP(rr, req)
|
|
if rr.Code != tc.expectedResponseCode {
|
|
t.Errorf("%s: Unexpected Response Type. Expected %v got %v", tc.testName, tc.expectedResponseCode, rr.Code)
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func TestDeviceTokenResponse(t *testing.T) {
|
|
t0 := time.Now()
|
|
|
|
now := func() time.Time { return t0 }
|
|
|
|
baseDeviceRequest := storage.DeviceRequest{
|
|
UserCode: "ABCD-WXYZ",
|
|
DeviceCode: "foo",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "offline_access"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
}
|
|
|
|
tests := []struct {
|
|
testName string
|
|
testDeviceRequest storage.DeviceRequest
|
|
testDeviceToken storage.DeviceToken
|
|
testGrantType string
|
|
testDeviceCode string
|
|
expectedServerResponse string
|
|
expectedResponseCode int
|
|
}{
|
|
{
|
|
testName: "Valid but pending token",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "f00bar",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "f00bar",
|
|
expectedServerResponse: deviceTokenPending,
|
|
expectedResponseCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
testName: "Invalid Grant Type",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "f00bar",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "f00bar",
|
|
testGrantType: grantTypeAuthorizationCode,
|
|
expectedServerResponse: errInvalidGrant,
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Test Slow Down State",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "f00bar",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: now(),
|
|
PollIntervalSeconds: 10,
|
|
},
|
|
testDeviceCode: "f00bar",
|
|
expectedServerResponse: deviceTokenSlowDown,
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Test Expired Device Token",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "f00bar",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "f00bar",
|
|
expectedServerResponse: deviceTokenExpired,
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Test Non-existent Device Code",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "foo",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "bar",
|
|
expectedServerResponse: errInvalidRequest,
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Empty Device Code in Request",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "bar",
|
|
Status: deviceTokenPending,
|
|
Token: "",
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "",
|
|
expectedServerResponse: errInvalidRequest,
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
testName: "Claim validated token from Device Code",
|
|
testDeviceRequest: baseDeviceRequest,
|
|
testDeviceToken: storage.DeviceToken{
|
|
DeviceCode: "foo",
|
|
Status: deviceTokenComplete,
|
|
Token: "{\"access_token\": \"foobar\"}",
|
|
Expiry: now().Add(5 * time.Minute),
|
|
LastRequestTime: time.Time{},
|
|
PollIntervalSeconds: 0,
|
|
},
|
|
testDeviceCode: "foo",
|
|
expectedServerResponse: "{\"access_token\": \"foobar\"}",
|
|
expectedResponseCode: http.StatusOK,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Setup a dex server.
|
|
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
|
c.Issuer = c.Issuer + "/non-root-path"
|
|
c.Now = now
|
|
})
|
|
defer httpServer.Close()
|
|
|
|
if err := s.storage.CreateDeviceRequest(tc.testDeviceRequest); err != nil {
|
|
t.Errorf("Failed to store device token %v", err)
|
|
}
|
|
|
|
if err := s.storage.CreateDeviceToken(tc.testDeviceToken); err != nil {
|
|
t.Errorf("Failed to store device token %v", err)
|
|
}
|
|
|
|
u, err := url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
u.Path = path.Join(u.Path, "device/token")
|
|
|
|
data := url.Values{}
|
|
grantType := grantTypeDeviceCode
|
|
if tc.testGrantType != "" {
|
|
grantType = tc.testGrantType
|
|
}
|
|
data.Set("grant_type", grantType)
|
|
data.Set("device_code", tc.testDeviceCode)
|
|
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
|
|
|
rr := httptest.NewRecorder()
|
|
s.ServeHTTP(rr, req)
|
|
if rr.Code != tc.expectedResponseCode {
|
|
t.Errorf("Unexpected Response Type. Expected %v got %v", tc.expectedResponseCode, rr.Code)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(rr.Body)
|
|
if err != nil {
|
|
t.Errorf("Could read token response %v", err)
|
|
}
|
|
if tc.expectedResponseCode == http.StatusBadRequest || tc.expectedResponseCode == http.StatusUnauthorized {
|
|
expectErrorResponse(tc.testName, body, tc.expectedServerResponse, t)
|
|
} else if string(body) != tc.expectedServerResponse {
|
|
t.Errorf("Unexpected Server Response. Expected %v got %v", tc.expectedServerResponse, string(body))
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func expectErrorResponse(testCase string, body []byte, expectedError string, t *testing.T) {
|
|
jsonMap := make(map[string]interface{})
|
|
err := json.Unmarshal(body, &jsonMap)
|
|
if err != nil {
|
|
t.Errorf("Unexpected error unmarshalling response: %v", err)
|
|
}
|
|
if jsonMap["error"] != expectedError {
|
|
t.Errorf("Test Case %s expected error %v, received %v", testCase, expectedError, jsonMap["error"])
|
|
}
|
|
}
|
|
|
|
func TestVerifyCodeResponse(t *testing.T) {
|
|
t0 := time.Now()
|
|
|
|
now := func() time.Time { return t0 }
|
|
|
|
tests := []struct {
|
|
testName string
|
|
testDeviceRequest storage.DeviceRequest
|
|
userCode string
|
|
expectedResponseCode int
|
|
expectedRedirectPath string
|
|
}{
|
|
{
|
|
testName: "Unknown user code",
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "ABCD-WXYZ",
|
|
DeviceCode: "f00bar",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "offline_access"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
userCode: "CODE-TEST",
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
expectedRedirectPath: "",
|
|
},
|
|
{
|
|
testName: "Expired user code",
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "ABCD-WXYZ",
|
|
DeviceCode: "f00bar",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "offline_access"},
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
},
|
|
userCode: "ABCD-WXYZ",
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
expectedRedirectPath: "",
|
|
},
|
|
{
|
|
testName: "No user code",
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "ABCD-WXYZ",
|
|
DeviceCode: "f00bar",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "offline_access"},
|
|
Expiry: now().Add(-5 * time.Minute),
|
|
},
|
|
userCode: "",
|
|
expectedResponseCode: http.StatusBadRequest,
|
|
expectedRedirectPath: "",
|
|
},
|
|
{
|
|
testName: "Valid user code, expect redirect to auth endpoint",
|
|
testDeviceRequest: storage.DeviceRequest{
|
|
UserCode: "ABCD-WXYZ",
|
|
DeviceCode: "f00bar",
|
|
ClientID: "testclient",
|
|
Scopes: []string{"openid", "profile", "offline_access"},
|
|
Expiry: now().Add(5 * time.Minute),
|
|
},
|
|
userCode: "ABCD-WXYZ",
|
|
expectedResponseCode: http.StatusFound,
|
|
expectedRedirectPath: "/auth",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Setup a dex server.
|
|
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
|
c.Issuer = c.Issuer + "/non-root-path"
|
|
c.Now = now
|
|
})
|
|
defer httpServer.Close()
|
|
|
|
if err := s.storage.CreateDeviceRequest(tc.testDeviceRequest); err != nil {
|
|
t.Errorf("Failed to store device token %v", err)
|
|
}
|
|
|
|
u, err := url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
|
|
u.Path = path.Join(u.Path, "device/auth/verify_code")
|
|
data := url.Values{}
|
|
data.Set("user_code", tc.userCode)
|
|
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
|
|
|
rr := httptest.NewRecorder()
|
|
s.ServeHTTP(rr, req)
|
|
if rr.Code != tc.expectedResponseCode {
|
|
t.Errorf("Unexpected Response Type. Expected %v got %v", tc.expectedResponseCode, rr.Code)
|
|
}
|
|
|
|
u, err = url.Parse(s.issuerURL.String())
|
|
if err != nil {
|
|
t.Errorf("Could not parse issuer URL %v", err)
|
|
}
|
|
u.Path = path.Join(u.Path, tc.expectedRedirectPath)
|
|
|
|
location := rr.Header().Get("Location")
|
|
if rr.Code == http.StatusFound && !strings.HasPrefix(location, u.Path) {
|
|
t.Errorf("Invalid Redirect. Expected %v got %v", u.Path, location)
|
|
}
|
|
}()
|
|
}
|
|
}
|