disizwil commented on issue #70437:
URL: https://github.com/apache/doris/issues/70437#issuecomment-6765127934
Thanks for the detailed source-level triage. Here is the requested runtime
confirmation, done on a single FE pod reached directly (kubectl port-forward to
the pod, no load balancer or ingress in between), so the MySQL and HTTP tests
hit the same FE process.
### Build
- FE image:
`apache/doris:fe-4.1.5@sha256:bd0149d76fd02429ee4ab751f34c16948fbf761a886070489fdebf7b2069305c`
- `SHOW FRONTENDS`: `doris-4.1.5-release-917b20be838` (same commit as your
analysis)
- Doris Kubernetes operator: `apache/doris:operator-latest`
(`sha256:3a44226565923f33ac11334410b4ad4b7a082a8a0895b32f1548c7dff913c9a2`)
- Single FE (FOLLOWER, master), amd64
### Authentication settings (non-secret, anonymized)
```
authentication_type = ldap
authentication_chain = (empty)
access_controller_type = default (no external authorization provider)
ldap_authentication_enabled = true
ldap_host = ldap.example.com
ldap_port = 636
ldap_use_ssl = true
ldap_admin_name = cn=bind,ou=users,dc=example,dc=com
ldap_user_basedn = ou=users,dc=example,dc=com
ldap_group_basedn = ou=users,dc=example,dc=com
ldap_user_filter =
(|(userPrincipalName={login})(userPrincipalName={login}@example.com))
ldap_allow_empty_pass = false
ldap_user_cache_timeout_s = 300
ldap_default_roles = []
```
LDAP server: Microsoft Entra Domain Services (managed AD), LDAPS.
### Preconditions
- No local identity for the test user: it was dropped (`DROP USER
'ldap_user'@'%'`), and `SHOW ALL GRANTS` then contains no row matching the
username (checked on a substring, not the exact form).
- `REFRESH LDAP ALL;` executed right before each HTTP attempt, to rule out
the LDAP cache.
- No browser session open during the test.
### Results (timestamps UTC)
| # | Path | Login form | Password | Result |
|---|------|-----------|----------|--------|
| A | MySQL `--enable-cleartext-plugin` | `[email protected]` | correct
| OK. `CURRENT_USER()` = `'[email protected]'@'127.0.0.1'`, roles
`group_a,ldapDefaultRole` (temporary identity) |
| B1 | `POST /rest/v1/login` (Basic) | `ldap_user` | correct | 10:21:58:
`{"msg":"Internal Error","code":500}` |
| B2 | `POST /rest/v1/login` (Basic) | `[email protected]` | correct |
10:29:52: `{"msg":"Internal Error","code":500}` |
| C | `POST /rest/v1/login` (Basic) | `ldap_user` | **wrong** |
`{"code":401,"data":"Access denied for user '[email protected]' (using
password: YES)"}` |
| D | `POST /rest/v1/login` (Basic) | `ldap_user` | correct, **with** a
local identity `'ldap_user'@'%'` present | `{"msg":"Login
success!","code":200}` |
Notes:
- The HTTP status is 200 in every case; the error is only in the JSON `code`
field.
- C fails earlier (`checkPassword:282`), so the 500 in B1/B2 only happens
**after** a successful LDAP credential check.
- D confirms the identity-resolution gap: once a local identity with the
short name exists, the same LDAP credentials succeed. This is the workaround we
used until now.
- In both B1 and B2, the HTTP path appears to work with the part before `@`
(see the username in C), whereas the MySQL path keeps the full UPN.
### FE log for B1 (fe.warn.log, trimmed to Doris frames)
```
2026-11-10 10:21:58,604 WARN (qtp1172763770-225|225)
[RestApiExceptionHandler.unexpectedExceptionHandler():61] unexpected exception
java.lang.IllegalStateException
at
com.google.common.base.Preconditions.checkState(Preconditions.java:499)
at
org.apache.doris.httpv2.controller.BaseController.checkPassword(BaseController.java:284)
at
org.apache.doris.httpv2.controller.BaseController.checkWithCookie(BaseController.java:78)
at
org.apache.doris.httpv2.controller.LoginController.login(LoginController.java:41)
... (Spring / Jetty frames)
```
B2 at 10:29:52 produced an identical trace.
For C:
```
org.apache.doris.httpv2.exception.UnauthorizedException: Access denied for
user '[email protected]' (using password: YES)
at
org.apache.doris.httpv2.controller.BaseController.checkPassword(BaseController.java:282)
at
org.apache.doris.httpv2.controller.BaseController.checkWithCookie(BaseController.java:78)
```
### LDAP-to-role mapping (for the separate message issue)
- LDAP group `group_a` maps to the existing Doris role `group_a` (same name).
- `group_a` has no global privileges; in particular it has no `ADMIN_PRIV` /
`NODE_PRIV`.
- `ldapDefaultRole`: `SELECT` on `internal.information_schema` and
`internal.mysql`.
Earlier (with the local identity in place), the user could log in, but admin
pages showed the "login information has expired" dialog, and the FE logged:
```
org.apache.doris.httpv2.exception.UnauthorizedException: Cookie is invalid
at
org.apache.doris.httpv2.controller.BaseController.checkWithCookie(BaseController.java:110)
at
org.apache.doris.httpv2.controller.BaseController.checkAuthWithCookie(BaseController.java:68)
```
This matches your analysis: a privilege denial reported as an expired
session.
Happy to test a patch or a snapshot build on this environment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]