Skip to content

Commit

Permalink
Allow 127.0.0.1 and [::1] redirect_uris for native clients
Browse files Browse the repository at this point in the history
For better compatibility with other implementations out there, this
change adds suport for native redirect_uris to be 127.0.0.1 and [::1] so
that applications can use those addresses for more explicit control when
for example a client has misconfigured firewalls or renamed network
interfaces.
  • Loading branch information
longsleep committed Feb 5, 2021
1 parent a97d281 commit 3e79432
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 18 deletions.
17 changes: 17 additions & 0 deletions identity/clients/clients.go
Expand Up @@ -19,6 +19,7 @@ package clients

import (
"crypto"
"net/url"
)

// Details hold detail information about clients identified by ID.
Expand All @@ -44,3 +45,19 @@ type Secured struct {

Registration *ClientRegistration
}

// IsLocalNativeHTTPURI returns true if the provided URI qualifies to be used
// as http redirect URI for a native client.
func IsLocalNativeHTTPURI(uri *url.URL) bool {
if uri.Scheme != "http" {
return false
}
return IsLocalNativeHostURI(uri)
}

// IsLocalNativeHostURI returns true if the provided URI hostname is considered
// as localhost for a native client.
func IsLocalNativeHostURI(uri *url.URL) bool {
hostname := uri.Hostname()
return hostname == "localhost" || hostname == "127.0.0.1" || hostname == "::1"
}
21 changes: 10 additions & 11 deletions identity/clients/registry.go
Expand Up @@ -146,8 +146,8 @@ func (r *Registry) Register(client *ClientRegistration) error {
return fmt.Errorf("invalid redirect_uri %v - invalid or no hostname", urlString)
} else if !client.Insecure && parsed.Scheme != "https" {
return fmt.Errorf("invalid redirect_uri %v - make sure to use https when application_type is web", parsed)
} else if parsed.Host == "localhost" {
return fmt.Errorf("invalid redirect_uri %v - host must not be localhost", parsed)
} else if IsLocalNativeHTTPURI(parsed) {
return fmt.Errorf("invalid redirect_uri %v - host must not be localhost when application_type is web", parsed)
}

if len(client.Origins) == 0 {
Expand All @@ -170,7 +170,7 @@ func (r *Registry) Register(client *ClientRegistration) error {
return fmt.Errorf("invalid redirect_uri %v - invalid uri or no hostname", urlString)
} else if parsed.Scheme == "https" {
return fmt.Errorf("invalid redirect_uri %v - scheme must not be https when application_type is native", parsed)
} else if parsed.Scheme == "http" && parsed.Hostname() != "localhost" {
} else if parsed.Scheme == "http" && !IsLocalNativeHTTPURI(parsed) {
return fmt.Errorf("invalid redirect_uri %v = http host must be localhost when application_type is native", parsed)
}
}
Expand Down Expand Up @@ -209,25 +209,24 @@ func (r *Registry) Validate(client *ClientRegistration, clientSecret string, red
// Make sure to validate the redirect URI unless client is marked insecure
// and has no configured redirect URIs.
redirectURIOK := false
for _, urlString := range client.RedirectURIs {
for _, registeredURIString := range client.RedirectURIs {
if client.ApplicationType == oidc.ApplicationTypeNative {
urlStringParsed, _ := url.Parse(urlString)
if urlStringParsed.Host == "localhost" && urlStringParsed.Scheme == "http" {
u, err := url.Parse(redirectURIString)
registeredURI, _ := url.Parse(registeredURIString)
if IsLocalNativeHTTPURI(registeredURI) {
redirectURI, err := url.Parse(redirectURIString)
if err != nil {
break
}
host := u.Hostname()
if host == "localhost" && u.Scheme == "http" {
if urlStringParsed.Path == "" || u.Path == urlStringParsed.Path {
if IsLocalNativeHTTPURI(redirectURI) {
if registeredURI.Path == "" || redirectURI.Path == registeredURI.Path {
redirectURIOK = true
break
}
}
continue
}
}
if urlString == redirectURIString {
if registeredURIString == redirectURIString {
redirectURIOK = true
break
}
Expand Down
8 changes: 8 additions & 0 deletions identity/clients/registry_test.go
Expand Up @@ -12,6 +12,9 @@ func TestRedirectUriWithDynamicPort(t *testing.T) {
}{
{"http://localhost:12345", false},
{"http://localhost:12345/callback", false},
{"http://127.0.0.1:12345/callback", false},
{"http://192.168.88.4:8080/callback", true},
{"http://[::1]:12345/callback", false},
{"http://localhost", false},
{"custom://callback.example.net", false},
{"http://localhost:12345/other-callback", false},
Expand Down Expand Up @@ -50,6 +53,8 @@ func TestRedirectUriWithSpecificPath(t *testing.T) {
}{
{"http://localhost:12345", true},
{"http://localhost:12345/callback", false},
{"http://127.0.0.1:12345/callback", false},
{"http://[::1]:12345/callback", false},
{"http://localhost", true},
{"custom://callback.example.net", true},
{"http://localhost:12345/callback-disallowed", true},
Expand All @@ -58,6 +63,9 @@ func TestRedirectUriWithSpecificPath(t *testing.T) {
{"http://host-with-port:123/callback", true},
{"https://localhost:123/callback", true},
{"http://localhost/other-callback", false},
{"http://127.0.0.1/other-callback", false},
{"http://10.0.0.1/other-callback", true},
{"http://[::1]/other-callback", false},
{"http://localhost:8080/other-callback", false},
}

Expand Down
13 changes: 6 additions & 7 deletions oidc/payload/registration.go
Expand Up @@ -173,10 +173,10 @@ func (crr *ClientRegistrationRequest) Validate() error {
}
if ok := registeredGrantTypes[oidc.GrantTypeImplicit]; ok {
if uri.Scheme != "https" {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "implicit web clients must use https redirect_uris")
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "web clients must use https redirect_uris")
}
if uri.Hostname() == "localhost" {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "implicit web clients must not use localhost redirect_uris")
if clients.IsLocalNativeHostURI(uri) {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "web clients must not use localhost redirect_uris")
}
}
}
Expand All @@ -189,10 +189,9 @@ func (crr *ClientRegistrationRequest) Validate() error {
if err != nil {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "failed to parse redirect_uris")
}
if uri.Scheme == "http" {
if uri.Hostname() != "localhost" {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "native clients must only use localhost redirect_uris with http")
}

if !clients.IsLocalNativeHTTPURI(uri) {
return konnectoidc.NewOAuth2Error(oidc.ErrorCodeOIDCInvalidRedirectURI, "native clients must only use localhost redirect_uris with http")
}
}

Expand Down

0 comments on commit 3e79432

Please sign in to comment.