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>
This commit is contained in:
parent
672d54fafa
commit
14bc4d79c1
|
@ -588,7 +588,8 @@ func OIDCKeys(ctx *context.Context) {
|
||||||
// AccessTokenOAuth manages all access token requests by the client
|
// AccessTokenOAuth manages all access token requests by the client
|
||||||
func AccessTokenOAuth(ctx *context.Context) {
|
func AccessTokenOAuth(ctx *context.Context) {
|
||||||
form := *web.GetForm(ctx).(*forms.AccessTokenForm)
|
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")
|
authHeader := ctx.Req.Header.Get("Authorization")
|
||||||
authContent := strings.SplitN(authHeader, " ", 2)
|
authContent := strings.SplitN(authHeader, " ", 2)
|
||||||
if len(authContent) == 2 && authContent[0] == "Basic" {
|
if len(authContent) == 2 && authContent[0] == "Basic" {
|
||||||
|
@ -608,7 +609,21 @@ func AccessTokenOAuth(ctx *context.Context) {
|
||||||
})
|
})
|
||||||
return
|
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]
|
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]
|
form.ClientSecret = pair[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -686,9 +701,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
|
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
|
||||||
|
errorDescription := "invalid client secret"
|
||||||
|
if form.ClientSecret == "" {
|
||||||
|
errorDescription = "invalid empty client secret"
|
||||||
|
}
|
||||||
handleAccessTokenError(ctx, AccessTokenError{
|
handleAccessTokenError(ctx, AccessTokenError{
|
||||||
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
|
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
|
||||||
ErrorDescription: "client is not authorized",
|
ErrorDescription: errorDescription,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue