mirror of
https://github.com/nais/wonderwall.git
synced 2026-05-08 09:27:12 +00:00
121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
package request
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/nais/wonderwall/pkg/config"
|
|
"github.com/nais/wonderwall/pkg/cookie"
|
|
"github.com/nais/wonderwall/pkg/openid"
|
|
"github.com/nais/wonderwall/pkg/router/paths"
|
|
)
|
|
|
|
var (
|
|
InvalidLoginParameterError = errors.New("InvalidLoginParameter")
|
|
)
|
|
|
|
// CanonicalRedirectURL constructs a redirect URL that points back to the application.
|
|
func CanonicalRedirectURL(r *http.Request) string {
|
|
redirectURL := "/"
|
|
|
|
referer := RefererPath(r)
|
|
if len(referer) > 0 {
|
|
redirectURL = referer
|
|
}
|
|
|
|
override := r.URL.Query().Get(RedirectURLParameter)
|
|
if len(override) > 0 {
|
|
referer, err := url.Parse(override)
|
|
if err == nil {
|
|
// strip scheme and host to avoid cross-domain redirects
|
|
referer.Scheme = ""
|
|
referer.Host = ""
|
|
redirectURL = referer.String()
|
|
}
|
|
}
|
|
|
|
return redirectURL
|
|
}
|
|
|
|
// LoginURLParameter attempts to get a given parameter from the given HTTP request, falling back if none found.
|
|
// The value must exist in the supplied list of supported values.
|
|
func LoginURLParameter(r *http.Request, parameter, fallback string, supported openid.Supported) (string, error) {
|
|
value := r.URL.Query().Get(parameter)
|
|
|
|
if len(value) == 0 {
|
|
value = fallback
|
|
}
|
|
|
|
if supported.Contains(value) {
|
|
return value, nil
|
|
}
|
|
|
|
return value, fmt.Errorf("%w: invalid value for %s=%s", InvalidLoginParameterError, parameter, value)
|
|
}
|
|
|
|
func PostLogoutRedirectURI(r *http.Request, fallback string) string {
|
|
value := r.URL.Query().Get(PostLogoutRedirectURIParameter)
|
|
|
|
if len(value) > 0 {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func RefererPath(r *http.Request) string {
|
|
result := ""
|
|
|
|
referer, err := url.Parse(r.Referer())
|
|
if err == nil && len(referer.Path) > 0 {
|
|
result = referer.Path
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// RetryURI returns a URI that should retry the desired route that failed.
|
|
// It only handles the routes exposed by Wonderwall, i.e. `/oauth2/*`. As these routes
|
|
// are related to the authentication flow, we default to redirecting back to the handled
|
|
// `/oauth2/login` endpoint unless the original request attempted to reach the logout-flow.
|
|
func RetryURI(r *http.Request, ingress string, loginCookie *cookie.Login) string {
|
|
retryURI := r.URL.Path
|
|
|
|
prefix := config.ParseIngress(ingress)
|
|
|
|
if strings.HasSuffix(retryURI, paths.OAuth2+paths.Logout) || strings.HasSuffix(retryURI, paths.OAuth2+paths.FrontChannelLogout) {
|
|
return prefix + retryURI
|
|
}
|
|
|
|
// 1. Default
|
|
redirect := "/"
|
|
|
|
// 2. Ingress has path prefix
|
|
if len(prefix) > 0 {
|
|
redirect = prefix
|
|
}
|
|
|
|
// 3. Referer header is set
|
|
referer := RefererPath(r)
|
|
if len(referer) > 0 {
|
|
redirect = referer
|
|
}
|
|
|
|
// 4. Redirect parameter is set
|
|
redirectURLFromParam, err := url.Parse(r.URL.Query().Get(RedirectURLParameter))
|
|
if err == nil && len(redirectURLFromParam.Path) > 0 {
|
|
redirect = redirectURLFromParam.Path
|
|
}
|
|
|
|
// 5. Login cookie exists and referer is set
|
|
if loginCookie != nil && len(loginCookie.Referer) > 0 {
|
|
redirect = loginCookie.Referer
|
|
}
|
|
|
|
retryURI = fmt.Sprintf(prefix + paths.OAuth2 + paths.Login)
|
|
retryURI = retryURI + fmt.Sprintf("?%s=%s", RedirectURLParameter, redirect)
|
|
return retryURI
|
|
}
|