Spring security 5.20 + SAML2 - spring-security

Is it possible to start a SAML2 authentication process restricting to certain URLs? So my idea is to use a URL like /saml2login that launches all the SAML authentication process.
I've trĀ”ed with something similar to:
httpSecurity.authorizeRequests()
.antMatchers("/saml2login").authenticated()
.and()
.saml2Login()
.relyingPartyRegistrationRepository(
new InMemoryRelyingPartyRegistrationRepository(
getSaml2AuthenticationConfiguration()
)
);
But It doesn't work

Related

Spring Security OIDC + WebFlux Calls Keycloak Every Time

I have configured spring webflux with Open Id Connect with Keycloak as an IDP.
The problem is that for every call to my application, the oauth2 client does a call to keycloak instead of using the security session.
I have configured my webflux security as follows:
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, ServerLogoutSuccessHandler handler) {
http
.authorizeExchange(exchanges -> exchanges
.anyExchange().authenticated()
)
.securityContextRepository(new WebSessionServerSecurityContextRepository())
.oauth2Login(withDefaults());
return http.build();
}
I have a security context repository saved in the web session.
I have configured my web session in memory like so:
#Bean
public ReactiveSessionRepository reactiveSessionRepository() {
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
}
In my logs I can see that a security context has been found:
WebSessionServerSecurityContextRepository : Found SecurityContext 'SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=Name: [alex], Granted Authorities: [[ROLE_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{sub=bdc6b386-623f-4fe4-a013-2c694678797b, email_verified=true, name=Aleksandar KIRILOV, preferred_username=alex, given_name=John, family_name=Doe, email=mymail#mail.com}], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]]]' in WebSession: 'org.springframework.session.web.server.session.SpringSessionWebSessionStore$SpringSessionWebSession#5a17f06f'
Please help on how to avoid calling keycloak if the security context is still valid in the websession.
Best Regards !
a colleague of mine found the solution:
It seems that there is a clock skew protection in spring oauth2 client and I had set my access_token to expire after only one minute.
The clock skew protection was also set to one minute meaning that spring will preemptively go and refresh the token since we are close to expiration time.

How can I return 401 for some URL when using spring security oAuth2 login

I'm trying to secure my application with Spring Security oAuth2. Is there a way to return 401 for some URL while other pages go to the login page if a user is not logged in.
For example, return login form for /ui/*, and return 401 for /api/*
I tried to use two SecurityWebFilterChain, but didn't success.
My spring security version is something different, and the codes are something like following:
http.exceptionHandling().authenticationEntryPoint(new DelegatingServerAuthenticationEntryPoint(
new DelegatingServerAuthenticationEntryPoint.DelegateEntry(
ServerWebExchangeMatchers.pathMatchers("/ui/**"),
new RedirectServerAuthenticationEntryPoint("/login")
),
new DelegatingServerAuthenticationEntryPoint.DelegateEntry(
ServerWebExchangeMatchers.pathMatchers("/api/**"),
new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)
))
);
You can configure Spring Security to use a custom AuthenticationEntryPoint, something like:
http
// ... your configuration
.exceptionHandling((ex) -> ex
.defaultAuthenticationEntryPointFor(new LoginUrlAuthenticationEntryPoint("/login"), new AntPathRequestMatcher("/ui/**"))
.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), new AntPathRequestMatcher("/api/**"))
);
This way Spring Security will pick up the AuthenticationEntryPoint based on the RequestMatcher#matches method

Spring Security OAuth2 configuring failureUrl makes the url inaccessible

I have a spring security based boot application for which I have configured an endpoint names /test for which I return a test.html page
#RequestMapping("/test")
public String test() {
return "test.html";
}
The endpoint works fine by itself, however if I set it as an OAuth2 failureUrl it becomes unavailable...
http.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.authorizeRequests()
.antMatchers("/test").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.failureUrl("/test");
Is this expected behavior? When I do this, spring security properly redirects to /test on authentication failure but /test is inaccessible and it ends up showing a generated page.
The behaviour of failureUrl differs based on whether or not a custom loginPage is configured.
Since you have not customized loginPage, the framework will intercept the failure URL ("/test") and generate the default error page, which is simply the default login page with an error message.
That is why you see the generated login page with accessing "/test".
Your Controller mapping for "/test" is ignored.
To tell the framework not to generate the error page, you can configure the failureHandler instead.
http
.oauth2Login((oauth2Login) -> oauth2Login
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/test"))
);
Note: This may be confusing because the Javadoc for failureUrl does not describe its behaviour properly. I have created a GitHub issue in the Spring Security backlog to fix this.

Spring MVC Test MockMvc - how do I configure a url mapping prefix

I have a DispatcherServlet that has a URL mapping /api1 and subsequentially a Controller with a mapping #GetMapping("/resource1") for a controller method. So basically I have a valid URL /api1/resource1 that should be handled by the mentioned controller.
Also, the setup incorporates a Spring Security Filter that matches requests /* as it secures other URLs not handled by Spring (but Jersey for example).
The API secured by the Spring Security Filter is setup like
protected void configure(HttpSecurity http) throws Exception {
//#formatter:off
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers()
.antMatchers("/api1/**")
.and()
.authorizeRequests()
.antMatchers("/**")
.authenticated()
For testing I use the MockMvc* support to setup a mocked web environment including a Spring security setup
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build()
I want to test that security checks are applied and the controller method is called on successful security checks.
when:
def result = mvc.perform(
get('/api1/resource1')
.header(HttpHeaders.AUTHORIZATION, "Bearer " + apiToken))
then:
result.andExpect(status().isOk())
The code above is based on the Spock framework with the MockMvc stuff.
All of the security checks are passing so the Spring security setup is complete, but finally the controller should be invoked but fails with a 404 status i.e the resource - this is the mapped controller method - is not found.
I'm confident that it fails because the mocked setup does not incorporate a the /api dispatcher servlet mapping. To proof that assumption I can modify the controller method mapping to #GetMapping("/api1/resource1") and the test will result in a HTTP OK (200).
So, my question is, is it possible to configure a kind of URL prefix in the MockMvc setup?
There is one constraint, the code base is not using Spring Boot (and can't for a while in future)!
Edit:
I added the following to my test to have all requests set the servletPath.
static MockHttpServletRequestBuilder get(String urlTemplate, Object... uriVars) {
new MockHttpServletRequestBuilder(HttpMethod.GET, urlTemplate, uriVars)
.servletPath('/api1')
}
I think you just need to configure the contextPath for the request.
See org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder.contextPath(String) for details.

How to configure /public, /protected, /private access paths in Spring Oauth2 Security

I have a very specific requirement in my project related to identity & authorization. I want to open 3 paths /public/, /protected/ & /private/ from my REST service module, which will behave as follows:
URLs starting with /public/ can be accessed without any authentication or authorization.
URLs starting with /private/ can be accessed only if the user is authenticated.
URLs starting with /protected/ can be accessed only if the user is authenticated as well as authorized.
To achieve this I have built a Configurator by extending "spring resource server configurator & overriding the configure method". But unfortunately it's not working. I have also tried to use "spring web service configurator & using the ignore ant url support " but the same is also not working. The configuration which is working only for /private/ & /protected/ URLs is as follows.
http.anonymous()
.disable()
.requestMatchers()
.antMatchers("/protected/**", "/private/**")
.and();
for (String protectedApiEp : configuredApis) {
http.authorizeRequests()
.antMatchers("/protected/" + protectedApiEp + "/**")
.hasAuthority(protectedApiEp);
}
http.authorizeRequests()
.antMatchers("/protected/**").denyAll()
.antMatchers("/private/**").permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Can anyone guide me how I can enable /public/ URLs as open to all users, with the above configuration?
The following configuration should work:
#EnableWebSecurity
public class WebApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
// Allow Spring Security to authorize requests.
http
.authorizeRequests()
// Allow anyone to access URLs starting with /public/.
.antMatchers("/public/**").permitAll()
// Allow anyone with the protected role to access URLs starting with /protected/.
.antMatchers("/protected/**").hasAuthority("protected")
// Allow anyone who is authenticated successfully to access all other URLs.
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
Here is a sample application that shows this configuration in action. Start the application as mvn clean spring-boot:run and then navigate to http://localhost:8080 to access the application.

Resources