Skip to content

Commit 98927cd

Browse files
committed
Ignore port for OAuth2 loopback redirect URIs (go-gitea#21293) (go-gitea#21373)
Backport go-gitea#21293 Following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3 Fixes go-gitea#21285
1 parent 2c1696b commit 98927cd

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

models/auth/oauth2.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"encoding/base32"
1111
"encoding/base64"
1212
"fmt"
13+
"net"
1314
"net/url"
1415
"strings"
1516

@@ -56,6 +57,18 @@ func (app *OAuth2Application) PrimaryRedirectURI() string {
5657

5758
// ContainsRedirectURI checks if redirectURI is allowed for app
5859
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
60+
uri, err := url.Parse(redirectURI)
61+
// ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
62+
if err == nil && uri.Scheme == "http" && uri.Port() != "" {
63+
ip := net.ParseIP(uri.Hostname())
64+
if ip != nil && ip.IsLoopback() {
65+
// strip port
66+
uri.Host = uri.Hostname()
67+
if util.IsStringInSlice(uri.String(), app.RedirectURIs, true) {
68+
return true
69+
}
70+
}
71+
}
5972
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
6073
}
6174

models/auth/oauth2_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
4242
assert.False(t, app.ContainsRedirectURI("d"))
4343
}
4444

45+
func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
46+
app := &OAuth2Application{
47+
RedirectURIs: []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
48+
}
49+
50+
// http loopback uris should ignore port
51+
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
52+
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
53+
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
54+
assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
55+
56+
// not http
57+
assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
58+
// not loopback
59+
assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
60+
assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
61+
// unparseable
62+
assert.False(t, app.ContainsRedirectURI(":"))
63+
}
64+
4565
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
4666
assert.NoError(t, unittest.PrepareTestDatabase())
4767
app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application)

0 commit comments

Comments
 (0)