Skip to content

Conversation

@AndyJiang99
Copy link

@AndyJiang99 AndyJiang99 commented Oct 23, 2025

Description

At LinkedIn, we need to be able to use multiple different authentication mechanisms, similar to the Trino Server itself, as we would like to:

  1. Enable our internal users to authenticate via SSO
  2. Enable some automated system interactions with Trino Gateway which does not have a human-in-the-loop, and thus, would need another method to performing administrative actions such as activating/deactivating Trino clusters on Trino Gateway.

This PR has the following changes:

  1. Change defaultType authentication to a list, to enable fallback authentications. This change allows for multiple authentication methods similar to trinodb/trino authentication: https://trino.io/docs/current/security/authentication-types.html
  2. UI enables only the first authentication in the defaultType, even if there are multiple authentication methods set.
  3. All users that log in, if they do not exist in authorization, and defaultPrivilege is set, they will be given the permission of defined in defaultPrivilege. This resolves the issue for OAuth authentications for large enterprises using Trino Gateway as they cannot add every single user to have USER permissions by default.

This PR is related to : #616

Additional context and related issues

Configurations

serverConfig:
  [...]

authentication:
  defaultTypes: ["oauth","form"]
  oauth:
    issuer: "[....]"
  form:
    [....]

presetUsers:
  admin:
    password: admin
    privileges: ADMIN_USER_API
  trinoUser:
    password: trinoUserPassword
    privileges: USER

authorization:
  defaultPrivilege: "USER"
  admin: (.*)ADMIN(.*)
  user: (.*)USER(.*)
  api: (.*)API(.*)

UI View with defaultPrivilege

  1. Login screen with OAuth
489212012-332754a9-7b26-4e40-9b49-df12efdbeeaf
  1. As andjiang is nto in the presetUsers list, defaults over to USER permissions so can only view history
489212036-2af810e1-ff81-445d-913e-a475a2dc5722

API Calls with OAuth enabled:

  1. Query API endpoing for all backends
489212143-9a8720c0-c8b7-4248-bbfa-d1faea27ae19
  1. Deactivate one backend with admin account
489212155-6ce2a988-8060-49c4-bbc0-70835b199f84
  1. API with deactivate trino-adhoc1
489212176-0eca1532-0c10-4498-afda-cb6952dd4012

Release notes

( ) This is not user-visible or is docs only, and no release notes are required.
( x ) Release notes are required, with the following suggested text:

* Trino Gateway now supports multiple authentication mechanisms via fallbacks. The first authentication in the list is rendered on the UI itself.
* Change configuration `defaultType` to `defaultTypes` and changes the type from a `string` to a `List<String>`.
* Add a new configuration of `defaultPrivilege` to enable large enterprise customers to have admins and all remaining accounts logging in via SSO would default to `USER` privilege

Summary by Sourcery

Enable support for multiple authentication methods in Trino Gateway HA by replacing the single defaultType with a prioritized list (defaultTypes), add fallbacks for BasicAuth API calls alongside OAuth/form login, and introduce a defaultPrivilege setting to automatically assign permissions to users not explicitly configured. Centralize OIDC test setup and add new tests for authorization and authentication fallback behaviors.

New Features:

  • Support multiple authentication mechanisms via a prioritized defaultTypes list with fallback order
  • Introduce defaultPrivilege configuration to grant default permissions to new SSO users
  • Expose loginType endpoint returning the ordered list of enabled authentication methods

Enhancements:

  • Add BasicAuth filter fallback for API calls under form authentication
  • Refactor and centralize OIDC container and HTTP client setup in test utilities

Build:

  • Add docker-java-api test dependency for containerized testing

Documentation:

  • Update security documentation to use defaultTypes list and describe fallback behavior

Tests:

  • Add unit tests for AuthorizationManager defaultPrivilege logic
  • Add integration tests for authentication fallback between OAuth and form methods

@cla-bot
Copy link

cla-bot bot commented Oct 23, 2025

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Andy Jiang.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email [email protected]
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@sourcery-ai
Copy link

sourcery-ai bot commented Oct 23, 2025

Reviewer's Guide

This PR enhances authentication to support multiple fallback methods, adds a default-privilege mechanism for new users, refactors OIDC test setup into reusable utilities, and updates the UI and docs accordingly.

Sequence diagram for authentication fallback logic

sequenceDiagram
participant "Client"
participant "ChainedAuthFilter"
participant "LbFilter (OAuth)"
participant "LbFilter (Form)"
participant "BasicAuthFilter (Form API)"

Client->>ChainedAuthFilter: Send authentication request
ChainedAuthFilter->>"LbFilter (OAuth)": Try OAuth authentication
alt OAuth fails
    ChainedAuthFilter->>"LbFilter (Form)": Try Form authentication
    alt Form fails
        ChainedAuthFilter->>"BasicAuthFilter (Form API)": Try Basic Auth (Form API)
    end
end
Loading

Class diagram for updated AuthenticationConfiguration and AuthorizationConfiguration

classDiagram
class AuthenticationConfiguration {
  +List<String> defaultTypes
  +OAuthConfiguration oauth
  +FormAuthConfiguration form
  +getDefaultTypes()
  +setDefaultTypes(List<String>)
}
class AuthorizationConfiguration {
  +String admin
  +String user
  +String api
  +String ldapConfigPath
  +String defaultPrivilege
  +getDefaultPrivilege()
  +setDefaultPrivilege(String)
}
AuthenticationConfiguration --> OAuthConfiguration
AuthenticationConfiguration --> FormAuthConfiguration
Loading

Class diagram for updated AuthorizationManager privilege logic

classDiagram
class AuthorizationManager {
  -Map<String, UserConfiguration> presetUsers
  -LbLdapClient lbLdapClient
  -AuthorizationConfiguration authorizationConfiguration
  +getPrivileges(String username)
}
AuthorizationManager --> AuthorizationConfiguration
AuthorizationManager --> LbLdapClient
Loading

File-Level Changes

Change Details Files
Enable multiple authentication methods via a list-based fallback
  • Change defaultType (string) to defaultTypes (List) in AuthenticationConfiguration
  • Iterate over defaultTypes in HaGatewayProviderModule to register OAuth, form, and basic-auth filters
  • Modify LoginResource to return a list of loginTypes instead of a single type
AuthenticationConfiguration.java
HaGatewayProviderModule.java
LoginResource.java
Assign default privileges to users not in presetUsers
  • Add defaultPrivilege field in AuthorizationConfiguration
  • Update AuthorizationManager.getPrivileges to return defaultPrivilege when no explicit privileges found
  • Introduce TestAuthorizationManager to verify default and preset-user privilege behaviors
AuthorizationConfiguration.java
AuthorizationManager.java
TestAuthorizationManager.java
Refactor OIDC test setup and add fallback tests
  • Centralize container setup and HTTP client creation in HaGatewayTestUtils (getTrinoContainer, setupOidc, createOkHttpClient)
  • Simplify TestOIDC by delegating setup and SSL configuration
  • Add TestAuthenticationFallbacks to validate multi-auth UI and API fallbacks
HaGatewayTestUtils.java
TestOIDC.java
TestAuthenticationFallbacks.java
Update UI and documentation for multi-auth and default-privilege
  • Adjust login.tsx to handle list of loginTypes and pick the first for rendering
  • Revise security.md and sample YAML to use defaultTypes list and describe priority/fallback behavior
login.tsx
docs/security.md

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java:178` </location>
<code_context>
+                                new LbUnauthorizedHandler("form")));
+                    }
+                }
+                default -> {}
+            }
         }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Default case in switch silently ignores unknown auth methods.

Logging a warning or error in the default case would help identify misconfigurations involving unsupported authentication methods.

Suggested implementation:

```java
        for (String authMethod : authMethods) {
            switch (authMethod) {
                case "oauth" -> {

```

```java
                default -> {
                    logger.warn("Unknown authentication method configured: {}", authMethod);
                }

```

If the `logger` variable is not already defined in this file, you should add it at the top of the class:

```java
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HaGatewayProviderModule.class);
```

Place this line with other field declarations in the class.
</issue_to_address>

### Comment 2
<location> `gateway-ha/src/main/java/io/trino/gateway/ha/security/AuthorizationManager.java:55-56` </location>
<code_context>
         }
-        return Optional.ofNullable(privs);
+
+        if (privs == null || privs.trim().isEmpty()) {
+            if (authorizationConfiguration != null && authorizationConfiguration.getDefaultPrivilege() != null) {
+                return Optional.of(authorizationConfiguration.getDefaultPrivilege());
+            }
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Default privilege fallback may mask misconfigurations.

Log fallback events to alert administrators to missing privilege assignments.

Suggested implementation:

```java
        this.presetUsers = presetUsers;
        this.authorizationConfiguration = configuration;
        if (configuration != null && configuration.getLdapConfigPath() != null) {
            lbLdapClient = new LbLdapClient(LdapConfiguration.load(configuration.getLdapConfigPath()));
        }
        else if (lbLdapClient != null) {
            privs = lbLdapClient.getMemberOf(username);
        }

        // Add logger for fallback events
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuthorizationManager.class);

```

```java
        if (privs == null || privs.trim().isEmpty()) {
            if (authorizationConfiguration != null && authorizationConfiguration.getDefaultPrivilege() != null) {
                log.warn("Privilege for user '{}' is missing or empty. Falling back to default privilege: '{}'. Please check privilege assignments.", username, authorizationConfiguration.getDefaultPrivilege());
                return Optional.of(authorizationConfiguration.getDefaultPrivilege());
            }
            return Optional.empty(); // No default privilege if not configured

```

If the logger is already defined elsewhere in the class, do not redefine it. Place the logger definition at the top of the class if needed.
</issue_to_address>

### Comment 3
<location> `docs/security.md:39` </location>
<code_context>
 `authentication:` section in the config file. The default authentication type is
-set using `defaultType: "form"` Following types of the authentications are
-supported.
+set using `defaultTypes: ["form"]`. The first authentication type in `defaultTypes` is prioritized and then falls back to following ones.
+Following types of the authentications are supported.

</code_context>

<issue_to_address>
**suggestion (typo):** Consider revising 'falls back to following ones' to 'falls back to the following ones' for grammatical correctness.

Adding 'the' before 'following ones' improves clarity and grammatical accuracy.

```suggestion
set using `defaultTypes: ["form"]`. The first authentication type in `defaultTypes` is prioritized and then falls back to the following ones.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

new LbUnauthorizedHandler("form")));
}
}
default -> {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Default case in switch silently ignores unknown auth methods.

Logging a warning or error in the default case would help identify misconfigurations involving unsupported authentication methods.

Suggested implementation:

        for (String authMethod : authMethods) {
            switch (authMethod) {
                case "oauth" -> {
                default -> {
                    logger.warn("Unknown authentication method configured: {}", authMethod);
                }

If the logger variable is not already defined in this file, you should add it at the top of the class:

private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HaGatewayProviderModule.class);

Place this line with other field declarations in the class.

Comment on lines +55 to +56
if (privs == null || privs.trim().isEmpty()) {
if (authorizationConfiguration != null && authorizationConfiguration.getDefaultPrivilege() != null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 suggestion (security): Default privilege fallback may mask misconfigurations.

Log fallback events to alert administrators to missing privilege assignments.

Suggested implementation:

        this.presetUsers = presetUsers;
        this.authorizationConfiguration = configuration;
        if (configuration != null && configuration.getLdapConfigPath() != null) {
            lbLdapClient = new LbLdapClient(LdapConfiguration.load(configuration.getLdapConfigPath()));
        }
        else if (lbLdapClient != null) {
            privs = lbLdapClient.getMemberOf(username);
        }

        // Add logger for fallback events
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuthorizationManager.class);
        if (privs == null || privs.trim().isEmpty()) {
            if (authorizationConfiguration != null && authorizationConfiguration.getDefaultPrivilege() != null) {
                log.warn("Privilege for user '{}' is missing or empty. Falling back to default privilege: '{}'. Please check privilege assignments.", username, authorizationConfiguration.getDefaultPrivilege());
                return Optional.of(authorizationConfiguration.getDefaultPrivilege());
            }
            return Optional.empty(); // No default privilege if not configured

If the logger is already defined elsewhere in the class, do not redefine it. Place the logger definition at the top of the class if needed.

`authentication:` section in the config file. The default authentication type is
set using `defaultType: "form"` Following types of the authentications are
supported.
set using `defaultTypes: ["form"]`. The first authentication type in `defaultTypes` is prioritized and then falls back to following ones.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Consider revising 'falls back to following ones' to 'falls back to the following ones' for grammatical correctness.

Adding 'the' before 'following ones' improves clarity and grammatical accuracy.

Suggested change
set using `defaultTypes: ["form"]`. The first authentication type in `defaultTypes` is prioritized and then falls back to following ones.
set using `defaultTypes: ["form"]`. The first authentication type in `defaultTypes` is prioritized and then falls back to the following ones.

@cla-bot
Copy link

cla-bot bot commented Oct 23, 2025

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Andy Jiang.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email [email protected]
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

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

Development

Successfully merging this pull request may close these issues.

1 participant