All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.c4_soft.springaddons.security.oidc.starter.ConfigurableClaimSetAuthoritiesConverter Maven / Gradle / Ivy

The newest version!
package com.c4_soft.springaddons.security.oidc.starter;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.springframework.lang.NonNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.StringUtils;

import com.c4_soft.springaddons.security.oidc.starter.properties.NotAConfiguredOpenidProviderException;
import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcProperties.OpenidProviderProperties.SimpleAuthoritiesMappingProperties;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;

import lombok.RequiredArgsConstructor;

/**
 * 

* Portable converter to extract Spring-security authorities from OAuth2 claims. *

*

* It relies on {@link OpenidProviderPropertiesResolver} to resolve the configuration properties for the provided claims (and throws if it * is not resolved). This properties enable to configure: *

*
    *
  • source claims (which claims to pick authorities from, dot.separated.path is supported)
  • *
  • for each claim: prefix (should anything like "ROLE_" or "PREFIX_" be pre-pended to authorities)
  • *
  • for each claim: case transformation (should be authorities be forced to uppercase, lowercase or be left untouched)
  • *
* * @author ch4mp */ @RequiredArgsConstructor public class ConfigurableClaimSetAuthoritiesConverter implements ClaimSetAuthoritiesConverter { private final OpenidProviderPropertiesResolver opPropertiesResolver; @Override public Collection convert(@NonNull Map source) { final var opProperties = opPropertiesResolver.resolve(source).orElseThrow(() -> new NotAConfiguredOpenidProviderException(source)); // @formatter:off return opProperties.getAuthorities().stream() .flatMap(authoritiesMappingProps -> getAuthorities(source, authoritiesMappingProps)) .map(r -> (GrantedAuthority) new SimpleGrantedAuthority(r)).toList(); // @formatter:on } private static String processCase(String role, SimpleAuthoritiesMappingProperties.Case caze) { switch (caze) { case UPPER: { return role.toUpperCase(); } case LOWER: { return role.toLowerCase(); } default: return role; } } private static Stream getAuthorities(Map claims, SimpleAuthoritiesMappingProperties props) { // @formatter:off return getClaims(claims, props.getPath()) .flatMap(claim -> Stream.of(claim.split(","))) .flatMap(claim -> Stream.of(claim.split(" "))) .filter(StringUtils::hasText) .map(String::trim) .map(r -> processCase(r, props.getCaze())) .map(r -> String.format("%s%s", props.getPrefix(), r)); // @formatter:on } @SuppressWarnings({ "rawtypes", "unchecked" }) private static Stream getClaims(Map claims, String path) { try { final var res = JsonPath.read(claims, path); if (res instanceof String r) { return Stream.of(r); } if (res instanceof List l) { if (l.size() == 0) { return Stream.empty(); } if (l.get(0) instanceof String) { return l.stream(); } if (l.get(0) instanceof List) { return l.stream().flatMap(o -> ((List) o).stream()); } } return Stream.empty(); } catch (PathNotFoundException e) { return Stream.empty(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy