BloodHound icon indicating copy to clipboard operation
BloodHound copied to clipboard

Feature: Toggle HTTPS override for SSO behind HTTP RP

Open 0xd6cb6d73 opened this issue 8 months ago • 0 comments

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.

0xd6cb6d73 avatar May 06 '25 11:05 0xd6cb6d73