Skip to content

Commit

Permalink
Use regex expression for lb authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaho12 committed Oct 11, 2023
1 parent ef77b29 commit ced88bb
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 18 deletions.
26 changes: 15 additions & 11 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,39 +73,43 @@ authentication:

### Form/LDAP

LDAP requires both random key pair and config path for LDAP

```
authentication:
defaultType: "form"
form:
ldapConfigPath: <ldap_config_path>
selfSignKeyPair:
privateKeyRsa: <private_key_path>
publicKeyRsa: <public_key_path>
```


## Authorization

The roles supported by trino load balancer
The roles in regex string format are supported by trino load balancer

- admin : Allows access to the Editor tab, which can be used to configure the
- admin : Allow access to the Editor tab, which can be used to configure the
backends

- user : Allows access to the rest of the website

- api : Allows access to to rest apis to configure the backends
- api : Allows access to rest apis to configure the backends

Users with attributes next to the role will be giving those privileges the
users. User attributes from LDAP is supported or you can use the preset users
defined in the yaml file. Authorization is supported via LDAP user attributes
users. You can use the preset users defined in the yaml file.
LDAP Authorization is also supported by adding user attribute configs in file.

- Check out [LDAPTestConfig.yml](https://github.com/trinodb/trino-gateway/blob/main/gateway-ha/src/test/resources/auth/ldapTestConfig.yml) file for config details

```
# Roles should be in regex format
authorization:
admin: 'lb_admin'
user: 'lb_user'
api: "lb_api"
ldapHost:
ldapPort:
ldapBindDn:
ldapSearch:
ldapPassword:
api: 'lb_api'
ldapConfigPath: <ldap_config_path>
```


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ public LbAuthorizer(AuthorizationConfiguration configuration) {
public boolean authorize(LbPrincipal principal, String role) {
switch (role) {
case "ADMIN":
log.info("User {} identified as ADMIN", principal.getName());
log.info("User '{}' identified as ADMIN", principal.getName());
return principal.getMemberOf()
.filter(m -> m.contains(configuration.getAdmin()))
.filter(m -> m.matches(configuration.getAdmin()))
.isPresent();
case "USER":
log.info("User {} identified as USER", principal.getName());
log.info("User '{}' identified as USER", principal.getName());
return principal.getMemberOf()
.filter(m -> m.contains(configuration.getUser()))
.filter(m -> m.matches(configuration.getUser()))
.isPresent();
case "API":
log.info("User {} identified as USER", principal.getName());
log.info("User '{}' identified as API", principal.getName());
return principal.getMemberOf()
.filter(m -> m.contains(configuration.getApi()))
.filter(m -> m.matches(configuration.getApi()))
.isPresent();
default:
log.warn("User {} is neither member of {} or of {} based on ldap search",
log.warn("User '{}' has no regex match with '{}' or '{}' based on ldap search",
principal.getName(),
configuration.getAdmin(),
configuration.getUser());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package io.trino.gateway.ha.security;

import io.trino.gateway.ha.config.AuthorizationConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.Optional;
import java.util.regex.PatternSyntaxException;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@Slf4j
public class TestLbAuthorizer {
private static final String USER = "username";
private static LbPrincipal principal;
private static LbAuthorizer authorizer;
private static AuthorizationConfiguration configuration;
private static final String ADMIN_ROLE = "ADMIN";
private static final String USER_ROLE = "USER";
private static final String API_ROLE = "API";
private static final String UNKNOWN_ROLE = "UNKNOWN";

private static final String PVFX_DATA_31 = "PVFX_DATA_31";

@BeforeAll
public static void setup() {
configuration = new AuthorizationConfiguration();
}
static void match(String member_of, String conf, String role, boolean expectedToMatch) {
principal = new LbPrincipal(USER, Optional.of(member_of));
if (role.equalsIgnoreCase(ADMIN_ROLE)){
configuration.setAdmin(conf);
authorizer = new LbAuthorizer(configuration);
}

if (role.equalsIgnoreCase(USER_ROLE)) {
configuration.setUser(conf);
authorizer = new LbAuthorizer(configuration);
}
if (role.equalsIgnoreCase(API_ROLE)) {
configuration.setApi(conf);
authorizer = new LbAuthorizer(configuration);
}
// UNKNOWN ROLE should always return FALSE

if (expectedToMatch) {
assertTrue(authorizer.authorize(principal, role));
} else {
assertFalse(authorizer.authorize(principal, role));
}
}

static void assertMatch(String member_of, String conf, String role) {
match(member_of, conf, role, true);
}
static void assertNotMatch(String member_of, String conf, String role) {
match(member_of, conf, role, false);
}

static void assertBadPattern(String member_of, String conf, String role) {
log.info("Compile bad pattern {}", conf);
try {
match(member_of, conf, role, false);
} catch (PatternSyntaxException e) {
log.info("Failed to compile ==> OKAY");
}
}

@Test
public void testBasic() throws Exception {
assertMatch(PVFX_DATA_31, PVFX_DATA_31, ADMIN_ROLE);
assertNotMatch(PVFX_DATA_31, PVFX_DATA_31, UNKNOWN_ROLE);
assertNotMatch(PVFX_DATA_31, "PVFX", USER_ROLE);
assertNotMatch(PVFX_DATA_31, "DATA", API_ROLE);
assertNotMatch(PVFX_DATA_31, "31", ADMIN_ROLE);
}

@Test
public void testZeroOrMoreCharacters() throws Exception {
assertMatch(PVFX_DATA_31, "PVFX(.*)", ADMIN_ROLE);
assertMatch(PVFX_DATA_31, "(?i)pvfx(.*)", USER_ROLE);
assertMatch(PVFX_DATA_31, "(.*)", API_ROLE);
assertMatch(PVFX_DATA_31, "PVFX_DATA_31(.*)", ADMIN_ROLE);
assertMatch(PVFX_DATA_31, "(.*)_31", USER_ROLE);
assertMatch(PVFX_DATA_31, "(.*)DATA(.*)", API_ROLE);
assertMatch(PVFX_DATA_31, "^.+$", ADMIN_ROLE);
assertNotMatch(PVFX_DATA_31, "^.+$", UNKNOWN_ROLE);
assertNotMatch(PVFX_DATA_31, "(.*)DATA", USER_ROLE);
assertNotMatch(PVFX_DATA_31, "PVFX__(.*)", API_ROLE);
}

@Test
public void testBadPatterns() throws Exception {
assertBadPattern(PVFX_DATA_31, "^[a-zA--Z]+$", ADMIN_ROLE); // bad range
assertBadPattern(PVFX_DATA_31, "^[a-zA-Z+$", USER_ROLE); // missing ]
assertBadPattern(PVFX_DATA_31, "^[a-zA-Z]+$\\", API_ROLE); // nothing to escape
}
}

0 comments on commit ced88bb

Please sign in to comment.