Spring security offers an XML way to configure CSRF protection by applying the <csrf /> tag into the <http> element configuration.
For development purposes, I want to occasionally switch off such protection. Normally I would edit my security-context.xml file and change to <csrf disabled="true">.
I tried to use an expression such as <csrf disabled="${someProperty:false}" /> but it's not valid because XML schema accepts only a raw boolean value.
I don't want to use an entire bean profile (for the entire <http> element) just for a single parameter that has to be switched on/off sometimes.
Any advice?
Additional info
In order to perform some unit testing with RESTClient against authenticated controllers (when I am too lazy to use JUnit with MockMvc) I both need to bypass form authentication (e.g. using <http-basic /> and instructing RESTClient on the credentials) and disable CSRF, otherwise all requests will be blocked for missing token.
My application is a WAR application and by design it uses XML configuration instead of code-based configuration
Use request-matcher-ref and create your own custom RequestMatcher.
<csrf token-repository-ref="csrfTokenRepository" request-matcher-ref="csrfRequestMatcher" />
Here is for spring bean definition:
<spring:bean class="com.faizalsidek.security.CsrfRequestMatcher" id="csrfRequestMatcher" />
<spring:bean class="org.springframework.security.web.csrf.CookieCsrfTokenRepository" id="csrfTokenRepository" />
Here is the custom CsrfRequestMatcher:
public class CsrfRequestMatcher implements RequestMatcher {
/**
* Enable CSRF flag.
*/
#Value("${csrf.enabled}")
private boolean csrfEnabled;
#Override
public final boolean matches(final HttpServletRequest request) {
return csrfEnabled;
}
}
Because I stumbled upon this Question with the same problem I'd like to complement Faizal Sidek's answer, because his answer removes the default matching of Spring security.
To keep the default behaviour when csrf is enabled you need to match the requests HTTP method like this:
Your custom request matcher:
package my.example;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;
public class CustomRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|TRACE|HEAD||OPTIONS)$");
private boolean enabled;
public CustomRequestMatcher(boolean enabled) {
this.enabled = enabled;
}
#Override
public boolean matches(HttpServletRequest httpServletRequest) {
return enabled && !allowedMethods.matcher(httpServletRequest.getMethod()).matches();
}
}
Then use it in your security.xml:
<http ...>
<csrf request-matcher-ref="requestMatcher"/>
</http>
<beans:bean id="requestMatcher" class="my.example.CustomRequestMatcher">
<beans:constructor-arg value="${myproperty}" />
</beans:bean>
Now if you set "myproperty" to false csrf is disabled, but if "myproperty" is true the default behaviour is preserved.
Related
We have a webapp which implements custom authentication via AuthenticationProvider.
This works fine now. But we want to provide an option for customer to implement their own authentication class implementing AuthenticationProvider. So they will delete our jar from app and add their jar to classpath.
It appears in security xml we need to specify only class implementing AuthenticationProvider but can't tell spring to pick any class implementing interface AuthenticationProvider
Current XML and Class implementation
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider"/>
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="w.x.y.z.CustomAuthenticationProvider"></beans:bean
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//Implementation
}
#Override
public boolean supports(Class<?> arg0) {
return true;
}
}
Is there anyway I can tell spring to pick any class implementing AuthenticationProvider?
Maybe you can do it by using type autowiring and factory method:
1-The CustomAuthenticationProvider it will be injected by type autowiring defined only in the jar added by your client and the deleted jar(it must be exactly one instance of AuthenticationProvider).
2-And then use a factory method to inject this provider into the authentication-manager.
1-first step
public class AuthenticationProviderFactory {
#Autowired
private AuthenticationProvider authProvider;
public AuthenticationProvider getAuthenticationProvider() {
return authProvider;
}
}
2-second step
<bean name="authenticationProviderFactory"
class="w.x.y.z..AuthenticationProviderFactory"></bean>
<bean name="authenticationProvider" factory-bean="authenticationProviderFactory"
factory-method="getAuthenticationProvider">
</bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
!!!! The deleted jar and the new jar must have the same applicationContext.xml name(where the AuthenticationProvider is declared) to make the replace working.
<import resource="applicationContextAuthProvider.xml"/>
I have a web application with spring security configured to limit access on both URLs and methods. I want to disable it entirely by-default, and allow my customers to easily turn it on if they want to (they can only access "spring-security.xml").
I managed to turn off the URL interception, but my method security is still enabled...
Any clue?
(I don't want to let the customer change my web.xml, so unfortunately modifying the "global-method-security" setting each time is not an option...)
This is my updated spring-security.xml configuration:
<http auto-config='true' use-expressions="true">
<intercept-url pattern="/**" access="permitAll" />
<http-basic />
<anonymous />
</http>
I have overriden the DelegatingFilterProxy.doFilter method like this:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String springSecured = System.getProperty("springSecured");
if (StringUtils.isNotBlank(springSecured) && springSecured.equalsIgnoreCase("true")) {
// Call the delegate
super.doFilter(request, response, filterChain);
} else {
// Ignore the DelegatingProxyFilter delegate
filterChain.doFilter(request, response);
}
}
and this is an example of the method security I have:
#RequestMapping(
value = "applications/{applicationName}/timeout/{timeout}",
method = RequestMethod.POST)
public
#ResponseBody
#PreAuthorize("isFullyAuthenticated() and hasPermission(#authGroups, 'deploy')")
Object deployApplication() {
// ...
}
If I were you I wouldn't use a custom filter chain implementation, just the one out of the box. You can enable and disable sections of bean configuration (since Spring 3.0) with nested elements, so something like this might be convenient:
<beans profile="secure">
<http auto-config='true' use-expressions="true">...</http>
</beans>
Your application is now unprotected in the default profile (and any other but the "secure" profile). You can enable the secure profile by providing a system property spring.profiles.active=secure, or by explicitly setting it in a context or servlet initializer.
I am trying out the HandlerInterceptors from Spring MVC 3.0.
Below is my interceptor
public class SessionInterceptor extends HandlerInterceptorAdapter {
#Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("inside preHandle");
if(request.getSession().getAttribute(SessionConsta nts.USER_SESSION_NAME) == null) {
response.sendRedirect("welcome");
return false;
}
return true;
}
}
Below is my configuration in my xml
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/services/*"/>
<bean class="com.ca.myca.interceptors.SessionInterceptor " />
</mvc:interceptor>
</mvc:interceptors>
But the interceptor is not getting called.
Please let me know if I am missing any thing.
In our application we are using double ** for any service sub-path match, so try changing it and check if it helps:
<mvc:mapping path="/services/**"/>
You are using <mvc:annotation-driven/> with mvc interceptor.
Please check on Spring reference:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/DispatcherServlet.html
"When running in a Java 5+ environment, a default AnnotationMethodHandlerAdapter will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type)."
<mvc:annotation-driven/> is supposed to be used for annotation-driven MVC controllers like #RequestMapping, #Controller etc, but I have seen there is no need to define "<mvc:annotation-driven/>" for supporting it.
Unless you are using jackson (for json support), you can try to remove <mvc:annotation-driven/> and use "<context:annotation-config>" instead for common use like autowiring etc.
try what is suggested in Configuration of Spring MVC and JSON using Jackson.
Put you interceptor in <mvc:interceptors> tag
<mvc:interceptors>
<bean class="xx.x..x..x...UserSessionInterceptor" />
</mvc:interceptors>
you can keep <mvc:annotation-driven/> and <context:annotation-config>
In reference to the post above by arviarya, <mvc:annotation-driven /> in the config XML results in a different handler Object being passed to the interceptor. In our interceptor method we had:
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) throws Exception {
if (mav != null && handler instanceof HandlerMethod) {
// something we want to have happen
}
This was being called with the #Controller-derived object without the <mvc:annotation-driven />, but was called with the HandlerMethod-derivedobject when it was present. For our if block to work, I needed the tag in our config XML.
In spring security 3.0, we are having AuthenticationProcessingFilter class, in which we were using determineTargetUrl() method, which returned the url based on different roles.
Now, we are moving to spring security 3.1.0.RC3 and I am stuck how should I now determine the url based on different roles as AuthenticationProcessingFilter class has been removed from new version. Can anyone please give me steps in brief with some code so that I can implement custom filter to redirect to different pages for different roles.
The best way to determine the target url based upon roles is to specify a target url in your Spring Security configuration as shown below. This will work in Spring 3.0 or 3.1
<http>
...
<form-login login-page="/login" default-target-url="/default"/>
</http>
Then create a controller that processes the default-target-url. The controller should redirect or forward based upon rolls. Below is an example of using Spring MVC, but any type of controller will work (i.e. Struts, a Servlet, etc).
#Controller
public class DefaultController {
#RequestMapping("/default")
public String defaultAfterLogin(HttpServletRequest request) {
if (request.isUserInRole("ROLE_ADMIN")) {
return "redirect:/users/sessions";
}
return "redirect:/messages/inbox";
}
}
The advantages to this approach are it is not coupled to any specific implementation of Security, it is not coupled to any specific MVC implementation, and it works easily with Spring Security namespace configuration. A full example can be found in the SecureMail project I presented at SpringOne this year.
An alternative is that you could create a custom AuthenticationSuccessHandler. The implementation might extend SavedRequestAwareAuthenticationSuccessHandler which is the default AuthenticationSuccessHandler. it could then be wired using the namespace as shown below.
<sec:http>
<sec:form-login authentication-success-handler-ref="authSuccessHandler"/>
</sec:http>
<bean:bean class="example.MyCustomAuthenticationSuccessHandler"/>
I would not recommend doing this as it is tied to Spring Security API's and it is better to avoid that when possible.
Using Custom Authentication Success Handler to specify the redirection based on user role after successful authentication.
You need to create Custom Authentication Success Handler as the following :
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
public class CustomeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
handle(request, response, authentication);
}
protected void handle(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
String targetUrl = determineTargetUrl(authentication);
if (response.isCommitted()) {
return;
}
redirectStrategy.sendRedirect(request, response, targetUrl);
}
protected String determineTargetUrl(Authentication authentication) {
boolean isTeacher = false;
boolean isAdmin = false;
Collection<? extends GrantedAuthority> authorities
= authentication.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
isTeacher = true;
break;
} else if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
isAdmin = true;
break;
}
}
if (isTeacher) {
return "/user/account";
} else if (isAdmin) {
return "/admin/account";
} else {
throw new IllegalStateException();
}
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
}
Then modify spring security xml file and defined your bean and use it
<bean id="customeAuthenticationSuccessHandler"
class="com.test.CustomeAuthenticationSuccessHandler"/>
<security:http auto-config="true" use-expressions="false">
<security:form-login login-page="/sign-in" login-processing-url="/sign-in" username-parameter="username"
password-parameter="password"
authentication-success-handler-ref="customeAuthenticationSuccessHandler"
always-use-default-target="true"
authentication-failure-url="/sign-in?error=true"/>
<security:logout logout-url="/logout" logout-success-url="/"/>
..
..
</security:http>
With Spring security I configure the parts of my web app that need to be secured by https with security:intercept-url tag.
For example:
<security:intercept-url pattern="/**/*secure*" requires-channel="https"/>
<security:intercept-url pattern="/**" requires-channel="http" />
This way all requests with "secure" in the file name or directories containing "secure" on the lowest level get https, the rest will get http.
Is there a way to use a flag to make Spring force https?
I could not get anything to work that takes stuff after the "?" of an url.
http://domain/abc?secure=true => https
http://domain/abc => http
Spring would then redirect transparently every request going to http://domain/abc?secure=true to https://domain/abc?secure=true.
Is there a way to achieve that?
The first pattern in the example achieves the result for a "secure" occuring before the "?", but I am looking for a solution/pattern to have a flag after the "?" only.
To make Spring consider fragments after the "?" in urls, the stripQueryStringFromUrls has to be set to false.
Here is a solutation I found in the Spring forum:
When this BeanPostProcessor is loaded, the property will be set.
public class BeanPostProcessorImpl implements BeanPostProcessor
{
final static private Logger log = Logger.getLogger(BeanPostProcessorImpl.class);
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
if (bean instanceof DefaultFilterInvocationSecurityMetadataSource)
{
log.info("********* Post-processing " + beanName);
((DefaultFilterInvocationSecurityMetadataSource) bean).setStripQueryStringFromUrls(false);
}
return bean;
}
}
This way pattern
<security:intercept-url pattern="/**/*?secure=true*" requires-channel="https"/>
finally works.
As far as I can tell you want to have a URL param which to tell spring to redirect you to an https channel.
So did you try:
<security:intercept-url pattern="/**/*?secure*" requires-channel="https"/>
or if that doesn't work try an escaped '?' :
<security:intercept-url pattern="/**/*\?secure*" requires-channel="https"/>
I just had a look at the source for the FilterChainProxy (in 3.0.5.RELEASE) and it uses regular expressions to match the patterns. So you can have a look at:
org.springframework.security.web.util.RegexUrlPathMatcher#pathMatchesUrl(Object compiledPath, String url)
or
org.springframework.security.web.FilterChainProxy#getFilters(String url)
to see exactly what pattern you need.
So even if spring currently doesn't support the '?' sign you can extend your own UrlPathMatcher and inject it into the FilterChainProxy.