mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-26 02:50:54 +00:00
fix: remove trailing slash from the issuer in oauth claims (#8028)
- Trim the ending slash '/' from the URL used in the OpenID Connect "well_known" endpoint and in the JWT tokens issued by Forgejo. - This makes it compliant with the OpenID specification. https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig - Resolves #7941 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8028 Reviewed-by: Lucas <sclu1034@noreply.codeberg.org> Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: jmaasing <jmaasing@noreply.codeberg.org> Co-committed-by: jmaasing <jmaasing@noreply.codeberg.org>
This commit is contained in:
parent
9b6e3b61cf
commit
5391f43888
4 changed files with 20 additions and 4 deletions
|
@ -225,7 +225,7 @@ func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, ser
|
||||||
idToken := &oauth2.OIDCToken{
|
idToken := &oauth2.OIDCToken{
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
|
ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
|
||||||
Issuer: setting.AppURL,
|
Issuer: strings.TrimSuffix(setting.AppURL, "/"),
|
||||||
Audience: []string{app.ClientID},
|
Audience: []string{app.ClientID},
|
||||||
Subject: fmt.Sprint(grant.UserID),
|
Subject: fmt.Sprint(grant.UserID),
|
||||||
},
|
},
|
||||||
|
@ -409,7 +409,7 @@ func IntrospectOAuth(ctx *context.Context) {
|
||||||
if err == nil && app != nil {
|
if err == nil && app != nil {
|
||||||
response.Active = true
|
response.Active = true
|
||||||
response.Scope = grant.Scope
|
response.Scope = grant.Scope
|
||||||
response.Issuer = setting.AppURL
|
response.Issuer = strings.TrimSuffix(setting.AppURL, "/")
|
||||||
response.Audience = []string{app.ClientID}
|
response.Audience = []string{app.ClientID}
|
||||||
response.Subject = fmt.Sprint(grant.UserID)
|
response.Subject = fmt.Sprint(grant.UserID)
|
||||||
}
|
}
|
||||||
|
@ -669,6 +669,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
|
||||||
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
|
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
|
||||||
func OIDCWellKnown(ctx *context.Context) {
|
func OIDCWellKnown(ctx *context.Context) {
|
||||||
ctx.Data["SigningKey"] = oauth2.DefaultSigningKey
|
ctx.Data["SigningKey"] = oauth2.DefaultSigningKey
|
||||||
|
ctx.Data["Issuer"] = strings.TrimSuffix(setting.AppURL, "/")
|
||||||
ctx.JSONTemplate("user/auth/oidc_wellknown")
|
ctx.JSONTemplate("user/auth/oidc_wellknown")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) {
|
||||||
|
|
||||||
// Scopes: openid
|
// Scopes: openid
|
||||||
oidcToken := createAndParseToken(t, grants[0])
|
oidcToken := createAndParseToken(t, grants[0])
|
||||||
|
assert.Equal(t, "https://try.gitea.io", oidcToken.RegisteredClaims.Issuer)
|
||||||
assert.Empty(t, oidcToken.Name)
|
assert.Empty(t, oidcToken.Name)
|
||||||
assert.Empty(t, oidcToken.PreferredUsername)
|
assert.Empty(t, oidcToken.PreferredUsername)
|
||||||
assert.Empty(t, oidcToken.Profile)
|
assert.Empty(t, oidcToken.Profile)
|
||||||
|
@ -67,6 +68,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) {
|
||||||
|
|
||||||
// Scopes: openid profile email
|
// Scopes: openid profile email
|
||||||
oidcToken = createAndParseToken(t, grants[0])
|
oidcToken = createAndParseToken(t, grants[0])
|
||||||
|
assert.Equal(t, "https://try.gitea.io", oidcToken.RegisteredClaims.Issuer)
|
||||||
assert.Equal(t, "User Five", oidcToken.Name)
|
assert.Equal(t, "User Five", oidcToken.Name)
|
||||||
assert.Equal(t, "user5", oidcToken.PreferredUsername)
|
assert.Equal(t, "user5", oidcToken.PreferredUsername)
|
||||||
assert.Equal(t, "https://try.gitea.io/user5", oidcToken.Profile)
|
assert.Equal(t, "https://try.gitea.io/user5", oidcToken.Profile)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"issuer": "{{AppUrl | JSEscape}}",
|
"issuer": "{{.Issuer | JSEscape}}",
|
||||||
"authorization_endpoint": "{{AppUrl | JSEscape}}login/oauth/authorize",
|
"authorization_endpoint": "{{AppUrl | JSEscape}}login/oauth/authorize",
|
||||||
"token_endpoint": "{{AppUrl | JSEscape}}login/oauth/access_token",
|
"token_endpoint": "{{AppUrl | JSEscape}}login/oauth/access_token",
|
||||||
"jwks_uri": "{{AppUrl | JSEscape}}login/oauth/keys",
|
"jwks_uri": "{{AppUrl | JSEscape}}login/oauth/keys",
|
||||||
|
|
|
@ -632,6 +632,19 @@ func TestSignInOAuthCallbackPKCE(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWellKnownDocumentIssuerDoesNotEndWithASlash(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
req := NewRequest(t, "GET", "/.well-known/openid-configuration")
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
type response struct {
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
}
|
||||||
|
parsed := new(response)
|
||||||
|
|
||||||
|
DecodeJSON(t, resp, parsed)
|
||||||
|
assert.Equal(t, strings.TrimSuffix(setting.AppURL, "/"), parsed.Issuer)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSignInOAuthCallbackRedirectToEscaping(t *testing.T) {
|
func TestSignInOAuthCallbackRedirectToEscaping(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
@ -697,7 +710,7 @@ func setupMockOIDCServer() *httptest.Server {
|
||||||
case "/.well-known/openid-configuration":
|
case "/.well-known/openid-configuration":
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(`{
|
w.Write([]byte(`{
|
||||||
"issuer": "` + mockServer.URL + `",
|
"issuer": "` + strings.TrimSuffix(mockServer.URL, "/") + `",
|
||||||
"authorization_endpoint": "` + mockServer.URL + `/authorize",
|
"authorization_endpoint": "` + mockServer.URL + `/authorize",
|
||||||
"token_endpoint": "` + mockServer.URL + `/token",
|
"token_endpoint": "` + mockServer.URL + `/token",
|
||||||
"userinfo_endpoint": "` + mockServer.URL + `/userinfo"
|
"userinfo_endpoint": "` + mockServer.URL + `/userinfo"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue