Feature: Toggle HTTPS override for SSO behind HTTP RP
Feature Description
Add a toggle to force HTTPS URL generation in SAML, OIDC and SSO code.
Are you intending to implement this feature?
No
Current Behavior
BHCE currently looks at its URL to generate the various redirect URLs used in the SSO flows. This works fine in a scenario where the user connects to the server directly but breaks in the following case:
- the BHCE instance is behind a reverse proxy
- the reverse proxy uses HTTP to communicate with BHCE
- users use HTTPS to commujnicate with the reverse proxy
In this case, the generated URLs use the HTTP scheme which doesn't work as the client connects to the reverse proxy using HTTPS.
Desired Behavior
A toggle, preferably in the administrative UI, would allow the administrator of the BHCE instance to force the SSO code to generate HTTPS URLs.
Use Case
We run BHCE behind a reverse proxy. The BHCE instance listens on HTTP to offload TLS processing to the RP to lighten the server load when using automation.
Implementation Suggestions
I have identified the following items which needed to be modified (in my case to hardcode a HTTPS scheme) to make this work in our environment.
SSO
At cmd/api/src/api/v2/auth/sso.go#L54:
func (s *AuthProvider) FormatProviderURLs(hostUrl url.URL) {
root := hostUrl
root.Path = path.Join("/api/v2/sso/", s.Slug)
...
At cmd/api/src/api/auth.go#L302:
func SetSecureBrowserCookie(request *http.Request, response http.ResponseWriter, name, value string, expires time.Time, httpOnly bool, sameSite http.SameSite) {
var (
hostURL = *ctx.FromRequest(request).Host
isHttps = hostURL.Scheme == "https"
)
// If sameSite is not explicitly set, we want to rely on the host scheme
if sameSite == 0 && isHttps {
sameSite = http.SameSiteStrictMode
}
...
Obviously, this feature requires the code to NOT rely on the host scheme as we specifically want to override it. Authentication fails with recent version of chrome if this code is not made aware of our modifications as the Secure attribute is not set on the PKCE cookie (and possibly others).
OIDC
At cmd/api/src/api/v2/auth/oidc.go#L154:
func getRedirectURL(hostUrl url.URL, provider model.SSOProvider) string {
return fmt.Sprintf("%s/api/v2/sso/%s/callback", hostUrl.String(), provider.Slug)
}
SAML
At cmd/api/src/api/v2/auth/saml.go#L149:
func (s ManagementResource) SAMLLoginRedirect(response http.ResponseWriter, request *http.Request) {
...
bheCtx := ctx.FromRequest(request)
redirectURL := api.URLJoinPath(*bheCtx.Host, fmt.Sprintf("/api/v2/sso/%s/login", ssoProvider.Slug))
http.Redirect(response, request, redirectURL.String(), http.StatusFound)
...
}
func (s ManagementResource) SAMLCallbackRedirect(response http.ResponseWriter, request *http.Request) {
...
bheCtx := ctx.FromRequest(request)
redirectURL := api.URLJoinPath(*bheCtx.Host, fmt.Sprintf("/api/v2/sso/%s/callback", ssoProvider.Slug))
http.Redirect(response, request, redirectURL.String(), http.StatusTemporaryRedirect)
...
}
cmd/api/src/api/v2/auth/saml.go#L398:
func (s ManagementResource) SAMLLoginHandler(response http.ResponseWriter, request *http.Request, ssoProvider model.SSOProvider) {
...
if bindingLocation == "" {
binding = saml.HTTPPostBinding
bindingLocation = serviceProvider.GetSSOBindingLocation(binding)
}
// TODO: add actual relay state support - BED-5071
if authReq, err := serviceProvider.MakeAuthenticationRequest(bindingLocation, binding, saml.HTTPPostBinding); err != nil {
...
}
Here, the serviceProvider's URLs need to have their scheme set to HTTPS before the MakeAuthenticationRequest call.
At cmd/api/src/model/samlprovider.go#L196:
func (s *SAMLProvider) FormatSAMLProviderURLs(hostUrl url.URL) {
root := hostUrl
root.Path = path.Join(SAMLRootURIVersionMap[s.RootURIVersion], s.Name)
...
It is possible that the SAML-related items are incomplete or not entirely necessary as we do not use it anymore.
Additional Information
The highlighted items should likely be plumbed to some front-end toggle controlling an HTTPS-only override.