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]

Reply via email to