Secure several Rest Endpoint with Spring Security - spring

I am using Spring (no Boot) with several rest endpoints I want to secure
Generally my setup (using ldap) is working, but now I struggle with the configuration. This is my config:
httpSecurity
.csrf().disable()
.authorizeRequests()
.antMatchers("/positions/**", "/deals/**")
.hasAnyRole("AP_MYAPP_BASICUSER", "JOBVIEW")
.antMatchers("/requests/**/approve", "/requests/**/comment")
.hasRole("AP_MYAPP_MASTERUSER")
.antMatchers("**", "/**", "/requests/**")
.hasAnyRole("AP_MYAPP_BASICUSER", "JOBVIEW")
.and().httpBasic();
I want to make sure that all endpoints are accessible for User AP_MYAPP_BASICUSER except of endpoints "approve" and "comment" which are only for masterusers.
Example:
requests/** returns all open requests (AP_MYAPP_BASICUSER)
requests/1/approve approves the request with id = 1 (only AP_MYAPP_MASTERUSER)
requests/1/comments adds a comment to the request with id = 1 (only AP_MYAPP_MASTERUSER)
deals/** returns all open deals (AP_MYAPP_BASICUSER)
positions/** returns all open positions (AP_MYAPP_BASICUSER)
What am I doing wrong? Thanks for helping

Related

Spring SAML SSO with OKTA - InResponseTo when changing web app context

We're having a lot of trouble with OKTA SAML SSO integration with Spring Security. We're using the saml-dsl extension to Spring Security to configure the auth, and everything works fine on HTTP, however when we try to use HTTPS the authentication only works when the app is deployed on root (/) context. When we change the context to anything else, it stops working and starts throwing InResponseTo field errors and sometimes with different configurations it comes to a redirect loop.
Here's the configuration we're using:
http
.csrf()
.disable();
http
.sessionManagement().sessionFixation().none();
http
.logout()
.logoutSuccessUrl("/");
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(samlConfigurer())
.serviceProvider()
.keyStore()
.storeFilePath(config.getKeystorePath())
.password(config.getKeystorePassword())
.keyname(config.getKeyAlias())
.keyPassword(config.getKeystorePassword())
.and()
.protocol("https")
.hostname(String.format("%s:%s", serverURL, config.getServerPort()))
.basePath("/"+contextRoot)
.and()
.identityProvider()
.metadataFilePath(config.getMetadataUrl());
And we should have our OKTA setup properly as well ( https://localhost:8443/ourappcontext/saml/SSO for testing, all the other stuff too )
We've tried most of the solutions proposed on here and the Spring documentation ( empty factory, spring session management and session fixation and so on ) and nothing seems to work. Are we doing something wrong? We're currently not generation any SP metadata, could it be that this is at fault and the request is somehow redirected to the wrong place or something? Really confused as of right now, first time using SAML and I'm not sure if it's the extension, the OKTA config or the Spring config...
We're deploying on Wildfly and you set the application context on there through a separate jboss-web.xml, if that matters at all.
By default the HttpSessionStorageFactory is used and this provides HttpSessionStorage SAML message store.
--> The HTTP session cookie is the browser side key to the server side SAML message store.
When the HTTP session cookie is not sent by the browser when the SAML response is delivered to Spring Security SAML SP, it can not find the related SAML AuthNRequest and fails to compare 'InResponseTo' value with 'ID' value of matching AuthNRequest.
If you can not assure HTTP session cookie is delivered you may implement your own SAMLMessageStorageFactory and SAMLMessageStorage (as I did).

Multiple Authentication Provider in SpringBoot

In my SpringBoot application, I am trying to implement two different authorizations for two different areas.
Area 1 [API]:
/api/**
Area 2 [Admin]:
/admin/**
The Area 1 [API] is the API part of my application where I have implemented JWT Authentication. Every request that starts with /api will require an Authorization header containing jwt token.
The Area 2 [Admin]: is the admin area. Where I would like to log in with an URL from the browser, For example (/admin/login). I would like to have my username and password saved in the application.properties and for any URL that starts with /admin, I want the user to be authenticated (Session-based). I want to apply in-memory authentication in that case. I am looking for ideas to implement these two different authentications for two different areas.
You can use .authorizeRequests() method to configure endpoints for that security configuration file.
In void configure(HttpSecurity http) method in your WebSecurityConfigurerAdapter or ResourceServerConfigurerAdapter file you can use like
http
.antMatcher("/api/**")
.authorizeRequests()
...
Then spring security will start authorizing requests starting with /api path.
If added it in ResourceServerConfigurerAdapter spring oauth2 will start authorizing from there. To configure web security for an endpoint like /admin, in your WebSecurityConfigurerAdapter
http
.antMatcher("/admin/**")
.authorizeRequests()
...

Configure communication between multiple OAuth2 authorization servers and a single resource server

I'm currently setting up a single resource server that will be validating access tokens from various authorization servers.
Spring security (using the Okta security starter with this as well) seems to only allow me to set a single issuer URI.
I managed to find a solution that works but I'm unsure if this is the best practice/standard way of doing it. In the code snippet below I've explicitly setup the resources with Spring's Java Config for simplicity.
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.pathMatchers("/api/protected/by/authserver1")
.and()
.oauth2ResourceServer()
.jwt()
.jwtDecoder(ReactiveJwtDecoders.fromOidcIssuerLocation("https://authserver1")
.and()
.and()
.authorizeExchange()
.pathMatchers("/api/protected/by/authserver2")
.and()
.oauth2ResourceServer()
.jwt()
.jwtDecoder(ReactiveJwtDecoders.fromOidcIssuerLocation("https://authserver2");
return http.build()
}
This seems to work exactly as intended, tokens minted from one auth server and used on the endpoint validating the other receive 401. When the minted tokens are used on their respective endpoint, they are successfully validated.
It looks a little funny having .and() calls back to back, I'm under the impression that these chained calls are just creating multiple web filters under the hood? Either way, is this the standard way of enabling this functionality in a Spring application with Spring Security and WebFlux?
Additionally, I came across this SO question but I don't know that I'll be able to setup a 'federation provider' within the context of this project. However, If that approach is the best practice I'd like to know. However, I think that's happening to some extent at the Okta level with the federation broker mode on the auth server access policies...?
Either way, is this the standard way of enabling this functionality in a Spring application with Spring Security and WebFlux?
No. What's more the example you've provided won't work. You can investigate the ServerHttpSecurity implementation and see why. Actually when you call oauth2ResourceServer() it sets new OAuth2ResourceServerSpec or returns the old one which can be modified. So in your case only the second JwtDecoder will be applied, because it overrides the first one. If you want to configure oauth2ResourceServer per path you'll have to define multiple SecurityWebFilterChain as posted here https://stackoverflow.com/a/54792674/1646298 .

Spring boot security, applying an authentication filter only to certain routes

I'm building a web application which will contain an API and an admin interface in a single application. As a result, I need two types of authentication, token based auth for the API, and form based auth for the admin interface.
I've almost got it working by applying a filter to authenticate API tokens, however the filter is being executed for every request, and I only want it to be executes on paths matching '/api/**'.
Hopefully it's clear from my security configuration what I'm trying to do, but sadly it doesn't work as expected.
All API requests will start '/api/', while all admin interface requests will start '/admin/'. So I was hoping to apply different security rules to each.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/account/login").permitAll();
http.addFilterBefore(webServiceAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).authorizeRequests().antMatchers("/api/**").hasAuthority("APIUSER");
http.authorizeRequests().antMatchers("/admin/**").authenticated().and()
.formLogin()
.loginPage("/admin/account/login").permitAll()
.passwordParameter("password")
.usernameParameter("username")
.failureUrl("/admin/account/login?error").permitAll()
.defaultSuccessUrl("/admin/dashboard")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/admin/account/logout"))
.logoutSuccessUrl("/admin/account/login");
http.exceptionHandling().accessDeniedPage("/admin/account/forbidden");
}
There is a way to configure several HttpSecuritys depending on the url by using the antMatcher (or in more advanced cases requestMatchers) on the HttpSecurity directly (not on authorizeRequests!). See: https://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/builders/HttpSecurity.html#antMatcher-java.lang.String-
This requires defining several WebSecurityConfigurerAdapters with defined #Orders such that Spring uses the first appropriate configuration depending on the given url and the order of the configurations. For more details please take a look at the docs at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#multiple-httpsecurity
I don't know if this is the 'correct' way of doing it, but I've managed to only get the filters code to execute when a route is matched with '/api/**' by adding an if statement to the filter itself;
So within my filter I have the following;
AntPathMatcher urlMatch = new AntPathMatcher();
if (urlMatch.match("/api/**", httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()))) {
// Token authentication in here
}

Spring Security: authorize all request, except coming from trusted subnet

I have this lines in my config class:
http.authorizeRequests()
.anyRequest().authenticated();
Now I want all requests from trusted subnet to bypass Spring Security without authorization.
So, I fixed my configuration:
http.authorizeRequests()
.antMatchers("/**").hasIpAddress(127.0.0.1/24)
.anyRequest().authenticated();
Ok, machine-to-machine communication inside private subnet now works good.
Unfortunately, authorized clients from web browser have 401 error every single time.
Is there a way to write OR condition?
Like this: client has ip #.#.#.# OR should be authorized
The methods like hasIpAddress and authenticated or hasRole are there for simple access rules. Underneath they all call the access method to add an expression. You can also use this yourself to write more complex security expressions.
http.authorizeRequests()
.anyRequest().access("hasIpAddress('127.0.0.1/24') or isAuthenticated()");
There is a small mention of this in the Spring Security reference guide.

Resources