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

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.

Related

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 .

How to allow anonymous users to access a certain function only using spring security

I'm using Spring Security in my project.
I have a condition where the anonymous users should be able to read from database whereas only authorized users to add/update/delete.
How can we mention such situation in the security-config?
.antMatchers("/user/**").permitAll()
permit all requires to be authenticated but I want even non-authenticated users to access via the GET method.
#RequestMapping("/user")
#PreAuthorize("hasAuthority('USER')")
public List<UserAll> getAll() {
return userService.getAll();
}
And here how do I mention that this function should be accessed by anonymous users too?
In my WebSecurityConfig class I use this:
.authorizeRequests()
.antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**")
.permitAll()
.antMatchers("/secure/rest/**")
.authenticated()
.antMatchers("/register**")
.anonymous()
.antMatchers("/login**")
.anonymous()
.and();
What this does is it ONLY allows unauthenticated users to use the register and login endpoints. It allows ONLY authenticated users to access other endpoints (ones that start with /secure/rest.
It also allows my Swagger endpoints to be used by both authenticated and unauthenticated users.
permitAll does not require the user to be authenticated. It allows all requests through.
As a side note I recommend having different security configs per environment. I don't recommend exposing Swagger endpoints to everybody in prod environments. The above config is for my lower development environments.

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 Oauth2 SSO with Zuul Proxy

I'm modifying the oauth2-vanilla sample from Springs excellent security tutorials. The oauth2-vanilla combines the Zuul Proxy and the UI into a single application. I would like to seperate the Zuul Proxy and the UI. (The Zuul Proxy should act as an API gateway and as a reverse proxy for several UIs).
When accessing the UI via the zuul proxy, it should be able to do SSO based on Oauth2 between the UI and the resource backend.
The oauth2-vanilla looks like this
Where I want to move to something like this :
I've removed the UI part from the gateway, and added a zuul route for the ui
zuul:
routes:
resource:
url: http://localhost:9000
user:
url: http://localhost:9999/uaa/user
ui:
url: http://localhost:8080
I created a new UI webapp containing the UI (Angular stuff) with an #EnableOAuth2Sso annotation.
So I'm accessing the UI via http://localhost:8888 (through the zuul proxy).
After authenticating and doing through the UI flow, I can access the /user endpoint that returns me the user. (During debugging, I see that when I access the /user endpoint that I have an HTTP Session with an OAuth2Authentication.
When I access the /resource endpoint however, the HttpSessionSecurityContextRepository cannot find a session and is unable to build a context with the OAuth2Authentication.
I've created a git repository with the modified sample.
I'm guessing there is something wrong with the gateway configuration.
I've tried changing cookie paths, changing HttpSecurity rules in the proxy but I cannot get it to work.
What I don't understand is why the UI, when accessed through the proxy is able to resolve the /user endpoint fine (with an HTTP session and a OAuth2Authentication), but it is unable to access the /resource endpoint.
Also, as the UI is now running in the /ui context, it seems that I need to have the following code in the gateway for it to load up the angular css / js files.
.antMatchers("/ui/index.html", "/ui/home.html", "ui/css/**", "/ui/js/**").permitAll().anyRequest().authenticated();
It also doesn't seem right that I need to prefix it with the zuul ui route.
Any help would be appreciated.
I was never able to get the #EnableOauthSso to work. Instead, I annotated as an #EnableResourceServer and created a security config for Zuul.
#Configuration
#EnableResourceServer
public class JwtSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/**").hasAuthority("ROLE_API")
.and()
.csrf().disable();
}
}

Resources