Setting custom cache-control header from configuration XML for Spring Security? - spring

I am attempting to configure cache-control response header to a custom value via my Spring Security configuration XML. Unfortunately, it seems like I'm only able to disable the cache-control header from the XML configuration as per the documentation:
<http>
<headers defaults-disable="true">
<cache-control />
</headers>
</http>
Being this seems to be the case, I attempted to create a custom WebSecurityConfigurerAdapter as so:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("******* SETTING CUSTOM CACHE-CONTROL....");
StaticHeadersWriter writer = new StaticHeadersWriter("Cache-Control", "2592000");
RequestMatcher resourcesMatcher = new AntPathRequestMatcher("/**/*");
HeaderWriter resourcesHeaderWriter = new DelegatingRequestMatcherHeaderWriter(resourcesMatcher, writer);
http.headers().cacheControl().disable().addHeaderWriter(resourcesHeaderWriter);
http.headers().disable();
}
}
Unfortunately, even though the class is in fact initially called, it seems like the configuration is actually overwritten by the XML, as the cache-control response header still appears to be set to the defaults:
Any thoughts on how I can specify something similar with the XML file itself, preferably able to match a specific pattern (ex. *.js)?
Thanks!

I believe the answer that you want is already described in the question here:
disable caching for specific url in spring security
By doing something like this:
<security:http>
[intercept-url, etc omitted...]
<security:headers>
<!-- selectively applied to dynamic pages only via pattern matching, -->
<security:header ref="noCacheHeaders"/>
</security:headers>
</security:http>
<bean id="noCacheHeaders" class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<constructor-arg value="/index.html"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.web.header.writers.CacheControlHeadersWriter"/>
</constructor-arg>
</bean>

Related

spring security custom-filter with java configuration

How can I replace default filter with custom filter in java configuration? In XML it would be, for example:
<bean id="myFilter" class="lalalal.MyFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<security:http auto-config="true">
<security:custom-filter ref="myFilter" position="FORM_LOGIN_FILTER"/>
</security:http>
About filterBefore, filterAfter and default filter inhereting I know.
Assuming you have an understanding in general of Java configuration for Spring-security, adding filters is relatively simple (general details of updating spring-security config to java here):
So in your WebSecurityConfigurerAdapter implementation, do something like this:
#Configuration
#EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override protected void configure(HttpSecurity http) throws Exception {
//Custom security filters
http.addFilterBefore( myFilter(), BasicAuthenticationFilter.class );
//Rest of the security configuration goes here
...
}
That is a very cut down example - but hopefully helps enough - you would put additional security configuration here (e.g. role based restrictions, csrf, session config etc) and myFilter() is another method defining the bean you mention in the question that sets up your Filter. There is also an addFilterAfter() method and you can choose where to place your filter in the chain.
Here is an example for API security that shows some custom filters being used.

Looking for a way to apply aspects to spring-mvc controller method

The original intention was to be able to configure filter mappings with annotations (i.e. #FilteredBy below) instead of adding filter mappings to the web.xml file. Something like:
#Controller
public class MyController {
#RequestMapping(value = "/special/page.html")
#FilteredBy("SpecialBean") // <-- *** desired ***
public String doSpecialStuff() {
return "special/page";
}
}
I see that Servlet 3.0 introduces #ServletFilter which can be applied any object method and the mappings are defined by #FilterMapping. However, I want invert the responsibility of the mapping to the controller method consuming the shared logic of my "SpecialBean".
Why not use your spring context xml. If you are using mvc:annotation you can try this.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/filtered/page.htm" />
<bean class="com.yourinterceptor" />
</mvc:interceptor>
</mvc:interceptors>

Spring MVC #PathVariable with dot (.) is getting truncated

This is continuation of question
Spring MVC #PathVariable getting truncated
Spring forum states that it has fixed(3.2 version) as part of ContentNegotiationManager. see the below link.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632
In my application requestParameter with .com is truncated.
Could anyone explain me how to use this new feature? how is it configurable at xml?
Note: spring forum- #1
Spring MVC #PathVariable with dot (.) is getting truncated
As far as i know this issue appears only for the pathvariable at the end of the requestmapping.
We were able to solve that by defining the regex addon in the requestmapping.
/somepath/{variable:.+}
Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and trucate it to retrieve your parameter.
So if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
if you change your mapping to /somepath/{variable:.+} as suggested, any dot, including the last one will be consider as part of your parameter :
/somepath/param will result in a param with value param
/somepath/param.json will result in a param with value param.json
/somepath/param.xml will result in a param with value param.xml
/somepath/param.anything will result in a param with value param.anything
/somepath/param.value.json will result in a param with value param.value.json
...
If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
So, again, if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
note : the difference from the default config is visible only if you have a mapping like somepath/something.{variable}. see Resthub project issue
if you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.
Here you define only json and xml extensions :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false"/>
<property name="favorParameter" value="true"/>
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).
For that reason, you still have to override the all mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping : https://jira.springsource.org/browse/SPR-11253. Please vote if you are intereted in.
While overriding, be carreful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list bean :
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<util:list id="messageConverters">
<bean class="your.custom.message.converter.IfAny"></bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>
<bean name="exceptionHandlerExceptionResolver"
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
<property name="order" value="0"/>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
I implemented, in the open source project Resthub that I am part of, a set of tests on these subjects : see https://github.com/resthub/resthub-spring-stack/pull/219/files & https://github.com/resthub/resthub-spring-stack/issues/217
Update for Spring 4: since 4.0.1 you can use PathMatchConfigurer (via your WebMvcConfigurer), e.g.
#Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
In xml, it would be (https://jira.spring.io/browse/SPR-10163):
<mvc:annotation-driven>
[...]
<mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
In addition to Martin Frey's answer, this can also be fixed by adding a trailing slash in the RequestMapping value:
/path/{variable}/
Keep in mind that this fix does not support maintainability. It now requires all URI's to have a trailing slash - something that may not be apparent to API users / new developers. Because it's likely not all parameters may have a . in them, it may also create intermittent bugs
In Spring Boot Rest Controller, I have resolved these by following Steps:
RestController :
#GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(#PathVariable(value = "email") String email){
//code
}
And From Rest Client:
Get http://mywebhook.com/statusByEmail/abc.test#gmail.com/
adding the ":.+" worked for me, but not until I removed outer curly brackets.
value = {"/username/{id:.+}"} didn't work
value = "/username/{id:.+}" works
Hope I helped someone :)
/somepath/{variable:.+} works in Java requestMapping tag.
Here's an approach that relies purely on java configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport{
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
}
One pretty easy way to work around this issue is to append a trailing slash ...
e.g.:
use :
/somepath/filename.jpg/
instead of:
/somepath/filename.jpg
In Spring Boot, The Regular expression solve the problem like
#GetMapping("/path/{param1:.+}")
The complete solution including email addresses in path names for spring 4.2 is
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>
Add this to the application-xml
If you are using Spring 3.2.x and <mvc:annotation-driven />, create this little BeanPostProcessor:
package spring;
public final class DoNotTruncateMyUrls implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Then put this in your MVC config xml:
<bean class="spring.DoNotTruncateMyUrls" />
Finally I found solution in Spring Docs:
To completely disable the use of file extensions, you must set both of the following:
useSuffixPatternMatching(false), see PathMatchConfigurer
favorPathExtension(false), see ContentNegotiationConfigurer
Adding this to my WebMvcConfigurerAdapter implementation solved the problem:
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseSuffixPatternMatch(false);
}
For me the
#GetMapping(path = "/a/{variableName:.+}")
does work but only if you also encode the "dot" in your request url as "%2E" then it works. But requires URL's to all be that...which is not a "standard" encoding, though valid. Feels like something of a bug :|
The other work around, similar to the "trailing slash" way is to move the variable that will have the dot "inline" ex:
#GetMapping(path = "/{variableName}/a")
now all dots will be preserved, no modifications needed.
If you write both back and frontend, another simple solution is to attach a "/" at the end of the URL at front. If so, you don't need to change your backend...
somepath/myemail#gmail.com/
Be happy!
As of Spring 5.2.4 (Spring Boot v2.2.6.RELEASE)
PathMatchConfigurer.setUseSuffixPatternMatch and ContentNegotiationConfigurer.favorPathExtension have been deprecated ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-now and https://github.com/spring-projects/spring-framework/issues/24179).
The real problem is that the client requests a specific media type (like .com) and Spring added all those media types by default. In most cases your REST controller will only produce JSON so it will not support the requested output format (.com).
To overcome this issue you should be all good by updating your rest controller (or specific method) to support the 'ouput' format (#RequestMapping(produces = MediaType.ALL_VALUE)) and of course allow characters like a dot ({username:.+}).
Example:
#RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {
private final UsernameService service;
#GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
public ResponseEntity isUsernameAlreadyInUse(#PathVariable(value = "username") #Valid #Size(max = 255) String username) {
log.debug("Check if username already exists");
if (service.doesUsernameExist(username)) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
return ResponseEntity.notFound().build();
}
}
Spring 5.3 and above will only match registered suffixes (media types).
If you are using Spring 3.2+ then below solution will help. This will handle all urls so definitely better than applying regex pattern in the request URI mapping to allow . like /somepath/{variable:.+}
Define a bean in the xml file
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
The flags usage can be found on the documentation. I am putting snipped to explain
exlanation of useRegisteredSuffixPatternMatch is said to be resolving the issue. From the java doc in the class
If enabled, a controller method mapped to "/users" also matches to
"/users.json" assuming ".json" is a file extension registered with the
provided {#link #setContentNegotiationManager(ContentNegotiationManager)
contentNegotiationManager}. This can be useful for allowing only specific
URL extensions to be used as well as in cases where a "." in the URL path
can lead to ambiguous interpretation of path variable content, (e.g. given
"/users/{user}" and incoming URLs such as "/users/john.j.joe" and
"/users/john.j.joe.json").
Simple Solution Fix: adding a regex {q:.+} in the #RequestMapping
#RequestMapping("medici/james/Site")
public class WebSiteController {
#RequestMapping(value = "/{site:.+}", method = RequestMethod.GET)
public ModelAndView display(#PathVariable("site") String site) {
return getModelAndView(site, "web site");
}
}
Now, for input /site/jamesmedice.com, “site” will display the correct james'site

Configure POST ProtocolBinding in Spring Security SAML authentication request

Spring Security SAML insists on requesting the Artifact binding in the SAML authentication request (ProtocolBinding attribute):
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL="http://sp.com/saml/SSO/alias/defaultAlias"
Destination="https://idp.com/idp"
ForceAuthn="false"
ID="a4acj06d42fdc0d3494h859g3f7005c"
IsPassive="false"
IssueInstant="2012-12-05T17:07:18.271Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Version="2.0"
>
How can I configure POST binding instead?
Thanks for any answers!
-- Andreas
Thanks nobby and Sanjeev, I've recently applied this to a similar case and it put me on the right track.
Being very new to the Spring Security SAML2 extension, I had to do a little extra digging around to get the WebSSOProfileOptions applied. Essentially to get an HTTP-POST binding on the SAML authentication request you need the profile options passed to the org.springframework.security.saml.websso.WebSSOProfileImpl#sendAuthenticationRequest() method.
For our config, which is very similar to the config in the Spring RC2 sample project, this meant passing the WebSSOProfileOptions bean as described in Sanjeev's solution to the samlEntryPoint.defaultProfileOptions property (or adding a binding property there).
Trouble is, this did not result in the AuthnRequest picking up the binding property as set. In our case our SAML metadata was specifying isDefault=true on the HTTP-Artifact bound AssertionConsumerService. And in our RC2 version of the Spring Security SAML2 library this is the default behaviour of the org.springframework.security.saml.metadata.MetadataGenerator.
This can be overridden by setting the assertionConsumerIndex property of the MetadataGenerator. The HTTP Post assertion consumer gets configured at index 1 in our case.
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="assertionConsumerIndex" value="1" /><!-- 1=HTTP-POST -->
</bean>
</constructor-arg>
</bean>
In the securityContext.xml sp-initiated binding can be set. Example below used HTTP-POST
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false"/>
<property name="binding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"/>
</bean>
Values of bindings can be found in org.opensaml.common.xml.SAMLConstants class.
For anyone wanting to do it in Java rather than XML:
#Bean
public WebSSOProfileOptions profileOptions() {
WebSSOProfileOptions profileOptions = new WebSSOProfileOptions();
profileOptions.setIncludeScoping(false);
profileOptions.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
return profileOptions;
}
and:
#Bean
public MetadataGeneratorFilter metadataGeneratorFilter() {
return new MetadataGeneratorFilter(metadataGenerator());
}
public MetadataGenerator metadataGenerator() {
MetadataGenerator metadataGenerator = new MetadataGenerator();
metadataGenerator.setAssertionConsumerIndex(1);
// ...
return metadataGenerator;
}

Mapping jsp for a url in Spring 3 without using controller

How to map a jsp for a url in spring 3 without requestmapping to any controller.
eg. /login to login.jsp without having any userdefined controller in between
Like URLFILENAMECONTROLLER in spring2.5, similarly in spring 3
You can use this paragraph from Spring docs for reference. In short, you can do in several ways one of them with view-controller annotation. The other way when using Java Config:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
Where the code maps request for /login to /WEB-INF/views/login.jsp view if the view resolver is defined as in the previous answer.
You can do this:
<mvc:view-controller path="/login" view-name="login"/>
Assuming that you have defined a ViewResolver, something like this:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
This will resolve a request to /login to a /WEB-INF/views/login.jsp page

Resources