I would like any requests that do not resolve to specific controller mappings to go to a view with a name derived from the request path.
Eg localhost/success should end up rendering a view located at /WEB-INF/view/freemarker/success.ftl. I gather from the Spring documentation that this behaviour should be enabled by default, by it doesn't appear to be working with my setup.
<mvc:annotation-driven />
<mvc:interceptors>
<!-- On pre-handle, resolve the device that originated the web request -->
<bean
class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
</mvc:interceptors>
<!-- Spring Mobile -->
<bean
class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
<constructor-arg>
<!-- Freemarker -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="false" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
</constructor-arg>
<property name="mobilePrefix" value="mobile/" />
<property name="tabletPrefix" value="tablet/" />
</bean>
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/view/freemarker/" />
</bean>
Turns out there was no HandlerMapping implementation found for these requests, and so DispatcherServlet never called the DefaultRequestToViewNameTranslator.
Adding the following provided the appropriate HandlerMapping, and thus filled in the missing link. The only downside now is that it's throwing exceptions logging at SEVERE for any requests that can't be satisfied, as opposed to DispatcherServlet's more polite WARNING.
<mvc:view-controller path="/*" />
Related
I have the following beans in my contexs:
<!-- Context 1 -->
<beans profile="ldap">
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
My goal is to use the first bean only for production version another one for test purposes.
Namely when I start test based on production context I expect that production bean would be replaced by test bean with needed configuration.
But unfortunately when I tried to create two beans with same name only production bean is created and another one is ignored. Another thing that I noticed that when I tried to change test bean name to: activeDirectoryAuthProvider1 then both beans are successfully created. Can anyone explain why it happen and suggest possible solution how it can be bypassed?
You need to use different contexts for development and production. In each context you define only the relevant bean (i.e. only 1 bean with a certain name). If you use maven you can put the test/development context under src/test/resources and the production context under src/main/resources
If you do not use maven there are other approaches. You can find an example here: http://mrhaki.blogspot.it/2009/02/use-spring-configurator-to-support.html
Take a look at Spring Profiles you can have one for test and one for prod.
<beans profile="test">
<!-- Context 1 -->
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<beans profile="prod">
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
You can set the active profile in a various ways. Check the docs.
I have a security app context which works fine with Pre-authentication.
I would want to know if it is possible to have both Basic Authentication (With LDAP Bind as authentication manager) and Pre-authentication effective at the same time:
If container provides principal name, we will rely on it (and go to LDAP to get user details), and if pre-authentication of container does not happen (e.g. we have deployed in Jetty for testing without pre-authetication), we would want Basic Authentication to be used which in turns authenticated by LDAP Bind.
Is it something possible? How can I do it?
Here is my existing (simplified) app context:
<s:global-method-security
secured-annotations="enabled"
pre-post-annotations="enabled"
proxy-target-class="true" />
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<s:filter-chain-map path-type="ant">
<s:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,preAuthenticatedFilter" />
</s:filter-chain-map>
</bean>
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean
class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='true' />
</bean>
</property>
</bean>
<bean id="preAuthenticatedFilter"
class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider ref="preAuthenticatedAuthProvider" />
</s:authentication-manager>
<bean id="preAuthenticatedAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" >
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper" >
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<!-- some config skipped -->
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService" >
<constructor-arg index="0" ref="ldapUserSearch"/>
<constructor-arg index="1" ref="ldapAuthoritiesPopulator"/>
<property name="userDetailsMapper" ref="fooUserDetailsMapper" />
</bean>
<bean id="fooUserDetailsMapper" class="com.foo.FooUserDetailsMapper" />
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- some config skipped -->
</bean>
<bean id="ldapAuthoritiesPopulator"
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<!-- some config skipped -->
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.simple.SimpleLdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapAuthorities" class="com.fil.ims.LdapAuthoritiesServices" />
I have tried the followings but none of them works
add a new ldap authentication provider (org.springframework.security.ldap.authentication.LdapAuthenticationProvider), and add one more <s:authentication-provider> entry under <s:authentication-manager>, or
add a separate org.springframework.security.web.authentication.www.BasicAuthenticationFilter, which points to a new <s:authentication-provider> which points to the new ldap authentication provider (It is complaining for "An AuthenticationEntryPoint is required".)
What should be the right way to do so?
From my bare understanding, seems 2 should be the right way, if someone can give me some direction, it will be good enough.
Thanks
Here is what I want to achieve:
I am using Websphere and I want to rely on the container to do the authentication (using Kerberos+SPNEGO). When it come to Spring Security, I want to rely on the pre-authentication, and use LDAP to retrieve user details (roles etc) for authorization checking.
Here is the part of Spring app context config I have (tried to only include related parts)
<s:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="true" />
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<s:filter-chain-map path-type="ant">
<s:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,preAuthenticatedFilter" />
</s:filter-chain-map>
</bean>
<s:http use-expressions="true" create-session="stateless" auto-config="true">
<!--
<s:http-basic />
-->
</s:http>
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='true' />
</bean>
</property>
</bean>
<bean id="preAuthenticatedFilter"
class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider ref="preAuthenticatedAuthenticationProvider" />
</s:authentication-manager>
<bean id="preAuthenticatedAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" >
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper" >
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService" >
<constructor-arg index="0" ref="ldapUserSearch"/>
<constructor-arg index="1" ref="ldapAuthoritiesPopulator"/>
<property name="userDetailsMapper" >
<bean class="com.foo.MyUserDetailsMapper" />
</property>
</bean>
<bean id="ldapContextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<!-- some setting skipped here -->
</bean>
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- some setting skipped here -->
</bean>
<bean id="ldapAuthoritiesPopulator"
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<!-- some setting skipped here -->
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.simple.SimpleLdapTemplate">
<constructor-arg ref="ldapContextSource" />
</bean>
It mostly worked, I can see correct user name and role coming in for my custom UserDetailsMapper (com.foo.MyUserDetailsMapper) which comes from LDAP, and inside that I am returning a new UserDetails with updated roles.
The problem is, in my controller, when I tried to do
SecurityContextHolder.getContext().getAuthentication()
It is returning null. (For which works before I change to pre-authentication)
Is there anything I missed?
Found the problem. Sorry that is mostly because of my own implementation fault which is not visible in the question itself.
My custom UserDetails impl is incorrectly having getEnabled() returning false. In LdapAuthenticationProvider, it is working fine as there is no checking on the user status.
However, in PreAuthenticatedAuthenticationProvider, by default there is a UserDetailsChecker which checks the status of user, for which getEnabled() returning false will cause the user details checker to fail silently, and causing authentication not populated to SecurityContext (i.e. treating that account as not authenticated)
Although it is mostly my implementation issue, I think still worth leaving here as a reference for difference of LdapAuthenticationProvider and PreAuthenticatedAuthenticationProvider
In my Spring MVC 3.1 application, I think I can't use "<mvc:annotation-driven />". Why? Because I want to apply an interceptor to all mappings except to the "<mvc:resources" elements. So I can't use :
<mvc:annotation-driven />
<mvc:resources order="-10" mapping="/public/**" location="/public/" />
<mvc:resources order="-10" mapping="/favicon.ico" location="/public/favicon.ico" />
<mvc:resources order="-10" mapping="/robots.txt" location="/public/robots.txt" />
<mvc:resources order="-10" mapping="/humans.txt" location="/public/humans.txt" />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.my.Interceptor" />
</mvc:interceptor>
</mvc:interceptors>
Because I don't want the interceptor to apply to the resources and there is no way (I think) to specify a path for the mapping which would apply the interceptor to everything except this and that.
So I have to add my own RequestMappingHandlerMapping to be able to specify the interceptor on it, and not globally. Because of this and this, it seems I can't simply define my own RequestMappingHandlerMapping while keeping the <mvc:annotation-driven /> element!
So... With some help, I've been able to get rid of the <mvc:annotation-driven /> element and pretty much everything works well now. I have my interceptor applied on everything but my resources. Everything works well, except the flash scope!
#RequestMapping(value="/test", method=RequestMethod.POST)
public String test(Model model, RedirectAttributes redirectAttrs)
{
redirectAttrs.addFlashAttribute("myKey", "my message");
return "redirect:test2";
}
#RequestMapping(value="/test2")
public String test2(Model model, HttpServletRequest request)
{
Map<String, ?> map = RequestContextUtils.getInputFlashMap(request); // map is NULL
System.out.println(model.containsAttribute("myKey")); // Prints FALSE
}
The flash map is NULL and my model doesn't contain my variable. When I try with the <mvc:annotation-driven /> element it works well! So my question is: what is missing from my context to make the flash scope work?
I also did try to set "org.springframework.web" to a DEBUG logging level, and after the redirect there is nothing logged related to a FlashMap or FlashMapManager. It seems some required bean is definitely missing.
Here are the interesting parts of my context file:
<!-- commented! -->
<!-- <mvc:annotation-driven /> -->
<bean id="baseInterceptor" class="com.my.Interceptor" />
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="order" value="0" />
<property name="interceptors">
<list>
<ref bean="conversionServiceExposingInterceptor" />
<ref bean="baseInterceptor" />
</list>
</property>
</bean>
<bean id="myRequestMappingHandlerAdapter" 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">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<bean id="conversionServiceExposingInterceptor" class="org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor">
<constructor-arg ref="conversionService" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:/messages/messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<mvc:resources order="-10" mapping="/public/**" location="/public/" />
<mvc:resources order="-10" mapping="/favicon.ico" location="/public/favicon.ico" />
<mvc:resources order="-10" mapping="/robots.txt" location="/public/robots.txt" />
<mvc:resources order="-10" mapping="/humans.txt" location="/public/humans.txt" />
What is missing for the flash scope to work?
UPDATE : See my answer for the solution... Nothing was missing actually. Only the Session was not working correctly and I found a way to make it work.
I finally found what was missing for the flash scope to work!
In the action where I access the flash variables (on the page the redirect leads to), I have to use this:
public String test2(Model model, HttpServletRequest request, HttpSession session)
instead of this :
public String test2(Model model, HttpServletRequest request)
It seems that this makes the Session to work correctly and therefore makes the flash scope to work correctly too! Why? I don't know...
It looks like all you need to do is to register a flash map manager with a bean name of flashMapManager and it should get automatically initialized and used by your Dispatcher Servlet:
<bean name="flashMapManager" class="org.springframework.web.servlet.support.DefaultFlashMapManager/>
My project includes older un-annotated controllers together with newer annotation-based controllers.
I am using the latest Spring jars (3.0.5) and in my dispatcher-servlet.xml there's <mvc:annotation-driven />.
The problem is that <mvc:annotation-driven /> causes the request mapping (through the name property of the controller beans in the dispatcher-servlet.xml) to my un-annotated controllers not to work... each time I direct the request to an un-annotated controller I am getting an error message such as:
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/some_path/some_page.htm] in DispatcherServlet with name 'dispatcher'
How can I keep the un-annotated controllers as they are but tell spring to recognize their (old style) mapping?
I am looking for solutions with minimum change to the Java code of the controllers that I already have.
Thanks!
When you add <mvc:annotation-driven /> to your config, it replaces the default set of handler mappings and handler adapters, and those defaults were the ones that handled the old-style controllers.
You have 2 options. First thing to try is to remove <mvc:annotation-driven />. You can still use annotated controllers without this. It does add extra features like Jackson JSON support, but if you don't need those extra features, then you don't need it. So try your app without <mvc:annotation-driven /> and see if it still works.
Failing that, you can reinstate the mappings and adapters for your old controllers. You didn't say how your controllers used to have their URLs mapped, but try adding these to your config:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.handler.ControllerClassNameHandlerMapping"/>
If you used SimpleUrlHandlerMapping, then that should be working already.
You also need to add the HandlerAdapter back in:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
Don't just add these in blindly. Try them individually, and see what the minimal set is to get your old controllers working alongside the new ones.
I found that by exploding the mvc:annotation-driven into it's actual replacement, it was easier to figure out.
<mvc:annotation-driven /> explodes to this:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<!-- Configures a validator for spring to use -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<bean class="com.eps.web.spring.validation.SpringMessageSourceMessageInterpolator" />
</property>
</bean>
<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
Once the magic was gone, I got this error trying to load an "Old" controller:
javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.mvc.ParameterizableViewController#
From that point, I added
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
And all my old controllers worked.