Combining login based auth with saml 2 in spring boot - spring-boot

My goal is to add SSO way in addition to login based into spring boot app.
I use Okta as identity provider and got stuck into misunderstanding conceptions:
When I follow single sign on url from Okta, it goes to localhost endpoint and falls with 415 response. My websecurity config:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(SECURITY_WHITELIST)
.permitAll()
.and()
.httpBasic()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
/* configuring saml*/
.and()
.saml2Login(Customizer.withDefaults())
.saml2Logout(Customizer.withDefaults())
// .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class).antMatcher("/**/auth-saml") //
.authorizeRequests()
.anyRequest().authenticated();
http.addFilterBefore(tokenAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);
}
and controller's endpoint signature with console exception log:
#PostMapping(value = BASE_NAME,consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE )
ResponseEntity<AuthenticationDTO> login ( #RequestBody MultiValueMap body);
https://pastebin.com/UREcv7CW
Do I get it correctly that 415 response occurs due to token based configuration and it cant retrieve it from the header? Also any advice to configure both ways of authentication are welcome. Thanks!
ps: spring security config -
spring:
security:
saml2:
relyingparty:
registration:
okta:
identityprovider:
entity-id: https://www.okta.com/************
verification.credentials:
- certificate-location: classpath:credentials/okta.cert
singlesignon.url: https://trial-8410773.okta.com/app/trial-********/sso/saml
singlesignon.sign-request: false

Related

Spring Security with OAuth2 losing session

We have a Spring Boot-based Gateway using Spring Security, OAuth2 login, and Zuul routing. It is also using Spring Session to store sessions in Redis. This Gateway stores an OAuth2 token in the session and forwards the OAuth2 Bearer token to backend services.
We have an issue where users are being signed out quite often. It appears this happens roughly hourly. We are not even quite sure what is causing this with all the different tools in place.
Our session cookie in the browser expires in a longer period of time. So I suspect it is either Spring invalidating the session, or the OAuth2 token expiring.
From a quick inspection of the code, it appears that OAuth2TokenRelayFilter supports refreshing the token. Is this correct?
How can track down the cause of this and fix it?
For reference, we are using these versions:
Spring Boot 2.1.12
Spring Cloud Greenwich.SR4
Here are some relevant snippets.
Our web security config for the web pages.
#Configuration
#EnableWebSecurity
#EnableOAuth2Sso
#Order(SecurityProperties.BASIC_AUTH_ORDER - 2)
#Profile("!security-disabled")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/login", "/login/**", "/favicon.ico").permitAll()
.antMatchers("/signout").authenticated()
.anyRequest().hasAnyRole("ADMIN", "MEMBER")
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.httpBasic()
.disable()
.formLogin()
.disable()
.logout()
.logoutUrl("/signout")
.deleteCookies("SESSION")
.and()
// #formatter:on
}
Security configuration for API paths.
#Configuration
#Order(SecurityProperties.BASIC_AUTH_ORDER - 2 - 10)
#Profile("!security-disabled")
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter
{
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasAnyRole("ADMIN", "MEMBER")
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.headers()
.frameOptions().sameOrigin()
.and()
.httpBasic()
.disable()
.formLogin()
.disable()
.logout()
.disable()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
// #formatter:on
}
}
Update
We have done some debugging of the Spring internals. First, we found that we were missing an OAuth2RestTemplate. Per the OAuth2 Boot documentation we found how to add it with:
#Bean
public OAuth2RestTemplate oauth2RestTemplate(
OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details)
{
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
This is now throwing an exception when OAuth2TokenRelayFilter calls restTemplate.getAccessToken().getValue();.
A redirect is required to get the users approval
This exception is thrown from AuthorizationCodeAccessTokenProvider.
OAuth2TokenRelayFilter
OAuth2TokenRelayFilter is a pre type filter which set the contexts with ACCESS_TOKEN and TOKEN_TYPE which will be used for the further authentication. It validates the tokens using getAccessToken() method and responds with "Cannot obtain valid access token" with 401 status.
You may check the validity of tokens and refresh token is correctly configured with grant_type as refresh_token as The Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired which allows clients to continue to have a valid access token without further interaction with the user.
In case if you want to disable OAuth2TokenRelayFilter, you may use the following
zuul.OAuth2TokenRelayFilter.pre.disable=true

Spring security - Disable CSRF and Authentication for specific URL (Java Conf)

I know this question is old but it is not working in my case.
I have a webapp using spring security authentication and CSRF enabled.
Now I want to expose couple of URL to expose to other application without authentication.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/rest/book").permitAll()
.antMatchers("/rest/check").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login")
.successHandler(customizeAuthenticationSuccessHandler)
//.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.permitAll();
}
I have other urls with "/rest/" which are secure. I tried csrfMatcher and with that I am able to expose "/rest/book" but then other urls are giving unexpected behavior.
Unexpected behavior like, my default login page is /login when no authentication but it stopped.

How to access swagger endpoints securely?

I have added swagger ui in my application, earlier below two url's i was able to access directly without any authentication.
http://localhost:1510/swagger-ui.html
http://localhost:1510/v2/api-docs
i need secure swagger urls, don't want anybody directly see the api details of my application.
Note :- For authentication purpose i am using JWT with spring security in my application.
SO in order to secure swagger URLS , i have made entry in spring seurity config .. below code
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/userLogin").permitAll()
.antMatchers("/v2/api-docs").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/swagger-ui.html").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.apply(securityConfigurerAdapter());
}
and when i am trying to access swagger urls , i am getting below exception on browser and as well as on eclipse console.
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
How can i pass the jwt token to see the swagger page ?

Restrict access to Swagger UI

I have swagger UI working with spring-boot. I have a stateless authentication setup for my spring rest api which is restricted based on roles for every api path.
However, I am not sure how can i put <server_url>/swagger-ui.html behind Basic authentication.
UPDATE
I have following websecurity configured via WebSecurityConfig
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
One suggestion without knowing more about your configuration is from this SO question.
https://stackoverflow.com/a/24920752/1499549
With your updated question details here is an example of what you can add:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
// add the specific swagger page to the security
.antMatchers("/swagger-ui.html").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
The problem with this is it only protects the Swagger UI page and not the API specification which is loaded as a .json file from that UI page.
A better approach is to put the swagger files under a path so that you can just add antMatchers("/swagger/**").hasRole("USER")
A bit late to answer. I carried out a small POC to execute the same. I am using Keycloak and Spring Security. Below is my configuration
http
.antMatcher("/**").authorizeRequests()
.antMatchers("/swagger-resources/**","/swagger-ui.html**","/swagger-ui/").hasRole("admin")
.anyRequest().authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.defaultAuthenticationEntryPointFor(authenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
.and()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.clearAuthentication(true)
.addLogoutHandler(keycloakLogoutHandler());
I have a working example here

two authentication mechanism on a spring boot application (Basic & JWT)

I have a spring boot app, I have just finished implementing a stateless authentication/authorization module based on jwt.
This is how I configured my security module:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.apply(securityConfigurerAdapter());
}
So basically if I want to access the url /api/jobs I get a 401 error unless I send the bearer token which I get after a succesfull authentication on /api/authenticate.
What I need to know is if it's possible to access /api/jobs without supplying the bearer token, using a basic http authentication with a login and passowrd
Yes, it's possible, just make sure you have:
http.httpBasic();
in your configuration. That builder also have other methods to configure the details for basic auth.

Resources