fix: glob support for RedirectURIs

Fixes #293
This commit is contained in:
David Sharnoff 2023-03-06 04:13:35 -08:00 committed by GitHub
parent 815ced424c
commit 7e5798569b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 14 deletions

View file

@ -44,11 +44,21 @@ func (c *Client) RedirectURIs() []string {
return c.redirectURIs return c.redirectURIs
} }
// RedirectURIGlobs provide wildcarding for additional valid redirects
func (c *Client) RedirectURIGlobs() []string {
return nil
}
// PostLogoutRedirectURIs must return the registered post_logout_redirect_uris for sign-outs // PostLogoutRedirectURIs must return the registered post_logout_redirect_uris for sign-outs
func (c *Client) PostLogoutRedirectURIs() []string { func (c *Client) PostLogoutRedirectURIs() []string {
return []string{} return []string{}
} }
// PostLogoutRedirectURIGlobs provide extra wildcarding for additional valid redirects
func (c *Client) PostLogoutRedirectURIGlobs() []string {
return nil
}
// ApplicationType must return the type of the client (app, native, user agent) // ApplicationType must return the type of the client (app, native, user agent)
func (c *Client) ApplicationType() op.ApplicationType { func (c *Client) ApplicationType() op.ApplicationType {
return c.applicationType return c.applicationType

View file

@ -6,6 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"path"
"strings" "strings"
"time" "time"
@ -274,6 +275,28 @@ func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
return scopes, nil return scopes, nil
} }
// checkURIAginstRedirects just checks aginst the valid redirect URIs and ignores
// other factors.
func checkURIAginstRedirects(client Client, uri string) error {
if str.Contains(client.RedirectURIs(), uri) {
return nil
}
if globClient, ok := client.(HasRedirectGlobs); ok {
for _, uriGlob := range globClient.RedirectURIGlobs() {
isMatch, err := path.Match(uriGlob, uri)
if err != nil {
return oidc.ErrServerError().WithParent(err)
}
if isMatch {
return nil
}
}
}
return oidc.ErrInvalidRequestRedirectURI().
WithDescription("The requested redirect_uri is missing in the client configuration. " +
"If you have any questions, you may contact the administrator of the application.")
}
// ValidateAuthReqRedirectURI validates the passed redirect_uri and response_type to the registered uris and client type // ValidateAuthReqRedirectURI validates the passed redirect_uri and response_type to the registered uris and client type
func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.ResponseType) error { func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.ResponseType) error {
if uri == "" { if uri == "" {
@ -281,19 +304,13 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
"Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.") "Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.")
} }
if strings.HasPrefix(uri, "https://") { if strings.HasPrefix(uri, "https://") {
if !str.Contains(client.RedirectURIs(), uri) { return checkURIAginstRedirects(client, uri)
return oidc.ErrInvalidRequestRedirectURI().
WithDescription("The requested redirect_uri is missing in the client configuration. " +
"If you have any questions, you may contact the administrator of the application.")
}
return nil
} }
if client.ApplicationType() == ApplicationTypeNative { if client.ApplicationType() == ApplicationTypeNative {
return validateAuthReqRedirectURINative(client, uri, responseType) return validateAuthReqRedirectURINative(client, uri, responseType)
} }
if !str.Contains(client.RedirectURIs(), uri) { if err := checkURIAginstRedirects(client, uri); err != nil {
return oidc.ErrInvalidRequestRedirectURI().WithDescription("The requested redirect_uri is missing in the client configuration. " + return err
"If you have any questions, you may contact the administrator of the application.")
} }
if strings.HasPrefix(uri, "http://") { if strings.HasPrefix(uri, "http://") {
if client.DevMode() { if client.DevMode() {
@ -313,10 +330,11 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error { func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error {
parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri) parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
isCustomSchema := !strings.HasPrefix(uri, "http://") isCustomSchema := !strings.HasPrefix(uri, "http://")
if str.Contains(client.RedirectURIs(), uri) { if err := checkURIAginstRedirects(client, uri); err == nil {
if client.DevMode() { if client.DevMode() {
return nil return nil
} }
// The RedirectURIs are only valid for native clients when localhost or non-"http://"
if isLoopback || isCustomSchema { if isLoopback || isCustomSchema {
return nil return nil
} }

View file

@ -45,6 +45,16 @@ type Client interface {
ClockSkew() time.Duration ClockSkew() time.Duration
} }
// HasRedirectGlobs is an optional interface that can be implemented by implementors of
// Client. See https://pkg.go.dev/path#Match for glob
// interpretation. Redirect URIs that match either the non-glob version or the
// glob version will be accepted. Glob URIs are only partially supported for native
// clients: "http://" is not allowed except for loopback or in dev mode.
type HasRedirectGlobs interface {
RedirectURIGlobs() []string
PostLogoutRedirectURIGlobs() []string
}
func ContainsResponseType(types []oidc.ResponseType, responseType oidc.ResponseType) bool { func ContainsResponseType(types []oidc.ResponseType, responseType oidc.ResponseType) bool {
for _, t := range types { for _, t := range types {
if t == responseType { if t == responseType {

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"net/http" "net/http"
"net/url" "net/url"
"path"
httphelper "github.com/zitadel/oidc/pkg/http" httphelper "github.com/zitadel/oidc/pkg/http"
"github.com/zitadel/oidc/pkg/oidc" "github.com/zitadel/oidc/pkg/oidc"
@ -98,5 +99,16 @@ func ValidateEndSessionPostLogoutRedirectURI(postLogoutRedirectURI string, clien
return nil return nil
} }
} }
if globClient, ok := client.(HasRedirectGlobs); ok {
for _, uriGlob := range globClient.PostLogoutRedirectURIGlobs() {
isMatch, err := path.Match(uriGlob, postLogoutRedirectURI)
if err != nil {
return oidc.ErrServerError().WithParent(err)
}
if isMatch {
return nil
}
}
}
return oidc.ErrInvalidRequest().WithDescription("post_logout_redirect_uri invalid") return oidc.ErrInvalidRequest().WithDescription("post_logout_redirect_uri invalid")
} }