How to disable specific headers in Spring Boot - spring-boot

Is it possible to disable following headers in Spring Boot?
X-Forwarded-Host:
X-Host:
X-Forwarded-Server:
Following did not work for me
class MyFilter extends OncePerRequestFilter {
#Override
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
public void setHeader(String name, String value) {
if (!name.equalsIgnoreCase("X-Forwarded-Host")) {
super.setHeader(name, value);
}
}
});
}

Let's try to have a look broader and start to think about request-response lifecycle.
Once a request has been initiated by a client, there are sort of stops and layers that the request/response goes through between client and the application. There might be a firewall, load-balancer, reverse proxy, middleware etc. On the other hand, based on the application server which serves the application, those headers might be added as well. If there is a mechanism which adds or removes or rewrites the headers apart from the application, those headers should have been managed out of the application.
That being said, if headers were added by the application, they could have been managed within the application. But if headers were added by another stop or layer, they should have been managed in a particular configuration.
Apart from the headers in general, if we think about these specific headers: Based on my general experience, the headers you provided are added when there is a reverse proxy between client and application.
You can leverage more information about them: https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#x-headers
To sum up, you should be managing those headers according to how and why they have been added.

If you want to disable all default headers you can do the folowing:
#EnableWebSecurity
public class WebSecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
// do not use any default headers unless explicitly listed
.defaultsDisabled()
.cacheControl(withDefaults())
);
return http.build();
}
}
To disable specific ones you can follow the same strategy.
Reference: https://docs.spring.io/spring-security/reference/5.8/servlet/exploits/headers.html#page-title

Related

Spring endpoint prevent default accept header */*

I'm creating an endpoint where I want to force the user to set the Accept http header:
#GetMapping("/")
public void get(#RequestHeader(HttpHeaders.ACCEPT) MediaType accept) {
//accept == MediaType.ALL
}
Problem:
localhost:8080/ without any Accept header results in Accept=*/* on Spring side.
Question: how can I tell Spring to not use the */* all by default, and reject requests directly without that header?
What you want (force the user to set the Accept http header),
What you catch (without any Accept header results in Accept=*/* at back-end),
What you ask (how can I tell Spring to not use the */* all by default, and reject requests directly without that header)
Answer:
You use Spring Security config. No out-of-the-box setting
https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties.security
Write custom filter check header, implement GenericFilterBean.
public class CustomAuthenticationFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
// Get header and validate from request object.
filterChain.doFilter(request, response);
}
}
Hook the filter into your security configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// other security config
.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

SM_USER for every requests from SIteminder (Static requests as well)

Siteminder sending SM_USER (userId) back to application for all requests including static resource requests. we dont need userId in every request header except for specified Url.
Can anyone help how can avoid this in Spring boot+Siteminder configuration?
below using Siteminder filter,
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(siteminderFilter(), RequestHeaderAuthenticationFilter.class)
......
......
}
#Bean
public RequestHeaderAuthenticationFilter siteminderFilter() throws Exception {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader(smEmpID);
filter.setAuthenticationManager(authenticationManagerBean());
filter.setCheckForPrincipalChanges(true);
filter.setExceptionIfHeaderMissing(false);
return filter;
Thanks.
You can set DisableUserNameVars=No in your ACO and it will stop sending SM_USER
For the urls you need userid you can setup custom header with userid like HTTP_SM_USER.
Please note, as per documentation, using SM_USER inside the application is not advisable.
For few other applications (like integrating with SAP or other apps) you must have SM_USER, so there you have no escape.

Spring Security OAuth - how to disable login page?

I want to secure my application with Spring Security, using OAuth 2. However, I don't want the server to redirect incoming unauthorized requests, but instead to respond with HTTP 401. Is it possible?
Example: this code redirects requests to a default login page.
application.properties
spring.security.oauth2.client.registration.google.client-id=...
spring.security.oauth2.client.registration.google.client-secret=...
AuthConfig.java
#Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login();
// https://stackoverflow.com/questions/31714585/spring-security-disable-login-page-redirect
// deos not work
// .and()
// .formLogin().successHandler((request, response, authentication) -> {});
}
}
You need to create new authentication entry point and set it in configuration.
#Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login();
}
}
public class AuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AuthenticationEntryPoint() {
super("");
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(401, "Unauthorized");
}
}
You need to set oauth2Login.loginPage in your HttpSecurity config and create a controller mapping to return whatever you want. Here's a simple example.
So in your security config
http
.authorizeRequests()
.antMatchers("/noauth").permitAll()
.oauth2Login()
.loginPage("/noauth")
In a controller
#GetMapping("/noauth")
public ResponseEntity<?> noAuth() {
Map<String, String> body = new HashMap<>();
body.put("message", "unauthorized");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(body);
}
You can pass a map or pojo to the body method.
I would like to expand on Petr's answer by explaining that apparently for the time being first of all, the default login page is shown when there are more than one OAuth2 configured providers. I would expect that Spring Boot would have a smart trick to bypass this page easily and choose the right provider automatically, basing e.g. on the existence of the provider's client ID in the original request. I found out the hard way that this is not the case. So the way to do this is.. this not very apparent trick of providing a custom handler for failures - that will REDIRECT the user to the correct OAuth2 endpoint for each provider, based on the original HTTP request URL. I tried this and it works and I spent a whole day trying all manners of other solutions - my original scenario was to pass additional parameters to OAuth2 scheme in order to be able to get them back on successful authentication - they used to do this appending Base64 encoded information to the "state" URL request parameter, but Spring Security does not allow this at the moment. So the only alternative was to call a Spring Security-protected URL with those parameters already there, so when the successful authentication happens, this URL is accessed again automatically with those parameters intact.
Related: Multiple Login endpoints Spring Security OAuth2

configuring interceptors to perform "pre-tasks" on hitting endpoints in spring based web app

I am required to perform some pre-task whenever few specific endpoints are hit in my spring based web app. I came across the interceptor component provided by the spring-security framework. I searched various forums but didn't find relevant answers for configuring and adding interceptor.
Consider a situation where I am required to set some key=value in a database by sending POST request in the database whenever the user hits following endpoints.
/endpoint1
/endpoint2
/endpoint3
/endpoint4
After completion of the pre-task user should be redirected to the origin endpoint.
How can this be achieved using an interceptor in the spring-security framework?
Spring Security is for security stuff related to Authentification and Authorization. You can trigger some action if somebody logged in, but if you just need to trigger action for each request than Spring Security is not a good place for that (according to business logic), better add just filter. Anyway answering to your question:
The best way is to add custom filter to Spring Security Filter Chain:
You have to overwrite:
#Configuration
public class CustomWebSecurityConfigurerAdapter
extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(
new CustomFilter(), BasicAuthenticationFilter.class);
}
}
and create your custom filter:
public class CustomFilter extends GenericFilterBean {
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//your logic here
chain.doFilter(request, response); //it's needed to pass your request father
}
}
Code taken from baeldung.com see for more information

#EnableOAuth2Sso - How to protect / unprotect resources?

I’m trying to use the #EnableOAuth2Sso feature in Spring Cloud Security. Specifically, I’m attempting to protect some resources with OAuth2 while leaving others publicly accessible. I've managed to get this working, but I'm looking at the resulting code and wondering if there is a cleaner way.
I’m following the documentation here: https://github.com/spring-cloud/spring-cloud-security/blob/master/src/main/asciidoc/spring-cloud-security.adoc AND similar guidance from the Spring Boot reference. I have a tiny code example that illustrates my dilemma: https://github.com/kennyk65/oAuthSsoExample.
In a nutshell, I want the localhost:8080/unprotected resource to be publicly available, and I want the localhost:8080/protected resource to require OAuth2 (via github, as configured). I’m able to get the basic OAuth2 behavior to work just fine, but causing /unprotected to be publicly available is problematic.
First, The docs indicate that you can just use the OAuth2SsoConfigurer’s match() method to specify the resources to protect. I've found this doesn't work; when I try I get an IllegalStateException saying that at least one mapping is required. This appears to be referring to the unimplemented configure(HttpSecurity) method.
Next, I’ve tried to specify a mapping in configure(HttpSecurity) that states that the ‘unprotected’ resources should be unprotected. However, this results in Http basic security being applied to that resource. Curiously, this results in the ‘protected’ resource being completely public!
// This results in “unprotected” being protected by HTTP Basic
// and “protected” being completely open!
#Configuration
protected static class OauthConfig extends OAuth2SsoConfigurerAdapter {
#Override
public void match(RequestMatchers matchers) {
matchers.antMatchers("/protected/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/unprotected/**").permitAll();
}
}
On a whim I tried deliberately adding that the protected resource should be authenticated. This resulted in the protected resource getting OAuth2 protection (hurrah!) but the unprotected resource got http basic security applied (huh?).
// This results in “protected” being protected by OAuth 2
// and “unprotected” being protected by HTTP Basic, even though we say permitAll():
#Configuration
protected static class OauthConfig extends OAuth2SsoConfigurerAdapter {
#Override
public void match(RequestMatchers matchers) {
matchers.antMatchers("/protected/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/protected/**”).authenticated();
.antMatchers("/unprotected/**").permitAll();
}
}
At wit’s end to try to find the magic combination, I tried simply switching HTTP basic authentication off using security.basic.enabled: false. This worked (hurrah!), though I’m still a bit puzzled what the issue is with the mappings.
So I guess my question is, is this correct? What is the best way to protect some resources with OAuth 2 and leave others alone?
If you match on /protected/** then it makes no sense to then add an access rule to /unprotected/** (the path doesn't match so the rule will never be applied). You either need another filter chain for your "unprotected" resources, or a wider match for the SSO one. In the former case, the default one that you get from Spring Security will do if you don't mind switching off the security it is providing. E.g.
#Configuration
protected static class OauthConfig extends OAuth2SsoConfigurerAdapter {
#Override
public void match(RequestMatchers matchers) {
matchers.antMatchers("/protected/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**”).authenticated();
}
}
and set security.basic.enabled=false.

Resources