Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth Req omitted response_mode does not validate the default response_mode against the ResponseModeClient #742

Open
5 of 6 tasks
james-d-elliott opened this issue Mar 27, 2023 · 0 comments
Labels
bug Something is not working.

Comments

@james-d-elliott
Copy link
Contributor

james-d-elliott commented Mar 27, 2023

Preflight checklist

Describe the bug

It appears there is no check of the permitted response modes for a client if the response mode itself is omitted. I don't think this is intended. Theoretically if a client is configured to only allow the form_post response mode, and the response_mode parameter is omitted, this authorization request should always fail. However maybe I'm missing something?

Reproducing the bug

Add the following case to the TestNewAuthorizeRequest test:

		/* determine correct response mode if default */
		{
			desc: "failure with default response mode",
			conf: &Fosite{Store: store, Config: &Config{ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy}},
			query: url.Values{
				"redirect_uri":  {"https://foo.bar/cb"},
				"client_id":     {"1234"},
				"response_type": {"code"},
				"state":         {"strong-state"},
				"scope":         {"foo bar"},
				"audience":      {"https://cloud.ory.sh/api https://www.ory.sh/api"},
			},
			mock: func() {
				store.EXPECT().GetClient(gomock.Any(), "1234").Return(&DefaultResponseModeClient{
					DefaultClient: &DefaultClient{
						RedirectURIs:  []string{"https://foo.bar/cb"},
						Scopes:        []string{"foo", "bar"},
						ResponseTypes: []string{"code"},
						Audience:      []string{"https://cloud.ory.sh/api", "https://www.ory.sh/api"},
					},
					ResponseModes: []ResponseModeType{ResponseModeFormPost},
				}, nil)
			},
			expectedError: ErrUnsupportedResponseMode,
		},

Relevant log output

No response

Relevant configuration

It's important to note that the behavior can realistically handled by implementers as well as fixed directly in the library which may be a consideration in deciding on a fix.

Version

0.44.0

On which operating system are you observing this issue?

Linux

In which environment are you deploying?

Other

Additional Context

The following patch should resolve the issue:

Subject: [PATCH] fix: default response mode not checked
---
Index: authorize_request_handler.go
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/authorize_request_handler.go b/authorize_request_handler.go
--- a/authorize_request_handler.go	(revision daf3b15f0433c207e40601065cb9c92c52a025f2)
+++ b/authorize_request_handler.go	(date 1679955288254)
@@ -235,29 +235,47 @@
 	return nil
 }
 
+// validateResponseMode MUST be called after validateResponseTypes due to the check on the request.GetResponseTypes.
 func (f *Fosite) validateResponseMode(r *http.Request, request *AuthorizeRequest) error {
-	if request.ResponseMode == ResponseModeDefault {
-		return nil
+	useDefault := request.GetResponseMode() == ResponseModeDefault
+
+	// A fallback handler to set the default response mode in cases where we can not reach the Authorize Handlers
+	// but still need the e.g. correct error response mode.
+	if useDefault {
+		if request.ResponseTypes.ExactOne("code") {
+			request.SetDefaultResponseMode(ResponseModeQuery)
+		} else {
+			// If the response type is not `code` it is an implicit/hybrid (fragment) response mode.
+			request.SetDefaultResponseMode(ResponseModeFragment)
+		}
 	}
 
 	responseModeClient, ok := request.GetClient().(ResponseModeClient)
 	if !ok {
+		if useDefault {
+			return nil
+		}
+
 		return errorsx.WithStack(ErrUnsupportedResponseMode.WithHintf("The request has response_mode \"%s\". set but registered OAuth 2.0 client doesn't support response_mode", r.Form.Get("response_mode")))
 	}
 
-	var found bool
+	responseMode := request.GetResponseMode()
+
+	if useDefault {
+		responseMode = request.GetDefaultResponseMode()
+	}
+
 	for _, t := range responseModeClient.GetResponseModes() {
 		if request.ResponseMode == t {
-			found = true
-			break
-		}
-	}
-
-	if !found {
-		return errorsx.WithStack(ErrUnsupportedResponseMode.WithHintf("The client is not allowed to request response_mode '%s'.", r.Form.Get("response_mode")))
-	}
-
-	return nil
+			return nil
+		}
+	}
+
+	if useDefault {
+		return errorsx.WithStack(ErrUnsupportedResponseMode.WithHintf("The request did not specify a response_mode and the default response_mode '%s' is not allowed on this client.", responseMode))
+	}
+
+	return errorsx.WithStack(ErrUnsupportedResponseMode.WithHintf("The client is not allowed to request response_mode '%s'.", request.ResponseMode))
 }
 
 func (f *Fosite) authorizeRequestFromPAR(ctx context.Context, r *http.Request, request *AuthorizeRequest) (bool, error) {
@@ -382,17 +400,6 @@
 		return request, err
 	}
 
-	// A fallback handler to set the default response mode in cases where we can not reach the Authorize Handlers
-	// but still need the e.g. correct error response mode.
-	if request.GetResponseMode() == ResponseModeDefault {
-		if request.ResponseTypes.ExactOne("code") {
-			request.SetDefaultResponseMode(ResponseModeQuery)
-		} else {
-			// If the response type is not `code` it is an implicit/hybrid (fragment) response mode.
-			request.SetDefaultResponseMode(ResponseModeFragment)
-		}
-	}
-
 	// rfc6819 4.4.1.8.  Threat: CSRF Attack against redirect-uri
 	// The "state" parameter should be used to link the authorization
 	// request with the redirect URI used to deliver the access token (Section 5.3.5).
Index: authorize_request_handler_test.go
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/authorize_request_handler_test.go b/authorize_request_handler_test.go
--- a/authorize_request_handler_test.go	(revision daf3b15f0433c207e40601065cb9c92c52a025f2)
+++ b/authorize_request_handler_test.go	(date 1679954955533)
@@ -492,6 +492,31 @@
 		},
 		/* determine correct response mode if default */
 		{
+			desc: "failure with default response mode",
+			conf: &Fosite{Store: store, Config: &Config{ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy}},
+			query: url.Values{
+				"redirect_uri":  {"https://foo.bar/cb"},
+				"client_id":     {"1234"},
+				"response_type": {"code"},
+				"state":         {"strong-state"},
+				"scope":         {"foo bar"},
+				"audience":      {"https://cloud.ory.sh/api https://www.ory.sh/api"},
+			},
+			mock: func() {
+				store.EXPECT().GetClient(gomock.Any(), "1234").Return(&DefaultResponseModeClient{
+					DefaultClient: &DefaultClient{
+						RedirectURIs:  []string{"https://foo.bar/cb"},
+						Scopes:        []string{"foo", "bar"},
+						ResponseTypes: []string{"code"},
+						Audience:      []string{"https://cloud.ory.sh/api", "https://www.ory.sh/api"},
+					},
+					ResponseModes: []ResponseModeType{ResponseModeFormPost},
+				}, nil)
+			},
+			expectedError: ErrUnsupportedResponseMode,
+		},
+		/* determine correct response mode if default */
+		{
 			desc: "success with response mode",
 			conf: &Fosite{Store: store, Config: &Config{ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy}},
 			query: url.Values{
@james-d-elliott james-d-elliott added the bug Something is not working. label Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working.
Projects
None yet
Development

No branches or pull requests

1 participant