backend-api #6
@@ -3,13 +3,12 @@ package enseirb.myinpulse.api;
 | 
				
			|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
					import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
				
			||||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
					import org.springframework.security.core.context.SecurityContextHolder;
 | 
				
			||||||
import org.springframework.web.bind.annotation.*;
 | 
					import org.springframework.web.bind.annotation.*;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.management.relation.RoleNotFoundException;
 | 
					 | 
				
			||||||
import java.security.Principal;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
					import org.springframework.web.bind.annotation.GetMapping;
 | 
				
			||||||
import org.springframework.web.bind.annotation.RestController;
 | 
					import org.springframework.web.bind.annotation.RestController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.security.Principal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.management.relation.RoleNotFoundException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@SpringBootApplication
 | 
					@SpringBootApplication
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
@@ -26,7 +25,6 @@ public class GetUserInfo {
 | 
				
			|||||||
    @GetMapping("/unauth/random")
 | 
					    @GetMapping("/unauth/random")
 | 
				
			||||||
    public boolean rand(@RequestHeader("Authorization") String token) throws RoleNotFoundException {
 | 
					    public boolean rand(@RequestHeader("Authorization") String token) throws RoleNotFoundException {
 | 
				
			||||||
        System.err.println(token);
 | 
					        System.err.println(token);
 | 
				
			||||||
        System.err.println("HELLO");
 | 
					 | 
				
			||||||
        return Math.random() > 0.5;
 | 
					        return Math.random() > 0.5;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package enseirb.myinpulse.security;
 | 
					package enseirb.myinpulse.security;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static java.util.stream.Collectors.toSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.core.convert.converter.Converter;
 | 
					import org.springframework.core.convert.converter.Converter;
 | 
				
			||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
					import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
				
			||||||
import org.springframework.security.core.GrantedAuthority;
 | 
					import org.springframework.security.core.GrantedAuthority;
 | 
				
			||||||
@@ -18,41 +20,35 @@ import java.util.Map;
 | 
				
			|||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
import java.util.stream.Stream;
 | 
					import java.util.stream.Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static java.util.stream.Collectors.toSet;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
 | 
					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_";
 | 
					    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_";
 | 
					    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";
 | 
					    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";
 | 
					    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";
 | 
					    private static final String CLAIM_ROLES = "roles";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public AbstractAuthenticationToken convert(Jwt source) {
 | 
					    public AbstractAuthenticationToken convert(Jwt source) {
 | 
				
			||||||
        return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
 | 
					        return new JwtAuthenticationToken(
 | 
				
			||||||
                        .stream(), tokenRolesExtractor(source).stream())
 | 
					                source,
 | 
				
			||||||
                .collect(toSet()));
 | 
					                Stream.concat(
 | 
				
			||||||
 | 
					                                new JwtGrantedAuthoritiesConverter().convert(source).stream(),
 | 
				
			||||||
 | 
					                                tokenRolesExtractor(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> tokenRolesExtractor(Jwt jwt) {
 | 
					    public Collection<GrantedAuthority> tokenRolesExtractor(Jwt jwt) {
 | 
				
			||||||
        // Collection that will hold the extracted roles
 | 
					        // Collection that will hold the extracted roles
 | 
				
			||||||
@@ -69,33 +65,43 @@ public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthent
 | 
				
			|||||||
            // Check if any roles are present
 | 
					            // Check if any roles are present
 | 
				
			||||||
            if (roles != null && !roles.isEmpty()) {
 | 
					            if (roles != null && !roles.isEmpty()) {
 | 
				
			||||||
                // Iterate of the roles and add them to the granted authorities
 | 
					                // Iterate of the roles and add them to the granted authorities
 | 
				
			||||||
                Collection<GrantedAuthority> realmRoles = roles.stream()
 | 
					                Collection<GrantedAuthority> realmRoles =
 | 
				
			||||||
                        // Prefix all realm roles with "ROLE_realm_"
 | 
					                        roles.stream()
 | 
				
			||||||
                        .map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
 | 
					                                // Prefix all realm roles with "ROLE_realm_"
 | 
				
			||||||
                        .collect(Collectors.toList());
 | 
					                                .map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
 | 
				
			||||||
 | 
					                                .collect(Collectors.toList());
 | 
				
			||||||
                grantedAuthorities.addAll(realmRoles);
 | 
					                grantedAuthorities.addAll(realmRoles);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Resource (client) roles
 | 
					        // 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.
 | 
					        // 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
 | 
					        // Check if resources are assigned
 | 
				
			||||||
        if (resourceAccess != null && !resourceAccess.isEmpty()) {
 | 
					        if (resourceAccess != null && !resourceAccess.isEmpty()) {
 | 
				
			||||||
            // Iterate of all the resources
 | 
					            // Iterate of all the resources
 | 
				
			||||||
            resourceAccess.forEach((resource, resourceClaims) -> {
 | 
					            resourceAccess.forEach(
 | 
				
			||||||
                // Iterate of the "roles" claim inside the resource claims
 | 
					                    (resource, resourceClaims) -> {
 | 
				
			||||||
                resourceClaims.get(CLAIM_ROLES).forEach(
 | 
					                        // Iterate of the "roles" claim inside the resource claims
 | 
				
			||||||
                        // Add the role to the granted authority prefixed with ROLE_ and the name of the resource
 | 
					                        resourceClaims
 | 
				
			||||||
                        role -> grantedAuthorities.add(new SimpleGrantedAuthority(PREFIX_RESOURCE_ROLE + resource + "_" + role))
 | 
					                                .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;
 | 
					        return grantedAuthorities;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user