diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index aa599bd252..e8e5d2c54b 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -225,7 +225,7 @@ func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, ser idToken := &oauth2.OIDCToken{ RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()), - Issuer: setting.AppURL, + Issuer: strings.TrimSuffix(setting.AppURL, "/"), Audience: []string{app.ClientID}, Subject: fmt.Sprint(grant.UserID), }, @@ -409,7 +409,7 @@ func IntrospectOAuth(ctx *context.Context) { if err == nil && app != nil { response.Active = true response.Scope = grant.Scope - response.Issuer = setting.AppURL + response.Issuer = strings.TrimSuffix(setting.AppURL, "/") response.Audience = []string{app.ClientID} 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 func OIDCWellKnown(ctx *context.Context) { ctx.Data["SigningKey"] = oauth2.DefaultSigningKey + ctx.Data["Issuer"] = strings.TrimSuffix(setting.AppURL, "/") ctx.JSONTemplate("user/auth/oidc_wellknown") } diff --git a/routers/web/auth/oauth_test.go b/routers/web/auth/oauth_test.go index 487b551d6c..9782711dd0 100644 --- a/routers/web/auth/oauth_test.go +++ b/routers/web/auth/oauth_test.go @@ -51,6 +51,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) { // Scopes: openid oidcToken := createAndParseToken(t, grants[0]) + assert.Equal(t, "https://try.gitea.io", oidcToken.RegisteredClaims.Issuer) assert.Empty(t, oidcToken.Name) assert.Empty(t, oidcToken.PreferredUsername) assert.Empty(t, oidcToken.Profile) @@ -67,6 +68,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) { // Scopes: openid profile email 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, "user5", oidcToken.PreferredUsername) assert.Equal(t, "https://try.gitea.io/user5", oidcToken.Profile) diff --git a/templates/user/auth/oidc_wellknown.tmpl b/templates/user/auth/oidc_wellknown.tmpl index 54bb4a763d..d8edcae41d 100644 --- a/templates/user/auth/oidc_wellknown.tmpl +++ b/templates/user/auth/oidc_wellknown.tmpl @@ -1,5 +1,5 @@ { - "issuer": "{{AppUrl | JSEscape}}", + "issuer": "{{.Issuer | JSEscape}}", "authorization_endpoint": "{{AppUrl | JSEscape}}login/oauth/authorize", "token_endpoint": "{{AppUrl | JSEscape}}login/oauth/access_token", "jwks_uri": "{{AppUrl | JSEscape}}login/oauth/keys", diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index a89bb2c510..2b44863ec2 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -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) { defer tests.PrepareTestEnv(t)() @@ -697,7 +710,7 @@ func setupMockOIDCServer() *httptest.Server { case "/.well-known/openid-configuration": w.WriteHeader(http.StatusOK) w.Write([]byte(`{ - "issuer": "` + mockServer.URL + `", + "issuer": "` + strings.TrimSuffix(mockServer.URL, "/") + `", "authorization_endpoint": "` + mockServer.URL + `/authorize", "token_endpoint": "` + mockServer.URL + `/token", "userinfo_endpoint": "` + mockServer.URL + `/userinfo"