better support for /device/callback redirect uris with public clients.

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
This commit is contained in:
justin-slowik 2020-05-13 15:38:43 -04:00
parent f6d8427f32
commit 9882ea453f
6 changed files with 19 additions and 11 deletions

View file

@ -98,8 +98,9 @@ staticClients:
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
# - id: example-device-client
# redirectURIs:
# - /dex/device/callback
# - /device/callback
# name: 'Static Client for Device Flow'
# public: true
connectors:
- type: mockCallback
id: mock

View file

@ -374,7 +374,7 @@ func (s *Server) verifyUserCode(w http.ResponseWriter, r *http.Request) {
q.Set("client_secret", deviceRequest.ClientSecret)
q.Set("state", deviceRequest.UserCode)
q.Set("response_type", "code")
q.Set("redirect_uri", path.Join(s.issuerURL.Path, "/device/callback"))
q.Set("redirect_uri", "/device/callback")
q.Set("scope", strings.Join(deviceRequest.Scopes, " "))
u.RawQuery = q.Encode()

View file

@ -128,7 +128,7 @@ func TestDeviceCallback(t *testing.T) {
baseAuthCode := storage.AuthCode{
ID: "somecode",
ClientID: "testclient",
RedirectURI: "/device/callback",
RedirectURI: deviceCallbackURI,
Nonce: "",
Scopes: []string{"openid", "profile", "email"},
ConnectorID: "mock",
@ -194,7 +194,7 @@ func TestDeviceCallback(t *testing.T) {
testAuthCode: storage.AuthCode{
ID: "somecode",
ClientID: "testclient",
RedirectURI: "/device/callback",
RedirectURI: deviceCallbackURI,
Nonce: "",
Scopes: []string{"openid", "profile", "email"},
ConnectorID: "pic",
@ -210,7 +210,7 @@ func TestDeviceCallback(t *testing.T) {
testAuthCode: storage.AuthCode{
ID: "somecode",
ClientID: "testclient",
RedirectURI: "/device/callback",
RedirectURI: deviceCallbackURI,
Nonce: "",
Scopes: []string{"openid", "profile", "email"},
ConnectorID: "pic",
@ -336,7 +336,7 @@ func TestDeviceCallback(t *testing.T) {
client := storage.Client{
ID: "testclient",
Secret: "",
RedirectURIs: []string{"/device/callback"},
RedirectURIs: []string{deviceCallbackURI},
}
if err := s.storage.CreateClient(client); err != nil {
t.Fatalf("failed to create client: %v", err)

View file

@ -114,6 +114,10 @@ const (
scopeCrossClientPrefix = "audience:server:client_id:"
)
const (
deviceCallbackURI = "/device/callback"
)
const (
redirectURIOOB = "urn:ietf:wg:oauth:2.0:oob"
)
@ -433,6 +437,9 @@ func (s *Server) parseAuthorizationRequest(r *http.Request) (*storage.AuthReques
description := fmt.Sprintf("Unregistered redirect_uri (%q).", redirectURI)
return nil, &authErr{"", "", errInvalidRequest, description}
}
if redirectURI == deviceCallbackURI && client.Public {
redirectURI = s.issuerURL.Path + deviceCallbackURI
}
// From here on out, we want to redirect back to the client with an error.
newErr := func(typ, format string, a ...interface{}) *authErr {
@ -574,7 +581,7 @@ func validateRedirectURI(client storage.Client, redirectURI string) bool {
return false
}
if redirectURI == redirectURIOOB {
if redirectURI == redirectURIOOB || redirectURI == deviceCallbackURI{
return true
}

View file

@ -309,7 +309,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
handleFunc("/device/auth/verify_code", s.verifyUserCode)
handleFunc("/device/code", s.handleDeviceCode)
handleFunc("/device/token", s.handleDeviceToken)
handleFunc("/device/callback", s.handleDeviceCallback)
handleFunc(deviceCallbackURI, s.handleDeviceCallback)
r.HandleFunc(path.Join(issuerURL.Path, "/callback"), func(w http.ResponseWriter, r *http.Request) {
// Strip the X-Remote-* headers to prevent security issues on
// misconfigured authproxy connector setups.

View file

@ -1317,8 +1317,8 @@ func TestOAuth2DeviceFlow(t *testing.T) {
//Add the Clients to the test server
client := storage.Client{
ID: clientID,
//Secret: "testclientsecret",
RedirectURIs: []string{"/non-root-path/device/callback"},
RedirectURIs: []string{deviceCallbackURI},
Public: true,
}
if err := s.storage.CreateClient(client); err != nil {
t.Fatalf("failed to create client: %v", err)
@ -1421,7 +1421,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
ClientSecret: client.Secret,
Endpoint: p.Endpoint(),
Scopes: requestedScopes,
RedirectURL: "/non-root-path/device/callback",
RedirectURL: deviceCallbackURI,
}
if len(tc.scopes) != 0 {
oauth2Config.Scopes = tc.scopes