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()
...
Related
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
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>
We've seen a number of questions related to Spring Boot's Health Actuator endpoint for version 1.5+. Having gone through a number of them, we're still at a loss.
Our goals are:
To utilize Spring Boot/Spring Security's auto configuration of the security filter chaining (i.e. not have to fully implement/configure HttpSecurity)
To enable secured health access (to see a full view into the health information of the application)
To enable unsecured health access (to allow for an endpoint to function as a liveness probe in Kubernetes)
We've tried:
Using a WebSecurityConfigurerAdapter and configuring the WebSecurity object to ignore security for the /health endpoint, and then mapping a separate endpoint to the /health endpoint according to Routing multiple URLs to Spring Boot Actuator's health endpoint to hopefully enable a secured path.
Ensuring that security.oauth2.resource.filter-order=3 as was recommended in https://github.com/spring-projects/spring-boot/issues/5072. This puts the OAuth2AuthenticationProcessingFilter before the Actuator's Mvc endpoints, and allows for requests that contain pre-authenticated Authorization: Bearer ... headers (such as JWT authorizations) to be processed. However, it dictates that all requests contain authorization - otherwise, the FilterSecurityInterceptor triggers Secure object: FilterInvocation: URL: /health; Attributes: [#oauth2.throwOnError(authenticated)] and an AccessDeniedException
Utilizing Basic Authentication for /health and OAuth2 for everything else is a no-go (see Spring boot oauth2 management httpbasic authentication & https://github.com/spring-projects/spring-boot/issues/5072).
The question that we keep coming back to is how do we get:
Anonymous requests to the /health endpoint to function as unsecured
Pre-authenticated requests (i.e. those that contain pre-authenticated Authorization: Bearer ... headers) to the /health endpoint not having the appropriate authorizations or roles to function as unsecured
Pre-authenticated requests (i.e. those that contain pre-authenticated Authorization: Bearer ... headers) to the /health endpoint having the appropriate authorizations or roles to function as secured
We can easily allow any request to access /health by having something like:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers(HttpMethod.GET, "/health", "/info");
}
}
And that works great solely as a readiness/liveness probe. However, when the user is actually authenticated, it doesn't provide the benefit of seeing which backing services may be misbehaving.
Thanks in advance!
I faced something similar and this somewhat works:
Add a hacky access rule for actuators eg: #oauth2.clientHasRole('ROLE_CLIENT') or hasRole('ROLE_ANONYMOUS') that enables the security context to be populated for the actuator endpoints (for both authenticated and non authenticated requests) and tweak the 'sensitive' actuator endpoints configuration.
/health should return basic info for anonymous and full info for authenticated in this case, provided you enable the management security and mark it as non sensitive.
You still need to keep the filter configuration.
Try this, work for me
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/actuator/**","/assets/**")
.permitAll()
........
;
}
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();
}
}
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.