diff options
author | M Hickford <mirth.hickford@gmail.com> | 2022-10-08 09:53:17 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-08 16:53:17 +0800 |
commit | 14bc4d79c1bf1826aab50a8947ab72414202b28a (patch) | |
tree | af682fc95c2ab029a328487e15adeece2dbe4350 | |
parent | 672d54fafa5c5a805886b4125daca8ba1d490af9 (diff) | |
download | gitea-14bc4d79c1bf1826aab50a8947ab72414202b28a.tar.gz gitea-14bc4d79c1bf1826aab50a8947ab72414202b28a.zip |
Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
Backport #21351
This fixes error "unauthorized_client: invalid client secret" when
client includes secret in Authorization header rather than request body.
OAuth spec permits both:
https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1
Clients in possession of a client password MAY use the HTTP Basic
authentication scheme ... Alternatively, the authorization server MAY
support including the client credentials in the request-body
Sanity validation that client id and client secret in request are
consistent with Authorization header.
Improve error descriptions. Error codes remain the same.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
-rw-r--r-- | routers/web/auth/oauth.go | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 56f8294b1a..a9fc39d019 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -588,7 +588,8 @@ func OIDCKeys(ctx *context.Context) { // AccessTokenOAuth manages all access token requests by the client func AccessTokenOAuth(ctx *context.Context) { form := *web.GetForm(ctx).(*forms.AccessTokenForm) - if form.ClientID == "" { + // if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header + if form.ClientID == "" || form.ClientSecret == "" { authHeader := ctx.Req.Header.Get("Authorization") authContent := strings.SplitN(authHeader, " ", 2) if len(authContent) == 2 && authContent[0] == "Basic" { @@ -608,7 +609,21 @@ func AccessTokenOAuth(ctx *context.Context) { }) return } + if form.ClientID != "" && form.ClientID != pair[0] { + handleAccessTokenError(ctx, AccessTokenError{ + ErrorCode: AccessTokenErrorCodeInvalidRequest, + ErrorDescription: "client_id in request body inconsistent with Authorization header", + }) + return + } form.ClientID = pair[0] + if form.ClientSecret != "" && form.ClientSecret != pair[1] { + handleAccessTokenError(ctx, AccessTokenError{ + ErrorCode: AccessTokenErrorCodeInvalidRequest, + ErrorDescription: "client_secret in request body inconsistent with Authorization header", + }) + return + } form.ClientSecret = pair[1] } } @@ -686,9 +701,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s return } if !app.ValidateClientSecret([]byte(form.ClientSecret)) { + errorDescription := "invalid client secret" + if form.ClientSecret == "" { + errorDescription = "invalid empty client secret" + } handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeUnauthorizedClient, - ErrorDescription: "client is not authorized", + ErrorDescription: errorDescription, }) return } |