Skip to content

Commit

Permalink
When using isAuthenticated() the JWT token must be signed by a truste…
Browse files Browse the repository at this point in the history
…d issuer (#103)
  • Loading branch information
bjornandre authored Mar 18, 2024
1 parent aa30fc1 commit 7de313b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 3 deletions.
5 changes: 5 additions & 0 deletions conf/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ micronaut:
jwks:
keycloak-staging:
url: 'https://keycloak.staging-bip-app.ssb.no/auth/realms/ssb/protocol/openid-connect/certs'
google:
url: 'https://www.googleapis.com/oauth2/v3/certs'

http:
services:
Expand Down Expand Up @@ -117,6 +119,9 @@ pseudo.secrets:
type: TINK_WDEK

app-roles:
# When using isAuthenticated() the JWT token must be signed by one of the trusted-issuers
trusted-issuers:
- https://keycloak.staging-bip-app.ssb.no/auth/realms/ssb
users:
- isAuthenticated()
admins:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package no.ssb.dlp.pseudo.service.security;

import com.nimbusds.jwt.JWTClaimNames;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.context.annotation.Requirements;
import io.micronaut.context.annotation.Requires;
Expand Down Expand Up @@ -37,11 +38,13 @@ public List<String> resolveRoles(Map<String, Object> attributes) {
List<String> roles = new ArrayList<>();

Object username = attributes.get(tokenConfiguration.getNameKey());
if (rolesConfig.getAdmins().contains(SecurityRule.IS_AUTHENTICATED)
||rolesConfig.getAdmins().contains(username)) {
boolean trustedIssuer = isTrustedIssuer(attributes);
log.debug("User {} has a trusted issuer? {}", username, trustedIssuer);
if (rolesConfig.getAdmins().contains(SecurityRule.IS_AUTHENTICATED) && trustedIssuer
|| rolesConfig.getAdmins().contains(username)) {
roles.add(PseudoServiceRole.ADMIN);
}
if (rolesConfig.getUsers().contains(SecurityRule.IS_AUTHENTICATED)
if (rolesConfig.getUsers().contains(SecurityRule.IS_AUTHENTICATED) && trustedIssuer
|| rolesConfig.getUsers().contains(username)) {
roles.add(PseudoServiceRole.USER);
}
Expand All @@ -63,4 +66,8 @@ public List<String> resolveRoles(Map<String, Object> attributes) {
log.debug("Resolved roles {} for user {}", roles, username);
return roles;
}

private boolean isTrustedIssuer(Map<String, Object> attributes) {
return rolesConfig.getTrustedIssuers().contains(String.valueOf(attributes.get(JWTClaimNames.ISSUER)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@ConfigurationProperties("app-roles")
@Data
public class StaticRolesConfig {
private List<String> trustedIssuers = new ArrayList<>();
private List<String> users = new ArrayList<>();
private List<String> admins = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package no.ssb.dlp.pseudo.service.security;

import com.nimbusds.jwt.JWTClaimNames;
import io.micronaut.security.rules.SecurityRule;
import io.micronaut.security.token.config.TokenConfiguration;
import io.micronaut.security.token.config.TokenConfigurationProperties;
import no.ssb.dlp.pseudo.service.accessgroups.CloudIdentityService;
import no.ssb.dlp.pseudo.service.accessgroups.EntityKey;
import no.ssb.dlp.pseudo.service.accessgroups.Membership;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class CustomRolesFinderTest {

CloudIdentityService cloudIdentityService = mock(CloudIdentityService.class);
StaticRolesConfig rolesConfig = mock(StaticRolesConfig.class);
TokenConfiguration tokenConfig = new TokenConfigurationProperties();
CustomRolesFinder sut = new CustomRolesFinder(tokenConfig, rolesConfig, cloudIdentityService);

@Test
void single_user_gets_no_roles() {
final String email = "john.doe@ssb.no";
assertIterableEquals(List.of(), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}
@Test
void single_user_get_user_role() {
final String email = "john.doe@ssb.no";
when(rolesConfig.getUsers()).thenReturn(List.of(email));
assertIterableEquals(List.of(PseudoServiceRole.USER), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void single_user_get_admin_role() {
final String email = "john.doe@ssb.no";
when(rolesConfig.getAdmins()).thenReturn(List.of(email));
assertIterableEquals(List.of(PseudoServiceRole.ADMIN), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void single_user_get_multiple_roles() {
final String email = "john.doe@ssb.no";
when(rolesConfig.getUsers()).thenReturn(List.of(email));
when(rolesConfig.getAdmins()).thenReturn(List.of(email));
assertIterableEquals(List.of(PseudoServiceRole.ADMIN, PseudoServiceRole.USER), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void group_membership_user_role() {
final String email = "john.doe@ssb.no";
final String user_group = "user-group@ssb.no";
when(rolesConfig.getUsersGroup()).thenReturn(Optional.of(user_group));
when(cloudIdentityService.listMembers(eq(user_group)))
.thenReturn(List.of(new Membership("John Doe", new EntityKey(email, "ssb"))));
assertIterableEquals(List.of(PseudoServiceRole.USER), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void group_membership_admin_role() {
final String email = "john.doe@ssb.no";
final String user_group = "user-group@ssb.no";
when(rolesConfig.getAdminsGroup()).thenReturn(Optional.of(user_group));
when(cloudIdentityService.listMembers(eq(user_group)))
.thenReturn(List.of(new Membership("John Doe", new EntityKey(email, "ssb"))));
assertIterableEquals(List.of(PseudoServiceRole.ADMIN), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void authenticated_user_gets_no_roles_when_issuer_not_trusted() {
final String email = "john.doe@ssb.no";
when(rolesConfig.getUsers()).thenReturn(List.of(SecurityRule.IS_AUTHENTICATED));
assertIterableEquals(List.of(), sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email)));
}

@Test
void authenticated_user_get_user_role_when_issuer_is_trusted() {
final String email = "john.doe@ssb.no";
final String trusted_issuer = "some-issuer-url/auth/realm";
when(rolesConfig.getUsers()).thenReturn(List.of(SecurityRule.IS_AUTHENTICATED));
when(rolesConfig.getTrustedIssuers()).thenReturn(List.of(trusted_issuer));
assertIterableEquals(List.of(PseudoServiceRole.USER),
sut.resolveRoles(Map.of(tokenConfig.getNameKey(), email, JWTClaimNames.ISSUER, trusted_issuer)));
}
}

0 comments on commit 7de313b

Please sign in to comment.