I have a Spring boot application which performs the authentication for several applications, and I would like to set the RelayState so that after authentication the application redirects back to the calling application.
Within my configure method, I'm connecting to the IDP using:
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.antMatchers("/actuator*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.serviceProvider()
.keyStore()
.storeFilePath(this.keyStoreFilePath)
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s", this.serverName))
.basePath(this.contextPath)
.and()
.identityProvider()
.discoveryEnabled(false)
.metadataFilePath(this.metadataUrl);
Does anyone have any examples on how to set the relay state?
Thanks
Related
I am studying some code of spring-security. I would like to understand this example that I found on internet
1:
http.requestMatchers()
.antMatchers("/management/**") // (1)
.and()
.authorizeRequests() // (2)
.antMatchers("/management/health")
.permitAll()
.antMatchers("/management/info")
.permitAll()
.antMatchers("/management/**")
.hasRole("ACTUATOR")
.anyRequest().permitAll()
.and()
.httpBasic(); (3)
}
I can not understand this configuration, why this code:
http.requestMatchers()
.antMatchers("/management/**")
.and()
Is before the .authorizeRequests() ? (1)
What does that mean?
Can you explanation this example?
2: In the second case, what is the difference?
http.requestMatchers().antMatchers("/rest2/**")
.and()
.authorizeRequests()
.antMatchers("/rest/v1/test/hello").permitAll()
.antMatchers("/rest/v1/test/**").denyAll()
.and()
.requestMatchers().antMatchers("/rest/**")
.and()
.authorizeRequests()
.antMatchers("/rest/v1/test/hello").permitAll();
What is the impact using requestMatchers()?
If I send a request to "/rest/v1/test/hello2" I received a 401 Why if the rule that deny a request does not match with the antMatchers("/rest2/**") ?
The purpose of requestMatchers() is to specify which requests the spring security configuration will be applied to.
For example if you have 2 endpoints "/public" and "/private" and you only want security (specifically csrf protection) applied to "/private", then you could add the following configuration:
http
.requestMatchers()
.antMatchers("/private/**")
.and()
.csrf();
Then, if you POST to "/private" you will get a 403 response.
But if you POST to "/public" you will get a 200, because there has been no security applied.
This is separate from authorizeRequests which indicates the type of access that is required for that endpoint, as opposed to whether security is applied at all.
In example 1 that you mention
http
.requestMatchers()
.antMatchers("/management/**")
.and()
...
the security configuration is only applied to "/management/**", so if you were to make a request to "/foo", it would not be secured.
In example 2 that you mention,
http
.requestMatchers()
.antMatchers("/rest2/**")
.and()
.authorizeRequests()
.antMatchers("/rest/v1/test/hello").permitAll()
.antMatchers("/rest/v1/test/**").denyAll()
.and()
.requestMatchers()
.antMatchers("/rest/**")
.and()
.authorizeRequests()
.antMatchers("/rest/v1/test/hello").permitAll();
the reason why "/rest/v1/test/hello2" responds with a 401 is because "/rest/**" is in a request matcher, so your security rule .antMatchers("/rest/v1/test/hello").permitAll() will apply.
If you were to make a request to "/rest3/v1/test/hello2", then it would respond with a 200 because "/rest3/**" is not part of any request matcher.
Spring security API:
public final class HttpSecurity.RequestMatcherConfigurer
extends AbstractRequestMatcherRegistry
Allows mapping HTTP requests that this HttpSecurity will be used for
The following spring security config gives some unexpected behavior.
When making a request to some (non-health-check) endpoint (/user), in the browser and when using curl (via git bash on windows), an unauthenticated request returns an idp redirect as expected.
However, when using the WebTestClient, it returns 401 Unauthorized with www-authenticate: [Basic ...].
The request for basic authn in this context (and the password generated at startup) are unexpected because I've declared to disable basic authn via http.httpBasic().disable().
Why would this response come? Is there a better way to override the default basic auth configs? Is there an ordering on these configurations as suggested in this post? Where is this documented?
...env values
#Bean
public SecurityWebFilterChain webFilterChain(ServerHttpSecurity http) {
http.oauth2Client()
.and()
.oauth2Login()
.and()
.httpBasic()
.disable()
.formLogin()
.disable()
.csrf()
.disable()
.authorizeExchange()
.pathMatchers("/actuator/health").permitAll()
.anyExchange().authenticated();
return http.build();
}
#Bean
ReactiveClientRegistrationRepository getClientRegistrationRepository() {
ClientRegistration google =
ClientRegistration.withRegistrationId("google")
.scope("openid", "profile", "email")
.clientId(clientId)
.clientSecret(clientSecret)
.authorizationUri(authUri)
.tokenUri(tokenUri)
.userInfoUri(userInfoUri)
.redirectUri(redirectUri)
.jwkSetUri(jwksUri)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.userNameAttributeName("name")
.build();
return new InMemoryReactiveClientRegistrationRepository(google);
}
Project on github: https://github.com/segevmalool/spring-samples/blob/main/spring-security-webflux-postgres
httpBasic().authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))
Solution
I am using SAML authentication for my Spring boot application with Okta as IdP. The Single Signon(SSO) configuration is done and working as expected. But I am stuck with configuring Single Logout(SLO). I want to use SP initiated Logout. Please assist me to proceed further.
Mentioned below is the configure method that I created by extending WebSecurityConfigurerAdapter.
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.serviceProvider()
.keyStore()
.storeFilePath(this.keyStoreFilePath)
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s:%s", "localhost", this.port))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl);
}
I´m trying to configure a basic authentication plus ip filter, the basic auth, works fine with this configure:
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.httpBasic();
}
I would like to add ip filter, I´ve read some about hasIpAddress but I don´t know how use it.
For XML configuraton see Spring Security Reference:
26.2 Web Security Expressions
To use expressions to secure individual URLs, you would first need to set the use-expressions attribute in the <http> element to true. Spring Security will then expect the access attributes of the <intercept-url> elements to contain Spring EL expressions. The expressions should evaluate to a Boolean, defining whether access should be allowed or not. For example:
<http>
<intercept-url pattern="/admin*"
access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
...
</http>
Here we have defined that the "admin" area of an application (defined by the URL pattern) should only be available to users who have the granted authority "admin" and whose IP address matches a local subnet. We’ve already seen the built-in hasRole expression in the previous section. The expression hasIpAddress is an additional built-in expression which is specific to web security. It is defined by the WebSecurityExpressionRoot class, an instance of which is used as the expression root object when evaluation web-access expressions.
For Java configuration see ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#access:
Parameters:
attribute - the expression to secure the URLs (i.e. "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
Your modified code:
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.disable()
.authorizeRequests()
.anyRequest().access("isFullyAuthenticated() and hasIpAddress('192.168.1.0/24')")
.and()
.httpBasic();
}
I'm using Spring Security with Thymeleaf and want to create a login and a register form on different sites that make both use of CSRF protection. Protecting the login site is easy, as with the folloing WebSecurity configuration
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
Spring supports adding CSRF protection in general by the Security Filter Chain that is build in the configure method. This Filter Chain contains a CSRFFilter that adds/evaluates the CSRF token. This Filter Chain is then used for all matches defined in the above configuration. The mechanism of getting the Filters that are applied to a request can be found here in the method
doFilterInternal(ServletRequest, ServletResponse, FilterChain)
The problem is, if I add the "/register" site to this configuration, the user is redirected to the "/login" site first. If I don't add it to the above config, the mentioned FilterChain is not applied (and so not the CsrfFilter).
So what I want is to reuse the CsrfFilter in the Filter Chain of the "/register" site, but I don't know how to do that.
I'd prefer this approach to other ideas like writing a custom CSRF filter as suggested here or here.
From all of this i understood the problem is that you want people to access /register without needing to login first. Which is a simple fix:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.requestMatchers()
// add this line
.antMatchers("/register").permitAll().and
//
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
Turned out that the Spring Security Filter chain is applied to all endpoints mentioned in the list provided to requestMatchers().antMatchers().
So to use CSRF protection for a site that is not the login site, I just had to add it to this list and then permit all access to it, so there is no redirect to the login page. My final config looks like this
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.requestMatchers()
// consider these patterns for this config and the Security Filter Chain
.antMatchers("/login", "/register", "/oauth/authorize", "/oauth/confirm_access", "/oauth/token_key",
"/oauth/check_token", "/oauth/error")
.and()
// define authorization behaviour
.authorizeRequests()
// /register is allowed by anyone
.antMatchers("/register").permitAll()
// /oauth/authorize needs authentication; enables redirect to /login
.antMatchers("/oauth/authorize").authenticated()
// any other request in the patterns above are forbidden
.anyRequest().denyAll()
.and()
.formLogin()
// we have a custom login page at /login
// that is permitted to everyone
.loginPage("/login").permitAll();
}