How to remove SCOPE_ prefix in hasAuthority - spring-boot

This is my token response. but Spring auto add SCOPE_ prefix . how to config ScopeVoter.setScopePrefix(String scopePrefix) in spring boot. pls help me. thanks
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1MkRsOVNTMlREY0M5SkFtZmZ3ZE1BNjJkbFBreDlFMDdRSnhObF9sVDNJIn0.eyJleHAiOjE2MDQwMjM0MDEsImlhdCI6MTYwNDAyMzEwMSwianRpIjoiMTZkMDBjNzEtYTRiZS00MGNhLTk4NjUtZGQxNGVlYmU5MGFjIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21pY3Jvc2VydmljZSIsInN1YiI6IjFkYTEzZGMzLTI0NDUtNGVlNC1iMWE1LTM2NzZjNjIyNjg5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1vYmlsZXJldGFpbCIsInNlc3Npb25fc3RhdGUiOiIyYjM2MzFkYi05ZjAyLTQyMjktOTM4NC1kNDQxYzRjZjY3NTEiLCJhY3IiOiIxIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJtb2JpbGVyZXRhaWwiOnsicm9sZXMiOlsidW1hX3Byb3RlY3Rpb24iXX19LCJzY29wZSI6InBob25lIHByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudElkIjoibW9iaWxlcmV0YWlsIiwiY2xpZW50SG9zdCI6IjEyNy4wLjAuMSIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1tb2JpbGVyZXRhaWwiLCJjbGllbnRBZGRyZXNzIjoiMTI3LjAuMC4xIn0.L0miTQSm1C_vQdE4DxW4h27R3qphjZ97JVOaoRDkAyiWSu26NpiNH0hBF3_iJ4RUlDm6pjOMQvRntVcpouV7gtTd4Pvi9bkxPI6je-LEhIXHeDsFpMeNIy9T7YyfICsQQULLzwJ9uNDAWcsgSIGAqHcCaHtSh3X3PUyDQtFth8JBqUGESyzqAQ2F2ydtQC4TBe7l6bKeU0hO0rVFWTBOB8KZm4NaV2xgyy3KSkr_iSNctidTyXDQZBIKJsVqUH8uUcCMxsdqVHmMY9i_Sr_GzbMBGNnVeQpvLiqN3yHgwTXJA58Ttt5LL4yOmtJEG7Qj9gESxAmkj1_WKqmhNWp7oA",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxOGM5ZmRiNy1mNzQ0LTQ2ZjktODQ4Ni0wMTFjNWVkOWNkZDIifQ.eyJleHAiOjE2MDQwMjQ5MDEsImlhdCI6MTYwNDAyMzEwMSwianRpIjoiOTY5ZGMzZTEtMWVhOC00YThkLWIxOTEtZDhlNDg1YTU2ZWVkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21pY3Jvc2VydmljZSIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9hdXRoL3JlYWxtcy9taWNyb3NlcnZpY2UiLCJzdWIiOiIxZGExM2RjMy0yNDQ1LTRlZTQtYjFhNS0zNjc2YzYyMjY4OTciLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoibW9iaWxlcmV0YWlsIiwic2Vzc2lvbl9zdGF0ZSI6IjJiMzYzMWRiLTlmMDItNDIyOS05Mzg0LWQ0NDFjNGNmNjc1MSIsInNjb3BlIjoicGhvbmUgcHJvZmlsZSBlbWFpbCJ9.wZtoxah1dofhZOoMfODG2faFIivjjlTIxVeMJgu_Gm8",
"token_type": "bearer",
"not-before-policy": 0,
"session_state": "2b3631db-9f02-4229-9384-d441c4cf6751",
"scope": "phone profile email"
hasAuthority('SCOPE_phone') is working, but hasAnyAuthority('phone') not working
#RequestMapping(value = "/user", method = RequestMethod.GET)
#PreAuthorize("hasAuthority('SCOPE_phone')")
public ResponseEntity<String> getUser() {
return ResponseEntity.ok("Hello User");
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
#PreAuthorize("hasAnyAuthority('phone')")
public ResponseEntity<String> test() {
return ResponseEntity.ok("Hello test");
}

I manage it like below in one of our applciation. Have you tried custom AccessDecisionManager to inject ScopeVoter with NoPrefix. Since Default is SCOPE_. Since I could not find out of the box configuration for SCOPE_ prefix.
#Configuration
#EnableWebSecurity
public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.and()
....
....
....
....
.permitAll();
http.authorizeRequests()
.accessDecisionManager(accessDecisionManager()); // passed custom access decision manager
}
#Bean
public AccessDecisionManager accessDecisionManager() {
java.util.List<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(), // You can add or remove the Role voters as per need
new RoleVoter(), // For ROLE_ prefix
new AuthenticatedVoter(),
scopeVoterWithNoPrefix() // Get instance of ScopeVoter
);
return new UnanimousBased(decisionVoters);
}
#Bean
public ScopeVoter scopeVoterWithNoPrefix() {
ScopeVoter scopeVoter = new ScopeVoter();
scopeVoter.setScopePrefix("")
return scopeVoter;
}
}

You can add the following snippet to your configuration to empty default jwt authority prefix
#Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthorityPrefix("");
JwtAuthenticationConverter authConverter = new JwtAuthenticationConverter();
authConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return authConverter;
}
For example you can have it in your WebSecurityConfiguration

Related

Can not get user info with Spring Security SAML WITHOUT Spring Boot

I´m working on SAML integration in an older project but I can´t get the user information.
I've guided me with the response of this question:
https://stackoverflow.com/questions/70275050/spring-security-saml-identity-metadata-without-spring-boot
The project has these versions:
spring framework 5.3.24
spring security 5.6.10
opensaml 3.4.6
This is my code:
#Configuration
public class SAMLSecurityConfig {
private static final String URL_METADATA = "https://auth-dev.mycompany.com/app/id/sso/saml/metadata";
#Bean("samlRegistration")
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(URL_METADATA)
.registrationId("id")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
}
#EnableWebSecurity
public class WebSecurity {
#Configuration
#Order(2)
public static class SAMLSecurityFilter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.saml2Login(Customizer.withDefaults())
.antMatcher("/login/assertion")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
}
#Controller("loginController")
public class BoCRLoginController {
#RequestMapping(value = "/login/assertion", method = {RequestMethod.POST},
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<String> assertLoginData(#AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
System.out.println(principal); //here I get a null
return new ResponseEntity<>(HttpStatus.OK);
}
}
Once I did the login on okta the class: Saml2AuthenticatedPrincipal comes null value.
Could you help me to know why I received null value on the object Saml2AuthenticatedPrincipal where suppose have to receive the user information?

How to extract custom Principal in OAuth2 Resource Server?

I'm using Keycloak as my OAuth2 Authorization Server and I configured an OAuth2 Resource Server for Multitenancy following this official example on GitHub.
The current Tenant is resolved considering the Issuer field of the JWT token.
Hence the token is verified against the JWKS exposed at the corresponding OpenID Connect well known endpoint.
This is my Security Configuration:
#EnableWebSecurity
#RequiredArgsConstructor
#EnableAutoConfiguration(exclude = UserDetailsServiceAutoConfiguration.class)
public class OrganizationSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final TenantService tenantService;
private List<Tenant> tenants;
#PostConstruct
public void init() {
this.tenants = this.tenantService.findAllWithRelationships();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.authenticationManagerResolver(new MultiTenantAuthenticationManagerResolver(this.tenants));
}
}
and this is my custom AuthenticationManagerResolver:
public class MultiTenantAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> {
private final AuthenticationManagerResolver<HttpServletRequest> resolver;
private List<Tenant> tenants;
public MultiTenantAuthenticationManagerResolver(List<Tenant> tenants) {
this.tenants = tenants;
List<String> trustedIssuers = this.tenants.stream()
.map(Tenant::getIssuers)
.flatMap(urls -> urls.stream().map(URL::toString))
.collect(Collectors.toList());
this.resolver = new JwtIssuerAuthenticationManagerResolver(trustedIssuers);
}
#Override
public AuthenticationManager resolve(HttpServletRequest context) {
return this.resolver.resolve(context);
}
}
Now, because of the design of org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver.TrustedIssuerJwtAuthenticationManagerResolver
which is private, the only way I can think in order to extract a custom principal is to reimplement everything that follows:
TrustedIssuerJwtAuthenticationManagerResolver
the returned AuthenticationManager
the AuthenticationConverter
the CustomAuthenticationToken which extends JwtAuthenticationToken
the CustomPrincipal
To me it seems a lot of Reinventing the wheel, where my only need would be to have a custom Principal.
The examples that I found don't seem to suit my case since they refer to OAuth2Client or are not tought for Multitenancy.
https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor
How to extend OAuth2 principal
Do I really need to reimplement all such classes/interfaes or is there a smarter approach?
This is how I did it, without reimplementing a huge amount of classes. This is without using a JwtAuthenticationToken however.
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver()));
}
#Bean
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver() {
List<String> issuers = ... // get this from list of tennants or config, whatever
Predicate<String> trustedIssuer = issuers::contains;
Map<String, AuthenticationManager> authenticationManagers = new ConcurrentHashMap<>();
AuthenticationManagerResolver<String> resolver = (String issuer) -> {
if (trustedIssuer.test(issuer)) {
return authenticationManagers.computeIfAbsent(issuer, k -> {
var jwtDecoder = JwtDecoders.fromIssuerLocation(issuer);
var provider = new JwtAuthenticationProvider(jwtDecoder);
provider.setJwtAuthenticationConverter(jwtAuthenticationService::loadUserByJwt);
return provider::authenticate;
});
}
return null;
};
return new JwtIssuerAuthenticationManagerResolver(resolver);
}
}
#Service
public class JwtAuthenticationService {
public AbstractAuthenticationToken loadUserByJwt(Jwt jwt) {
UserDetails userDetails = ... // or your choice of principal
List<GrantedAuthority> authorities = ... // extract from jwt or db
...
return new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
}
}

Use Swagger-ui for a keycloak protected App

I'm trying to build a user-service to access keycloak with spring-boot and the keycloak-admin-client.
edit: I should mention that run the service and keycloak in different docker containers, I think that might be the problem.
My AUTH_SERVER is set to keycloak:8080, and I have it to redirect to localhost in my hostfile.
edit2: I managed to get the token through swagger, but the user-creation still ends with a 403 Forbidden, although the exact same code works if run outside of swagger. Seems like a problem with my spring-boot or my swagger.
Stragely enough, I can get a token just fine.
I want to create a user and provide a login endpoint, where another service can login a user with username/password and get a token back.
The code for user creation works if I run it outside of swagger in a main method, and I can get a token via postman. (now also through swagger)
But with swagger-ui, I get a "403 Forbidden" when trying to create a user.
I have tried both the Postrequest via resttemplate and through the admin-cli of keycloak.
Both work when run independently of swagger and both dont work with swagger.
#PostMapping(path = "new")
public ResponseEntity<String> addUser(UserData userData) {
UserRepresentation user = new UserRepresentation();
user.setEnabled(true);
user.setUsername(userData.getUsername());
user.setFirstName(userData.getFirstName());
user.setLastName(userData.getLastName());
RealmResource realmResource = getRealmResource();
UsersResource userResource = realmResource.users();
Response response = userResource.create(user);
log.info("Response: " + response.getStatusInfo());
return new ResponseEntity<>("User created with userId: " + userData.getBusinessEntityId(),
HttpStatus.OK);
}
My securityconfig:
/*
Submits the KeycloakAuthenticationProvider to the AuthenticationManager
*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/api/v1/user/admin").hasRole("admin")
.antMatchers("/api/v1/user/vendor").hasRole("vendor")
// .antMatchers("/api/v1/user/customer").hasRole("customer")
.anyRequest().permitAll();
}
My Swaggerconfig:
#Bean
public Docket apiDocumentation() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(Arrays.asList(securityContext()));
}
private SecurityScheme securityScheme() {
return new OAuthBuilder()
.name("spring_oauth")
.grantTypes(grantTypes())
.build();
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference("spring_oauth", new AuthorizationScope[]{})))
.forPaths(PathSelectors.any())
.build();
}
private List<GrantType> grantTypes() {
GrantType grantType = new ClientCredentialsGrant(AUTH_SERVER + "/realms/User-Service-Realm/protocol/openid-connect/token");
return Arrays.asList(grantType);
}
#Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.realm(REALM)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.scopeSeparator(" ")
.useBasicAuthenticationWithAccessCodeGrant(true)
.build();
}
My Keycloak settings:
I could manage it to work in a client credential grant.
You may want to try it with the following configuration instead.
private SecurityScheme securityScheme() {
return new OAuthBuilder()
.name("spring_oauth")
.grantTypes(grantTypes())
.build();
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference("spring_oauth", new AuthorizationScope[] {})))
.forPaths(PathSelectors.regex("/api.*"))
.build();
}
private List<GrantType> grantTypes() {
GrantType grantType = new ClientCredentialsGrant(authTokenURL);
return Arrays.asList(grantType);
}
I found out the solution:
I annotated the Requests in my RestController as PostRequests since thats whats specified in the keycloak docs and what makes sense.
After changing them to GetRequests, they work now.

How to add a custom OpenId Filter in a Spring boot application?

I am trying to implement the backend side of an OpenId Connect authentication. It is a stateless API so I added a filter that handles the Bearer token.
I have created the OpenIdConnect Filter that handles the Authentication and added it in a WebSecurityConfigurerAdapter.
public class OpenIdConnectFilter extends
AbstractAuthenticationProcessingFilter {
#Value("${auth0.clientId}")
private String clientId;
#Value("${auth0.issuer}")
private String issuer;
#Value("${auth0.keyUrl}")
private String jwkUrl;
private TokenExtractor tokenExtractor = new BearerTokenExtractor();
public OpenIdConnectFilter() {
super("/connect/**");
setAuthenticationManager(new NoopAuthenticationManager());
}
#Bean
public FilterRegistrationBean registration(OpenIdConnectFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
try {
Authentication authentication = tokenExtractor.extract(request);
String accessToken = (String) authentication.getPrincipal();
String kid = JwtHelper.headers(accessToken)
.get("kid");
final Jwt tokenDecoded = JwtHelper.decodeAndVerify(accessToken, verifier(kid));
final Map<String, Object> authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
verifyClaims(authInfo);
Set<String> scopes = new HashSet<String>(Arrays.asList(((String) authInfo.get("scope")).split(" ")));
int expires = (Integer) authInfo.get("exp");
OpenIdToken openIdToken = new OpenIdToken(accessToken, scopes, Long.valueOf(expires), authInfo);
final OpenIdUserDetails user = new OpenIdUserDetails((String) authInfo.get("sub"), "Test", openIdToken);
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
} catch (final Exception e) {
throw new BadCredentialsException("Could not obtain user details from token", e);
}
}
public void verifyClaims(Map claims) {
int exp = (int) claims.get("exp");
Date expireDate = new Date(exp * 1000L);
Date now = new Date();
if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("azp").equals(clientId)) {
throw new RuntimeException("Invalid claims");
}
}
private RsaVerifier verifier(String kid) throws Exception {
JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl));
Jwk jwk = provider.get(kid);
return new RsaVerifier((RSAPublicKey) jwk.getPublicKey());
}
Here is security configuration:
#Configuration
#EnableWebSecurity
public class OpenIdConnectWebServerConfig extends
WebSecurityConfigurerAdapter {
#Bean
public OpenIdConnectFilter myFilter() {
final OpenIdConnectFilter filter = new OpenIdConnectFilter();
return filter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.antMatcher("/connect/**").authorizeRequests()
.antMatchers(HttpMethod.GET, "/connect/public").permitAll()
.antMatchers(HttpMethod.GET, "/connect/private").authenticated()
.antMatchers(HttpMethod.GET, "/connect/private-
messages").hasAuthority("read:messages")
.antMatchers(HttpMethod.GET, "/connect/private-
roles").hasAuthority("read:roles")
.and()
.addFilterBefore(myFilter(),
UsernamePasswordAuthenticationFilter.class);
}
Rest endpoints looks like following:
#RequestMapping(value = "/connect/public", method = RequestMethod.GET,
produces = "application/json")
#ResponseBody
public String publicEndpoint() throws JSONException {
return new JSONObject()
.put("message", "All good. You DO NOT need to be authenticated to
call /api/public.")
.toString();
}
#RequestMapping(value = "/connect/private", method = RequestMethod.GET,
produces = "application/json")
#ResponseBody
public String privateEndpoint() throws JSONException {
return new JSONObject()
.put("message", "All good. You can see this because you are
Authenticated.")
.toString();
}
If I remove completely the filter for configuration and also the #Bean definition, the configuration works as expected: /connect/public is accessible, while /connect/private is forbidden.
If I keep the #Bean definition and add it in filter chain the response returns a Not Found status for requests both on /connect/public and /connect/private:
"timestamp": "18.01.2019 09:46:11",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/
When debugging I noticed that filter is processing the token and returns an implementation of Authentication.
Is the filter properly added in filter chain and in correct position?
Why is the filter invoked also on /connect/public path when this is supposed to be public. Is it applied to all paths matching super("/connect/**") call?
Why is it returning the path as "/" when the request is made at /connect/private
Seems that is something wrong with the filter, cause every time it is applied, the response is messed up.

Intercept the SSO cookie before the authorization server redirects the page

I have been banging my head for over a week to intercept the SSO cookie before the Authorization server redirects me my app page.
I'm implementing mitreid-connect for openid configuration. I have followed the documentation in the link and configured it using Java Config. Everything works fine, the redirects and etc., but I'm trying to implement AbstractPreAuthenticatedProcessingFilter to intercept the SSO cookie before the authorization server consumes it and generates the IdToken.
Please let me know if this is not right. I'm very new to spring-security and its scraping my scales off and its driving me crazy how to get hold to sso cookie
I have found this link
Please help me
#Configuration
public class filter extends AbstractPreAuthenticatedProcessingFilter {
#Bean(name = "singleSignOnFilter")
public String filter() {
return "PRE_AUTH_FILTER";
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return null;
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
Cookie[] cookie = request.getCookies();
for(int i = 0; i < cookie.length; i++) {
System.out.println(cookie[i].getName() + " - " + cookie[i].getValue());
}
return null;
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Inject
private ClientDetailsEntity client;
#Inject
private String issuer;
#Bean
public ProviderManager providerManager() {
List<AuthenticationProvider> authenticationProvider = new LinkedList<AuthenticationProvider>();
authenticationProvider.add(oidcAuthProvider());
return new ProviderManager(authenticationProvider);
}
#Bean(name = "authenticationProvider")
public AuthenticationProvider oidcAuthProvider() {
return new OIDCAuthenticationProvider();
}
#Bean(name = "authoritiesMapper")
public OIDCAuthoritiesMapper authorityMapper() {
NamedAdminAuthoritiesMapper namedAdminAuthMapper = new NamedAdminAuthoritiesMapper();
namedAdminAuthMapper.setAdmins(admins());
return namedAdminAuthMapper;
}
#Bean(name = "admins")
public Set<SubjectIssuerGrantedAuthority> admins() {
Set<SubjectIssuerGrantedAuthority> admin = new HashSet<SubjectIssuerGrantedAuthority>();
return admin;
}
#Bean(name = "openIdConnectAuthenticationFilter")
public Filter openIdConnectAuthenticationFilter() {
OIDCAuthenticationFilter oidcAuthFilter = new OIDCAuthenticationFilter();
oidcAuthFilter.setAuthenticationManager(providerManager());
oidcAuthFilter.setIssuerService(issuerService());
oidcAuthFilter.setClientConfigurationService(clientConfigurationService());
oidcAuthFilter.setAuthRequestUrlBuilder(authRequestUrlBuilder());
return oidcAuthFilter;
}
#Bean(name = "issuerService")
public IssuerService issuerService() {
StaticSingleIssuerService issuerService = new StaticSingleIssuerService();
issuerService.setIssuer(issuer);
return issuerService;
}
#Bean(name = "clientConfigurationService")
public ClientConfigurationService clientConfigurationService() {
StaticClientConfigurationService clientConfigService = new StaticClientConfigurationService();
clientConfigService.setClients(registeredClient());
return clientConfigService;
}
#Bean(name = "clients")
public Map<String, RegisteredClient> registeredClient() {
Map<String, RegisteredClient> oidcRegClients = new HashMap<String, RegisteredClient>();
oidcRegClients.put(issuer, new RegisteredClient(client));
return oidcRegClients;
}
#Bean(name = "authRequestUrlBuilder")
public AuthRequestUrlBuilder authRequestUrlBuilder() {
return new PlainAuthRequestUrlBuilder();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(openIdConnectAuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class)
.formLogin()
.loginPage("/openid_connect_login")
.and()
.logout()
.and()
.authorizeRequests()
.antMatchers("/items")
.authenticated()
.anyRequest()
.permitAll();
}
}
You are on right path. I think, your question is how to extract the information(for e.g. username) from cookie and then use this information to authorize the user. Here are the steps, to clear some air.
Configure a subclass of AbstractPreAuthenticatedProcessingFilter (e.g. below )
public class CustomPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter {
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
// below sample extracts the username from header.You can pull from cookie
String expectedHeaderNameContainingUsername = "abcd";
String username = request.getHeader(expectedHeaderNameContainingUsername);
return username;
}
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
String expectedHeaderNameContainingCredentials = "";
if (StringUtils.isNotBlank(expectedHeaderNameContainingCredentials)) {
return request.getHeader(expectedHeaderNameContainingCredentials);
}
return "N/A";
}
}
Simply register the above filter with HTTP security with
http.addFilter(Filter filter);
It seems your filter is not registered with spring security.
The AbstractPreAuthenticatedProcessingFilter forwards the result of getPreAuthenticatedPrincipal(..) to authmanager to build the principal object.
Hope this helps.

Resources