fix: URL-encode login provider name in the href attribute (#10301)

The authentication provider's name (`$provider.DisplayName`) is not URL-encoded, so any illegal characters (e.g., '/') will be put in the link's href attribute verbatim.
For example, if the provider's name is `foo/bar` (valid name), the href attribute will point to `/user/oauth2/foo/bar` instead of `/user/oauth2/foo%2Fbar`, resulting in a "404 Not found" error.

This patch fixes this behaviour by URL-encoding the provider's DisplayName before appending it to the href attribute.

Signed-off-by: doasu <me@doasu.dev>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10301
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: doasu <me@doasu.dev>
Co-committed-by: doasu <me@doasu.dev>
This commit is contained in:
doasu 2026-03-31 21:51:57 +02:00 committed by Gusted
parent 939a3ada66
commit a9bd068d00
2 changed files with 31 additions and 1 deletions

View file

@ -8,7 +8,7 @@
<div class="tw-flex tw-flex-col tw-justify-center">
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
{{range $provider := .OAuth2Providers}}
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName | PathEscape}}">
{{$provider.IconHTML 28}}
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
</a>

View file

@ -97,6 +97,36 @@ func TestSigninWithRememberMe(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK)
}
func TestProviderDisplayNameIsPathEscaped(t *testing.T) {
defer tests.PrepareTestEnv(t)()
testCases := []string{
"sla/shed",
"per%cent",
"que?ry=string",
"ha#sh",
"spa ce", // doesn't break the path
"pl+us", // unchanged by url.PathEscape
"amper&sand", // unchanged by url.PathEscape
}
for _, testCase := range testCases {
// GitLab is only used here for convenience.
addAuthSource(t, authSourcePayloadGitLabCustom(testCase))
}
request := NewRequest(t, "GET", "/user/login")
response := MakeRequest(t, request, http.StatusOK)
htmlDoc := NewHTMLParser(t, response.Body)
for _, testCase := range testCases {
t.Run(testCase, func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
htmlDoc.AssertElement(t, fmt.Sprintf("a.oauth-login-link[href='/user/oauth2/%s']", url.PathEscape(testCase)), true)
})
}
}
func TestDisableSignin(t *testing.T) {
defer tests.PrepareTestEnv(t)()
// Mock alternative auth ways as enabled