Keycloak Springboot bearer only for specific endpoint and non bearer for another - spring-boot

I am trying to use keycloak springboot adapter. I want to make some endpoints with "/api" work with bearer only to true.
But I also want the endpoint "/login" to not be a bearer only endpoint and redirect the user to the keycloak OIDC login page if he is not authenticated.
How can I achieve that ?
All I have now is just bearer only for every endpoints in my application properties.
Thanks in advance for your answers :)

In web-security conf,
enable anonymous
in http-security ant-matchers, add an entry for your public routes with permitAll()
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.anonymous();
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
return http.build();
}
PS
Keycloak spring adapters are deprecated
As an alternative, you can use:
spring-addons-webmvc-jwt-resource-server tutorial here
spring-boot-starter-oauth2-resource-server tutorial there (it requires more Java conf)

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 Boot Security without Login Form

I want to add security to a Spring Boot application so I thought about using Spring Security. My only problem is the Login Form, Is there some way to authenticate a User by reading the login credentials from a config file instead of letting someone type in the name and password? I want to do that because the application will be running on a Raspberry Pi. What would be the best approach for something like that?
You can use basic authentication and pass username and password in the header.
The configuration could look like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/dashboard/**").permitAll()
.anyRequest().authenticated()
.and().httpBasic();
http.csrf().disable();
}
From the client you have to add the header:
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
The string behind Basic is the Base64 encoded username:password

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>

Accessing my api using google bearer token

I've enabled google auth by defining the following configuration along with the appropriate application.yml file.
#EnableOAuth2Sso
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"));
}
}
I can access my various endpoints through the browser. But the client might not always be a browser.
I have a controller method defined as below
#GetMapping("/user")
public Principal getUser(Principal principal) {
return principal;
}
From the Principal returned I can see the tokenValue which is of type Bearer. How can I use that against my api? Or another token for that matter. I simply want to access my own api using google auth and oauth.
wget -i http://localhost:8080/user -H "Authorization: Bearer $TOKEN"
Redirects me to the login page.
To clarify a bit more I want to authenticate using google auth but be able to access my api using oauth. Weather it's the token returned by google or one generated by spring doesn't matter. Any clues about how I can make that happen?
You can have a look at spring's tutorial focusing on oauth2, and checkout the github project. They have a nice auth-server project where you can find an exemple of what you want to achieve.
Steps to test your scenario are:
Checkout the tutorial project git clone https://github.com/spring-guides/tut-spring-boot-oauth2.git
Run the spring boot project named auth-server
cd auth-server && mvn spring-boot:run
Authenticate through http://localhost:8080
You'll find out that on auth-server side (the api server), an OAuth2Authentication principal will be available with a bearer token made available. You could use this auth-server exemple to design a Controller returning this token if user is authenticated.
Then you'll be able to wget or curl the auth-server with such requests:
curl -X GET "http://localhost:8080/me" -H "Authorization: Bearer 22e70fcf-eb60-483c-9105-xxxx"
In my tests I got following response: {"name":"674008369426415"}
without the bearer, I fortunately got:
curl -X GET "http://localhost:8080/me"
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
Missing parts of code
Looking at your code, I think you're missing the SSO Filter part of the spring's tutorial:
http.antMatcher("/**")
// more configuration here
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
and
#Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
There must be an interception of client's request somewhere, so this may be something worth looking.

how to implement a authentication with spring boot security?

i am using spring boot. i want to post a username and password params to login, and if login success then return a token. after, i will use the token to judge login status. here is my security configure code. but i don't konw where to write the login authentication logic code.
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin()
.loginPage("/user/unlogin")
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/user/login")
.antMatchers("/user/logout")
.antMatchers("/user/register");
}
}
==========================
thank you !
There's always more than one way to do something with Spring. There is a happy path (probably) with Spring Boot, and you seem to have started on it. Note though, if you want Boot to provide some default behaviour, then don't use #EnableWebSecurity (as advised in the user guide). The web-secure sample has an example you can follow.
If you use formLogin() the default login URL is /login (not /user/login), so you should be able to post the username and password to that endpoint to authenticate. Don't add /login to the unsecured paths using web.ignoring() or Spring Security will never process it. When you post to /login you get back a JSESSIONID cookie. That's your authentication token, and it expires when the session expires in the server (30min by default, but easily configurable). Include it in future requests for secure resources - some HTTP clients will even do that for you (like a browser does).

Resources