Skip to content

Commit

Permalink
feat: refresh project authorities for internal tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
matteo-s committed Oct 8, 2024
1 parent e904839 commit e6343df
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -122,7 +124,9 @@ public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exce
keyStoreConfig.getJWKSetKeyStore().getJwk()
)
);
coreJwtAuthProvider.setJwtAuthenticationConverter(coreJwtAuthenticationConverter("authorities"));
coreJwtAuthProvider.setJwtAuthenticationConverter(
coreJwtAuthenticationConverter("authorities", projectAuthHelper)
);

// Create authentication Manager
securityChain.oauth2ResourceServer(oauth2 ->
Expand Down Expand Up @@ -340,12 +344,15 @@ public static JwtDecoder coreJwtDecoder(String issuer, String audience, JWK jwk)
return jwtDecoder;
}

public static JwtAuthenticationConverter coreJwtAuthenticationConverter(String claim) {
public static JwtAuthenticationConverter coreJwtAuthenticationConverter(
String claim,
AuthorizableAwareEntityService<Project> projectAuthHelper
) {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter((Jwt source) -> {
if (source == null) return null;

List<GrantedAuthority> authorities = new ArrayList<>();
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

if (StringUtils.hasText(claim) && source.hasClaim(claim)) {
Expand All @@ -358,7 +365,27 @@ public static JwtAuthenticationConverter coreJwtAuthenticationConverter(String c
}
}

//TODO evaluate refreshing project authorities via helper
//refresh project authorities via helper
if (projectAuthHelper != null && StringUtils.hasText(source.getSubject())) {
String username = source.getSubject();

//inject roles from ownership of projects
projectAuthHelper
.findIdsByCreatedBy(username)
.forEach(p -> {
//derive a scoped ADMIN role
authorities.add(new SimpleGrantedAuthority(p + ":ROLE_ADMIN"));
});

//inject roles from sharing of projects
projectAuthHelper
.findIdsBySharedTo(username)
.forEach(p -> {
//derive a scoped USER role
//TODO make configurable?
authorities.add(new SimpleGrantedAuthority(p + ":ROLE_USER"));
});
}

return authorities;
});
Expand Down Expand Up @@ -392,7 +419,7 @@ public static JwtAuthenticationConverter externalJwtAuthenticationConverter(
converter.setJwtGrantedAuthoritiesConverter((Jwt source) -> {
if (source == null) return null;

List<GrantedAuthority> authorities = new ArrayList<>();
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

//read roles from token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import it.smartcommunitylabdhub.commons.config.SecurityProperties;
import it.smartcommunitylabdhub.commons.config.SecurityProperties.JwtAuthenticationProperties;
import it.smartcommunitylabdhub.commons.models.entities.project.Project;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -43,7 +44,6 @@
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
Expand Down Expand Up @@ -92,13 +92,8 @@ public void afterPropertiesSet() throws Exception {
Assert.notNull(jwkSetKeyStore, "jwks store is required");
Assert.notNull(jwkSetKeyStore.getJwk(), "jwk is required");

JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
authoritiesConverter.setAuthoritiesClaimName("authorities");
authoritiesConverter.setAuthorityPrefix("");
jwtConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);

//build auth provider to validate tokens
JwtAuthenticationConverter jwtConverter = coreJwtAuthenticationConverter("authorities", projectAuthHelper);
accessTokenAuthProvider = new JwtAuthenticationProvider(coreJwtDecoder(jwkSetKeyStore.getJwk(), false));
accessTokenAuthProvider.setJwtAuthenticationConverter(jwtConverter);
refreshTokenAuthProvider = new JwtAuthenticationProvider(coreJwtDecoder(jwkSetKeyStore.getJwk(), true));
Expand Down Expand Up @@ -346,7 +341,7 @@ public static JwtAuthenticationConverter externalJwtAuthenticationConverter(
converter.setJwtGrantedAuthoritiesConverter((Jwt source) -> {
if (source == null) return null;

List<GrantedAuthority> authorities = new ArrayList<>();
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

//read roles from token
Expand Down Expand Up @@ -390,4 +385,52 @@ public static JwtAuthenticationConverter externalJwtAuthenticationConverter(
converter.setPrincipalClaimName(usernameClaim);
return converter;
}

public static JwtAuthenticationConverter coreJwtAuthenticationConverter(
String claim,
AuthorizableAwareEntityService<Project> projectAuthHelper
) {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter((Jwt source) -> {
if (source == null) return null;

Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

if (StringUtils.hasText(claim) && source.hasClaim(claim)) {
List<String> roles = source.getClaimAsStringList(claim);
if (roles != null) {
roles.forEach(r -> {
//use as is
authorities.add(new SimpleGrantedAuthority(r));
});
}
}

//refresh project authorities via helper
if (projectAuthHelper != null && StringUtils.hasText(source.getSubject())) {
String username = source.getSubject();

//inject roles from ownership of projects
projectAuthHelper
.findIdsByCreatedBy(username)
.forEach(p -> {
//derive a scoped ADMIN role
authorities.add(new SimpleGrantedAuthority(p + ":ROLE_ADMIN"));
});

//inject roles from sharing of projects
projectAuthHelper
.findIdsBySharedTo(username)
.forEach(p -> {
//derive a scoped USER role
//TODO make configurable?
authorities.add(new SimpleGrantedAuthority(p + ":ROLE_USER"));
});
}

return authorities;
});
return converter;
}
}

0 comments on commit e6343df

Please sign in to comment.