Spring OAuth2 + Http basic redirection with token - spring

I'm using OAuth2 Spring setup from official spring guide - full blown authorization server part.
There are two apps - separate authorization server with user resource server embedded and a client application - using JWT OAuth.
By default if you want to navigate to protected resource of the client app you get redirected to authorization server app where you can choose which authentication provider you'd like to use for the session. The problem is I want to support also local login mechanisms.
I managed to introduce a simple login form which just gets from /user resource with Basic authentication which works fine except there is no redirection back to the resource which initiated the process in the first place and no JWT token is being issued.
Normally I would get redirected with JWT token but I guess basic authentication doesn't even have authentication success handlers not to mention SavedRequestAwareAuthenticationSuccessHandler which OAuth2ClientAuthenticationProcessingFilter seems to be using after successfully logged in.
Here's my initial idea:
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
// .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.antMatcher("/**")
.httpBasic()
.authenticationEntryPoint(LoginUrlAuthenticationEntryPoint("/"))
.and()
.authorizeRequests()
.antMatchers("/", "/login**", "/webjars/**").permitAll()
.antMatchers("/registration/**").permitAll()
.antMatchers(HttpMethod.POST, "/auth/account/password/reset*/**").permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.and().logout()
.logoutSuccessUrl("/").permitAll()
// .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().csrf().disable() // todo consider how to enable this only for parts of the service which is exposed to the web browser
.addFilterBefore(createClientFilter(), BasicAuthenticationFilter::class.java)
}
And somewhere at the end of the chain
val oldRedirectUrl = HttpSessionRequestCache().getRequest(request, response).redirectUrl
DefaultRedirectStrategy().sendRedirect(request, response, oldRedirectUrl) // all those should be in authentication success handler for basic auth
The only problem is that once the user is authenticated at auth server (port 9998) and gets redirected to initial application (port 9999) he gets the following error:
The second time he does it (when he is already authenticated) it works fine. Read somewhere that the issue might be with apps stealing each others cookies so I renamed the cookies using
server:
session:
cookie:
name: AUTH_SESSION
Config option. The resulting cookies (after authentication) under localhost domain are:
What is interesting AUTH_SESSION cookie changes its value after signing in.
Additionally I have no idea where JSESSION_ID came from. Maybe that's the problem here?
By the way it works perfectly when using formLogin auth.

Related

Configure spring security with oauth2/openid for session id but also access token

it is possible to configure spring with oauth2 to accept multiple login possibilities?
Currently I have it working with:
#Override
protected void configure(HttpSecurity http) throws Exception { // #formatter:off
http.authorizeRequests(authorizeRequests -> authorizeRequests
.anyRequest()
.authenticated())
.oauth2Login(AbstractAuthenticationFilterConfigurer::permitAll)
.addFilterAfter(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()))
.oauth2ResourceServer().jwt();
} // #formatter:on
If one tries to access an authorize ressource, he gets redirected to a login page of an identity provider, logs in and then get a session id on the client side. The access token and the refreh token are held into memory on the server side.
But now I also want to use an access token to access ressources.
But when I do this, the security application context is just null.
What do I have to do?
I have searching in the doc but could not understand how to achieve this.
I would expect to just add in application.properties:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri
And to add:
.oauth2ResourceServer().jwt() to my HttpSecurity but this does not do the work.
Found the answer, if Bearer is not set as prefix in the Authorization header when sending the token, then it will not be recognized.
Kind of normal since it is the standard...

Spring OAuth2 security concerns

I am currently implementing Authorization_Code type OAuth2 flow to have single-sign-on (SSO) on my website.
Here is my code that enables it.
#Override
protected void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.antMatchers("/login", "/authorize", "/error")
.permitAll()
.anyRequest()
.authenticated()
.and().formLogin().loginPage("https://sso.mywebsite.com").loginProcessingUrl("/perform_login")
.defaultSuccessUrl("/success",true)
.failureUrl("/error").permitAll()
.and()
.csrf()
.disable();
// #formatter:on
}
My concern is described below.
To make a login request (with username and password), sso.mywebsite.com should make a POST request to my oAuth service - http://oauth/perform_login?username=USERNAME&password=PASSWORD.
I tried it with Postman and it works. However, isn't this a security problem to send plain username and password like above in query param? I thought exposing user credential in uri (query param) could get captured by various network sniffing tools.
Is there a way to do this in different method?
As long as you are using HTTPS, your query parameters will be secure.
I am unclear, why your SSO website should make a POST to that URL (and also, why instead of having a POST body, append the parameters via the url). Shouldn't it rather "redirect" to the login page/authorization server or is the code above from your authorization server? It was a bit unclear from your description.

Spring Boot OAuth2 Single Sign On Concept not working

I am trying to develop OAuth2 Client Application with Single Sign On. I have already developed Authorization Server and tested with Client Credentials flow and its working fine. But when I try to use Authorization Code Grant with Single Sign On I could not get it right. Client application takes me to Login Screen when I access authenticated URL, but once authenticated I am redirected to call back url that's fine. But afterwards I could not access any URL as it all authenticated URL are automatically redirected to CALL BACK url. I have permitted call back url in my Security class
My requirement is once authenticated it will allow other urls normally before authentication it should not allow any url.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
.and()
.authorizeRequests()
.antMatchers("/","/index.html", "/home.html", "/login**","/webjars/**", "/error**","/favicon.ico**","/oauth/token","/oauth/authorize**","/demo/1")
.permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.httpBasic();
Here the call back url is demo/1 and Spring Security is not permitting any other url here.
My requirement is once authenticated it should allow other urls normally before authentication it should not allow any url.
http.authorizeRequests().antMatchers("/","/resources/**", "/**").permitAll().anyRequest().authenticated().and().formLogin()
.loginPage("/").permitAll().usernameParameter("username").passwordParameter("password")
.loginProcessingUrl("/j_spring_security_check").failureUrl("/")
.successHandler(myAuthenticationSuccessHandler()).and().logout().logoutSuccessUrl("/")
.logoutUrl("/logout").invalidateHttpSession(true).deleteCookies("JSESSIONID").and().csrf().disable().headers().frameOptions().sameOrigin();

How to allow certain endpoint in spring security to be allowed without authentication?

I have Spring Boot Rest API web app in which I am using spring security to have most endpoints to require authentication.
This is part of code:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
....
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatchers()
.antMatchers("/oauth/token")
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated();
}
Can some one explain what each line begining with http.csrf means?
How can I modify above code so that enpoint /bars/pk can be allowed to be accessed without requiring authentication just as if there was no Spring Security ?
By default, Spring Boot activates protection against CSRF attack (Cross Site Request Forgery attack). The attack consists of a malicious site taking advantage of a user being alredy authenticated to a site (e.g. bank) in order to trick the user to do actions on that site (e.g. fund transfer).
The protection against the attack consists of the Spring Boot application sending a token with every response and expecting the token to be sent by the client on subsequent request. If the token is not received, Spring Boot returns an error.
Sometimes, you want to disable this behavior (at your own risks), so you use csrf.disable. You might find it convenient to disable csrf protection if you develop a Stateless API, and you have no way to link a POST request to any previous requests or session. But again, you need to consider this and reason about it carefully.
Please note that CSRF protection has not effect on GET requests. It only affects state chaning requests (e.g. POST, DELETE)
In order to allow your endoints to anyone, without requiring any authentication, you need to use
http.authorizeRequests().antMatchers("/**").permitAll();
EDIT
To specifically allow unauthorized requests to /bars/pk and keep the other elements unchanged, modify your code as follows :
http.csrf().disable()
.requestMatchers()
.antMatchers("/oauth/token")
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/bars/pk").permitAll()
.anyRequest().authenticated();
Here is a complete example:
httpSecurity.authorizeRequests()
.antMatchers(HttpMethod.GET)
.permitAll() // Allow all GET requests to go unauthenticated
.antMatchers(allowedResources)
.permitAll() // Allow all requests to go unauthenticated for the specified paths
.antMatchers(protectedResources).hasRole(USER)
.antMatchers(adminResources).hasRole(ADMIN)
.anyRequest().authenticated(); // Authenticate all other request paths

Using SAML with Spring Boot behind an ELB redirects to http instead of https

I'm trying to use Okta to authenticate users from a SpringBoot application.
I've setup the app following the Okta Tutorial from : https://developer.okta.com/blog/2017/03/16/spring-boot-saml
However my app is behind an ELB, and as such the TLS is being terminated at the LB. So I've modified the configuration from the tutorial to suit my needs.
#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", serverName))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl);
}
This does the trick but there is a problem. After the user is authenticated by Okta, the user is finally redirected to a http URL instead of a https URL. I am thinking the reason for this is that the TLS is being terminated at the LB and my app is actually receiving the request with http which is being sent in the RelayState.
This is something I found : spring-boot-security-saml-config-options.md.
It contains a list of SAML properties for spring boot security. I added the following to the application.properties file
saml.sso.context-provider.lb.enabled = true
saml.sso.context-provider.lb.scheme=https
saml.sso.profile-options.relay-state=<https://my.website.com>
It doesn't change the http redirection. Is there something I am doing wrong?
When a SAML 2.0 IdP like Okta redirects back to you application the endpoint url is either based on the SAML 2.0 metadata you application expose or the configuration in the IdP.
Furthermore, it is optional to add a Destination property in SAML 2.0 AuthnRequest:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
Destination="https://my.website.com" IssueInstant="2018-11-22T09:23:08.844Z" Version="2.0" ID="id-f8ee3ab1-6745-42d5-b00f-7845b97fe953">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> ... </Issuer>
...
</samlp:AuthnRequest>

Resources