I am building an application using Spring-Boot (1.2.2) using the Spring-Boot Spring-Security dependency(which comes with 3.2.6).
I have deployed my application to Tomcat as "site" context, but I have apache in front of it stripping out the "site" part of the URL (by which I mean, the public facing URL does not include the "site" element, but apache adds that in before passing through to tomcat - so stripping is probably the wrong word :).
I want to force my application to be HTTP only, so have set up the config to force that:
#Configuration
#EnableWebSecurity
class AccountSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
http.requiresChannel().anyRequest().requiresInsecure()
}
If I then visit the application on HTTPS https://example.com/homepage, Spring redirects it, but adds the "site" element back in - so now gets re-directed to http://example.com/site/homepage - which 404s.
Is there anyway to configure this redirect so it doesn't add site everytime?
Related
I have rest API where I need to secure some (UI facing) endpoints with OKTA authentication, and others (backend-facing) with Azure Active Directory. I managed to do it separately (either I can secure the endpoints with OKTA or AAD), but they don't want to work together. As soon as I add okta-spring-boot-starter to POM (or okta-spring-security-oauth2) - AAD security stops working and endpoints are either open or secured with OKTA only. I am trying to do it using WebSecurityConfigurerAdapter implementations for okta and aad:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Configuration
#Order(1)
public static class OktaAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/v1/endpoint1").authenticated()
.antMatchers("/v1/endpoint2/**").authenticated();
}
}
#Configuration
#Order(2)
public static class ActiveDirectoryAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private AADAppRoleStatelessAuthenticationFilter filter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/v1/endpoint3/**").authenticated()
.antMatchers("/v1/endpoint4/**").authenticated()
.and()
.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
}
}
This configuration however works only for endpoint1 and endpoint2 (secured with okta), other rest points are open (as if 2nd implementation of WebSecurityConfigurerAdapter was ignored). If I remove okta package from pom, AAD configuration starts working. If I switch orders of above configurations then nothing is secured. I suspect okta package does some autoconfiguration, but can't find any information about it. What am I missing?
The Okta Spring Boot Starter is mostly just a light wrapper to help configure the existing Spring Security OAuth autoconfig with a few Okta specific bits.
My first suggestion (if possible) is to try to use Spring Security OAuth for both IdPs, as it doesn't look like the AAD starter works Spring Security's built-in OAuth support (I could be wrong, I only took a quick look). Assuming AAD is just OAuth/OIDC it will just work with a little bit of configuration.
You will still need a solution to protect your given routes 1 & 2 -> Okta 3 & 4 AAD. There are a few ways to do this. You could use scopes (assuming they are different) or some other type of "authority":
http.authorizeRequests()
.antMatchers("/your/route").hasAuthority("SCOPE_custom");
The Okta Spring Boot Starter should work with other IdPs configured with Spring Security OAuth properties: https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2login-boot-property-mappings
I cannot speak 100% to what the ADD starter adds, but I'm guessing it's similar to Okta. Which is:
A common set of properties (inline with other vendor offerings)
Vendor-specific JWT validation (Spring Security only does basic JWT validation, and each vendor has its own recommendations, assuming you are using JWT access tokens)
A little sugar (for example the Okta starter adds a mapping of Okta groups to Spring Authorities)
As far as JWT validation goes Okta recommends validating JWTs like this:
https://scotch.io/tutorials/jwt-vs-opaque-access-tokens-use-both-with-spring-boot#toc-better-jwt-validation
A similar technique could be used (if needed).
Keep us posted!
I've searched a little bit on the forum but I was not able to find something suitable. I recently published my spring boot multi maven project on my server(VPS). Everything was fine, but after I secured the site over HTTPS with Let's Encrypt, the static content of the site is not being served, instead it is blocked (403).
this is my app's structure:
app
--api
--src/main/resources/static
--business
--model
--repository
static resources are inside src/main/resources/static folder of the api maven module.
I'm able to reach my site homepage using (for example): https://example-app.com/index.html
js and other resources are on the same level of index.html.
inside my security configuration of spring boot security I have:
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
as I said, before https I was perfectly able to run my app, but now when I access my index.html I have many 403 inside the browser console(js, images, css, fonts). As you can see my security configuration is very permissive, so I don't think it's here the problem.
I presume it's a spring boot misconfigured option.
UPDATE
after some testing I saw the rest api called from within the app always end in 403, but if i try to call them outside app context(from url, postman...) they all works.
It's a bit of a guess work but let's see. httpSecurity.antMatcher(/api/public/**).permitAll() should only work for users that is already authenticated. Since you use SessionCreationPolicy.STATELESS it is possible that the AuthenticationContext is not available when you call a resource within your app.
If you don't mind exposing the resources to unauthenticated users, you can try doing this instead:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(/api/public/**);
}
}
I wish to use Spring Security (version 5.1.2) to generate a CSRF token for my Angular 7 application. I have the following in my SecurityConfig file:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
with the following RequestMapping in my controller:
#RestController
#RequestMapping("/authentication")
public class AuthenticationController {
#GetMapping("/csrf")
public void getCsrfToken(){...}
#PostMapping("/register")
public RegisterOutputDTO register(#RequestBody UserDTO input){...}
}
I gathered from various sources that the csrfTokenRepository would automatically generate a cookie with header XSRF-token on my first GET call (which is what /authentication/csrf is for), but I am not getting a cookie back from the server. Hence on my next POST call I am getting a 403 response. What could I possibly be missing?
As indicated on the comments to my question, I found the answer to my problem. A cookie can not be sent cross-domain.
My frontend was deployed on localhost:3000 and my backend on localhost:9080, which are considered different domains apparently. If I go to localhost:9080 (I get a white page, but that doesn't matter) and I then go to the application tab in Chrome, I find that the XSRF cookie I was looking for is stored like I was expecting all along. The cookie was available from the GET call I executed from my front-end. The problem is that the cookie needs to be available for localhost:3000 so that Angular can make use of the cookie.
There are multiple ways you can solve this issue in your local environment.
Use a proxy
You can use a proxy to map certain url paths to your backend. This is the solution I went with.
I run my Angular application with a webpack dev server. Webpack provides an easy way to proxy certain urls to your backend. For example:
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 3000,
proxy: {
'/api': 'http://localhost:9080'
}
}
The Angular application runs on localhost:3000. Any calls to localhost:3000/api/*. will be forwarded to localhost:9080/api/*. So in my case I no longer perform a GET call on localhost:9080/api/authentication/csrf, but I call localhost:3000/api/authentication/csrf which will then get forwarded to my backend. (I added /api to the path in my rest controller, for those wondering.)
Deploy both applications on the same port
Using the frontend-maven-plugin you can build the frontend to its dist folder and then let maven package the dist folder along with the backend for deploy. I haven't tried this, but there are various resources that show this should be easy to do with Spring boot. So both frontend and backend would be available through localhost:9080 for example.
Use Spring Profile to disable csrf locally
You can make use of Spring #Profile annotations to create a different configuration for local environment and the rest (test, acceptance, production). Csrf can simply be disabled for development. I do not prefer this option since I like to keep DEV and other environments the same as much as possible. It's also not a real answer to the problem statement.
Special thanks to the answer of user #dspies which helped me find the problem.
I have migrated a Spring Boot web application from 1.5.10 to 2.0.0, which is deployed with Heroku and runs over several domains. For the main domain, that was the first one to be set, everything is working smoothly but for the rest any of the static resources; like Javascript, CSS, images and icons (Webjars) are not accessible.
maindomain.com/js/example.js works fine and can be directly accessed with the browser. secondarydomain.com/js/example.js can't be accessed by the browser and running the app arises this error, I guess because instead of the .js file is returning some text message:
Refused to execute script from '' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled
The static resources are located at:
/resources/static/css
/resources/static/js
/resources/static/images
I have set the Spring security configuration with an extension of WebSecurityConfigurerAdapter, where I have withdrawn the annotation #EnableWebSecurity and I have added this code, with the intention to make sure that those resources are accessible, without success:
http
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
There is a HandleInterceptor, which deals with the directories accessible by each secondary domain. The main one, has access all over the application.
In this other question, with a different approach to the same problem, there is an extract of the HandleInterceptor.
Spring Boot 2.0.0 & static resources with different domains for the same app
Spring Security with boot is on the classpath, the auto-configuration secures all endpoints by default.
However, when it comes to complex applications, we need different security policies per endpoints. We also need to configure which endpoints should be secured, what type of users should be able to access the endpoints, and which endpoints should be public.
WebSecurity allow we to configure adding RequestMatcher instances that Spring Security should ignore.
HttpSecurity allow we can configure the endpoints that should be secured and the endpoint that should be public
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/image/**"").permitAll()
}
}
Hope it help.
I have a spring boot service with security over Keycloak.
The Service is working fine: http://localhost:8080/api/resource (is restricted) and only after authentication via keycloak accessible.
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().antMatchers("/open/*").permitAll()
.anyRequest().authenticated();
}
Now i am using Kong as reverse proxy for the wolrd outside: The entry for that is (for instance): https://gateway.example.com/customer which redirects to http://localhost:8080
After calling https://gateway.example.com/customer/api/resource, something goes wrong, instead to call https://gateway.example.com/customer/sso/login it calls https://gateway.example.com/sso/login and so i get "404 Not Found".
It seems that the security part remove or let's say ignore "customer" in the location.
There is a possibility to correct the location?
Thanks
If you're using a route matching by path and you won't that this will be stripped you need to set strip_path to true
Check the documentation.
I know this question is old, but just had this happen. In application.properties, try using this setting:
server.use-forward-headers=true
That will tell spring boot to forward requests relative to the proxy, not your app.