fix: merged
This commit is contained in:
@ -1,29 +1,15 @@
|
||||
package enseirb.myinpulse;
|
||||
|
||||
import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.jwt.*;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyinpulseApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyinpulseApplication.class, args);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyinpulseApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
@ -22,21 +22,21 @@ public class GetUserInfo {
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random")
|
||||
public boolean rand(){
|
||||
public boolean rand() {
|
||||
System.err.println("HELLO");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random2")
|
||||
public boolean rand2(){
|
||||
public boolean rand2() {
|
||||
System.err.println("HELLO2");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random3")
|
||||
public boolean rand3(){
|
||||
public boolean rand3() {
|
||||
System.err.println("HELLO");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
|
@ -23,10 +23,13 @@ public class WebSecurityCustomConfiguration {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(List.of("*"));
|
||||
configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
|
||||
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type",
|
||||
"x-auth-token")); // Do not remove, this fixes the CORS errors when unauthenticated
|
||||
UrlBasedCorsConfigurationSource source = new
|
||||
UrlBasedCorsConfigurationSource();
|
||||
configuration.setAllowedHeaders(
|
||||
Arrays.asList(
|
||||
"authorization",
|
||||
"content-type",
|
||||
"x-auth-token")); // Do not remove, this fixes the CORS errors when
|
||||
// unauthenticated
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
|
||||
return source;
|
||||
@ -34,17 +37,23 @@ public class WebSecurityCustomConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers("/random2").access(hasRole("REALM_MyINPulse-entrepreneur"))
|
||||
.requestMatchers("/random").access(hasRole("REALM_MyINPulse-admin"))
|
||||
.requestMatchers("/random3").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2ResourceServer(oauth2 -> oauth2
|
||||
.jwt(jwt -> jwt.
|
||||
jwtAuthenticationConverter(new KeycloakJwtRolesConverter())));
|
||||
http.authorizeHttpRequests(
|
||||
authorize ->
|
||||
authorize
|
||||
.requestMatchers("/random2")
|
||||
.access(hasRole("REALM_MyINPulse-entrepreneur"))
|
||||
.requestMatchers("/random")
|
||||
.access(hasRole("REALM_MyINPulse-admin"))
|
||||
.requestMatchers("/random3")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.oauth2ResourceServer(
|
||||
oauth2 ->
|
||||
oauth2.jwt(
|
||||
jwt ->
|
||||
jwt.jwtAuthenticationConverter(
|
||||
new KeycloakJwtRolesConverter())));
|
||||
return http.build();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,40 +16,35 @@ import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
|
||||
public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
|
||||
/**
|
||||
* Prefix used for realm level roles.
|
||||
*/
|
||||
/** Prefix used for realm level roles. */
|
||||
public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
|
||||
/**
|
||||
* Prefix used in combination with the resource (client) name for resource level roles.
|
||||
*/
|
||||
|
||||
/** Prefix used in combination with the resource (client) name for resource level roles. */
|
||||
public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
|
||||
|
||||
/**
|
||||
* Name of the claim containing the realm level roles
|
||||
*/
|
||||
/** Name of the claim containing the realm level roles */
|
||||
private static final String CLAIM_REALM_ACCESS = "realm_access";
|
||||
/**
|
||||
* Name of the claim containing the resources (clients) the user has access to.
|
||||
*/
|
||||
|
||||
/** Name of the claim containing the resources (clients) the user has access to. */
|
||||
private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
|
||||
/**
|
||||
* Name of the claim containing roles. (Applicable to realm and resource level.)
|
||||
*/
|
||||
|
||||
/** Name of the claim containing roles. (Applicable to realm and resource level.) */
|
||||
private static final String CLAIM_ROLES = "roles";
|
||||
|
||||
@Override
|
||||
public AbstractAuthenticationToken convert(Jwt source)
|
||||
{
|
||||
return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
|
||||
.stream(), TEMPORARNAME(source).stream())
|
||||
.collect(toSet()));
|
||||
public AbstractAuthenticationToken convert(Jwt source) {
|
||||
return new JwtAuthenticationToken(
|
||||
source,
|
||||
Stream.concat(
|
||||
new JwtGrantedAuthoritiesConverter().convert(source).stream(),
|
||||
TEMPORARNAME(source).stream())
|
||||
.collect(toSet()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the realm and resource level roles from a JWT token distinguishing between them using prefixes.
|
||||
* Extracts the realm and resource level roles from a JWT token distinguishing between them
|
||||
* using prefixes.
|
||||
*/
|
||||
public Collection<GrantedAuthority> TEMPORARNAME(Jwt jwt) {
|
||||
// Collection that will hold the extracted roles
|
||||
@ -66,33 +61,43 @@ public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthent
|
||||
// Check if any roles are present
|
||||
if (roles != null && !roles.isEmpty()) {
|
||||
// Iterate of the roles and add them to the granted authorities
|
||||
Collection<GrantedAuthority> realmRoles = roles.stream()
|
||||
// Prefix all realm roles with "ROLE_realm_"
|
||||
.map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
|
||||
.collect(Collectors.toList());
|
||||
Collection<GrantedAuthority> realmRoles =
|
||||
roles.stream()
|
||||
// Prefix all realm roles with "ROLE_realm_"
|
||||
.map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
|
||||
.collect(Collectors.toList());
|
||||
grantedAuthorities.addAll(realmRoles);
|
||||
}
|
||||
}
|
||||
|
||||
// Resource (client) roles
|
||||
// A user might have access to multiple resources all containing their own roles. Therefore, it is a map of
|
||||
// A user might have access to multiple resources all containing their own roles. Therefore,
|
||||
// it is a map of
|
||||
// resource each possibly containing a "roles" property.
|
||||
Map<String, Map<String, Collection<String>>> resourceAccess = jwt.getClaim(CLAIM_RESOURCE_ACCESS);
|
||||
Map<String, Map<String, Collection<String>>> resourceAccess =
|
||||
jwt.getClaim(CLAIM_RESOURCE_ACCESS);
|
||||
|
||||
// Check if resources are assigned
|
||||
if (resourceAccess != null && !resourceAccess.isEmpty()) {
|
||||
// Iterate of all the resources
|
||||
resourceAccess.forEach((resource, resourceClaims) -> {
|
||||
// Iterate of the "roles" claim inside the resource claims
|
||||
resourceClaims.get(CLAIM_ROLES).forEach(
|
||||
// Add the role to the granted authority prefixed with ROLE_ and the name of the resource
|
||||
role -> grantedAuthorities.add(new SimpleGrantedAuthority(PREFIX_RESOURCE_ROLE + resource + "_" + role))
|
||||
);
|
||||
});
|
||||
resourceAccess.forEach(
|
||||
(resource, resourceClaims) -> {
|
||||
// Iterate of the "roles" claim inside the resource claims
|
||||
resourceClaims
|
||||
.get(CLAIM_ROLES)
|
||||
.forEach(
|
||||
// Add the role to the granted authority prefixed with ROLE_
|
||||
// and the name of the resource
|
||||
role ->
|
||||
grantedAuthorities.add(
|
||||
new SimpleGrantedAuthority(
|
||||
PREFIX_RESOURCE_ROLE
|
||||
+ resource
|
||||
+ "_"
|
||||
+ role)));
|
||||
});
|
||||
}
|
||||
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
@SpringBootTest
|
||||
class MyinpulseApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextLoads() {}
|
||||
}
|
||||
|
Reference in New Issue
Block a user