Skip to content

Commit

Permalink
fix(oauth2): allow confidential auth code http
Browse files Browse the repository at this point in the history
This allows confidential clients to use the http scheme for a redirect URI.
  • Loading branch information
james-d-elliott committed Dec 27, 2024
1 parent 524abd8 commit 586d44f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
19 changes: 8 additions & 11 deletions handler/oauth2/flow_authorize_code_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ var (
_ oauth2.TokenEndpointHandler = (*AuthorizeExplicitGrantHandler)(nil)
)

func (c *AuthorizeExplicitGrantHandler) secureChecker(ctx context.Context) func(context.Context, *url.URL) bool {
if c.Config.GetRedirectSecureChecker(ctx) == nil {
return oauth2.IsRedirectURISecure
func (c *AuthorizeExplicitGrantHandler) GetRedirectSecureChecker(ctx context.Context) (checker func(context.Context, *url.URL) bool) {
if checker = c.Config.GetRedirectSecureChecker(ctx); checker != nil {
return checker
}
return c.Config.GetRedirectSecureChecker(ctx)

return oauth2.IsRedirectURISecure
}

func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx context.Context, requester oauth2.AuthorizeRequester, responder oauth2.AuthorizeResponder) error {
Expand All @@ -55,16 +56,12 @@ func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx conte

requester.SetDefaultResponseMode(oauth2.ResponseModeQuery)

// Disabled because this is already handled at the authorize_request_handler
// if !requester.GetClient().GetResponseTypes().Has("code") {
// return errorsx.WithStack(oauth2.ErrInvalidGrant)
// }
client := requester.GetClient()

if !c.secureChecker(ctx)(ctx, requester.GetRedirectURI()) {
return errorsx.WithStack(oauth2.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix 'localhost', for example: http://myapp.localhost/."))
if client.IsPublic() && !c.GetRedirectSecureChecker(ctx)(ctx, requester.GetRedirectURI()) {
return errorsx.WithStack(oauth2.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for confidential clients or hosts with suffix 'localhost', for example: http://myapp.localhost/."))
}

client := requester.GetClient()
for _, scope := range requester.GetRequestedScopes() {
if !c.Config.GetScopeStrategy(ctx)(client.GetScopes(), scope) {
return errorsx.WithStack(oauth2.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope '%s'.", scope))
Expand Down
34 changes: 34 additions & 0 deletions handler/oauth2/flow_authorize_code_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) {
ResponseTypes: oauth2.Arguments{consts.ResponseTypeAuthorizationCodeFlow},
Request: oauth2.Request{
Client: &oauth2.DefaultClient{
Public: true,
ResponseTypes: oauth2.Arguments{consts.ResponseTypeAuthorizationCodeFlow},
RedirectURIs: []string{"http://asdf.com/cb"},
},
Session: &oauth2.DefaultSession{
ExpiresAt: map[oauth2.TokenType]time.Time{oauth2.AccessToken: time.Now().UTC().Add(time.Hour)},
},
},
RedirectURI: parseUrl("http://asdf.com/cb"),
},
Expand All @@ -92,6 +96,36 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) {
description: "should fail because audience doesn't match",
expectErr: oauth2.ErrInvalidRequest,
},
{
handler: handler,
areq: &oauth2.AuthorizeRequest{
ResponseTypes: oauth2.Arguments{consts.ResponseTypeAuthorizationCodeFlow},
Request: oauth2.Request{
Client: &oauth2.DefaultClient{
ResponseTypes: oauth2.Arguments{consts.ResponseTypeAuthorizationCodeFlow},
RedirectURIs: []string{"http://asdf.de/cb"},
Audience: []string{"https://www.authelia.com/api"},
},
RequestedAudience: []string{"https://www.authelia.com/api"},
GrantedScope: oauth2.Arguments{"a", "b"},
Session: &oauth2.DefaultSession{
ExpiresAt: map[oauth2.TokenType]time.Time{oauth2.AccessToken: time.Now().UTC().Add(time.Hour)},
},
RequestedAt: time.Now().UTC(),
},
State: "superstate",
RedirectURI: parseUrl("http://asdf.de/cb"),
},
description: "should pass redirect uri http confidential",
expect: func(t *testing.T, areq *oauth2.AuthorizeRequest, aresp *oauth2.AuthorizeResponse) {
code := aresp.GetParameters().Get(consts.FormParameterAuthorizationCode)
assert.NotEmpty(t, code)

assert.Equal(t, strings.Join(areq.GrantedScope, " "), aresp.GetParameters().Get(consts.FormParameterScope))
assert.Equal(t, areq.State, aresp.GetParameters().Get(consts.FormParameterState))
assert.Equal(t, oauth2.ResponseModeQuery, areq.GetResponseMode())
},
},
{
handler: handler,
areq: &oauth2.AuthorizeRequest{
Expand Down

0 comments on commit 586d44f

Please sign in to comment.