diff --git a/path_oidc.go b/path_oidc.go index 127678bc..fb275e54 100644 --- a/path_oidc.go +++ b/path_oidc.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "net" "net/http" "net/url" "strings" @@ -537,6 +538,17 @@ func (b *jwtAuthBackend) verifyOIDCRequest(stateID string) *oidcRequest { return nil } +func isLoopbackAddress(hostname string) bool { + ip := net.ParseIP(hostname) + if ip != nil { + return ip.IsLoopback() + } else { + // localhost is not guaranteed to map back to a loopback interface address + // however, this is historically how the plugin has behaved + return hostname == "localhost" + } +} + // validRedirect checks whether uri is in allowed using special handling for loopback uris. // Ref: https://tools.ietf.org/html/rfc8252#section-7.3 func validRedirect(uri string, allowed []string) bool { @@ -546,7 +558,7 @@ func validRedirect(uri string, allowed []string) bool { } // if uri isn't a loopback, just string search the allowed list - if !strutil.StrListContains([]string{"localhost", "127.0.0.1", "::1"}, inputURI.Hostname()) { + if !isLoopbackAddress(inputURI.Hostname()) { return strutil.StrListContainsCaseInsensitive(allowed, uri) } diff --git a/path_oidc_test.go b/path_oidc_test.go index faf1b3c6..a38e2785 100644 --- a/path_oidc_test.go +++ b/path_oidc_test.go @@ -1563,6 +1563,7 @@ func TestOIDC_ValidRedirect(t *testing.T) { {"https://example.com/a/b/c", []string{"a", "b", "https://example.com/a/b/c"}, true}, {"https://localhost:9000", []string{"a", "b", "https://localhost:5000"}, true}, {"https://127.0.0.1:9000", []string{"a", "b", "https://127.0.0.1:5000"}, true}, + {"https://127.0.0.2:9000", []string{"a", "b", "https://127.0.0.2:5000"}, true}, {"https://[::1]:9000", []string{"a", "b", "https://[::1]:5000"}, true}, {"https://[::1]:9000/x/y?r=42", []string{"a", "b", "https://[::1]:5000/x/y?r=42"}, true}, {"https://EXAMPLE.com:5000", []string{"a", "b", "https://example.com:5000"}, true},