Skip to content

[Bug][server] Any Basic credentials pass RequireAuth when AUTH_ENABLED=true: OAuth2ProxyAuthentication never verifies the password #9146

Description

@celeronsx

Search before asking

  • I had searched in the issues and found no similar issues.

What happened

With AUTH_ENABLED=true (native OIDC, #8854), every non-public API route accepts any Authorization: Basic <user>:<pass> header as an authenticated user. Nothing checks the password.

OAuth2ProxyAuthentication (backend/server/api/middlewares.go) predates native auth. It decodes the Basic header and sets common.USER to the username, because in the classic layout nginx in config-ui has already verified the credentials against ADMIN_USER/ADMIN_PASS before proxying to the lake, and the lake only needed the name for audit fields:

func getBasicAuthUserInfo(c *gin.Context, basicRes context.BasicRes) (*common.User, error) {
	...
	userInfo := strings.Split(string(userInfoData), ":")
	if len(userInfo) != 2 {
		return nil, errors.Default.New("invalid user info data")
	}
	return &common.User{Name: userInfo[0]}, nil
}

#8854 added auth.RequireAuth() right after it (backend/server/api/api.go):

router.Use(RestAuthentication(router, basicRes))
router.Use(RequirePushAuthentication(basicRes))
router.Use(auth.OIDCAuthentication())
router.Use(OAuth2ProxyAuthentication(basicRes))
router.Use(auth.RequireAuth())

RequireAuth only asks whether a user is set, so the unverified Basic username now satisfies the gate. #8880 closed the same hole for X-Forwarded-User by requiring FORWARDED_USER_SECRET, but left the Basic branch as is.

Any deployment that exposes the lake directly with AUTH_ENABLED=true (the documented setup for native OIDC, where config-ui runs without ADMIN_USER/ADMIN_PASS) is affected: blueprints, connections (with stored tokens), pipelines and API keys are reachable and writable without signing in. CSRFProtect does not apply either, since the request carries no session cookie.

What do you expect to happen

With AUTH_ENABLED=true the lake is the authenticator. Only a valid session cookie, a valid API key, or forwarded headers with the matching FORWARDED_USER_SECRET should produce a user. A Basic header the lake cannot verify must not.

How to reproduce

Lake with AUTH_ENABLED=true, OIDC_ENABLED=true, one provider configured, reachable directly (not through config-ui nginx):

curl -s -o /dev/null -w '%{http_code}\n' "$LAKE/blueprints?page=1&pageSize=1"
# 401
curl -s -o /dev/null -w '%{http_code}\n' -u 'anyone:anything' "$LAKE/blueprints?page=1&pageSize=1"
# 200, full blueprint list
curl -s -o /dev/null -w '%{http_code}\n' -H 'Authorization: Bearer nope' "$LAKE/blueprints?page=1&pageSize=1"
# 401

Authorization: Basic Og== (empty user) and a non-base64 value give 401, so it is the decoded username alone that authenticates.

Anything else

Every time, on every non-public route. Verified on v1.0.3-beta17 (8fe26f4); middlewares.go is unchanged on main. Present since v1.0.3-beta13, the first release with #8854.

Fix I propose: consult the Basic header only when AUTH_ENABLED is off, which is the legacy nginx mode. With AUTH_ENABLED the supported callers are already what auth.go logs: "only API-key/proxy auth will work". Deployments that still front the lake with nginx Basic auth and also set AUTH_ENABLED=true can move to FORWARDED_USER_SECRET. A 9-line change plus tests; the bypass test fails on current code. Running as a local patch on our instance since 2026-09-17.

Version

v1.0.3-beta17 (8fe26f4), same code on main.

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions