How to apply spring-mobile-device interceptor to welcome-file? - spring

I,m using SpringMVC and i have different design for each device type Desktop/Tablet/Mobile
<!-- START of MOBILE -->
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean
class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver" />
<bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
<mvc:interceptors>
<!-- Resolve the device which has generated the request -->
<bean
class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
<!-- User's site preference -->
<bean
class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />
<!-- Redirects users to the device specific site -->
<bean
class="org.springframework.mobile.device.switcher.SiteSwitcherHandlerInterceptor"
factory-method="urlPath">
<constructor-arg value="/m" />
<constructor-arg value="/t" />
<constructor-arg value="/" />
</bean>
</mvc:interceptors>
<!-- Device aware view resolving -->
<bean id="liteDeviceDelegatingViewResolver"
class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
<constructor-arg>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</constructor-arg>
<property name="mobilePrefix" value="m/" />
<property name="tabletPrefix" value="t/" />
<property name="normalPrefix" value="/" />
<property name="enableFallback" value="true" />
</bean>
<!-- END of MOBILE -->
I have /m /t and / folders views in /WEB-INF/views/ folder for each device and all works fine, but this configuration not applies only to welcome page, ie I open page with phone and see desktop-version of login.jsp (/WEB_INF/views/login.jsp but not /WEB-INF/views/m/login.jsp)
<welcome-file-list>
<welcome-file>/WEB-INF/views/login.jsp</welcome-file>
</welcome-file-list>
What I have to do to change to fix it.

Just don't specify page... and handle 'home' request by controller :)
modify your web.xml to:
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
or just remove tag
now, your HomeController should look like this:
#Controller
public class HomeController {
#RequestMapping("/")
public String home(SitePreference sitePreference, Model model) {
return "login";
}
}
hope this helps.

Related

Using both Thymeleaf and JSP

I was using JSP + JSTL but I'm boring of c:if, c:choose, ...
So, I want my JSP pages to be rendered with both JSP and Thymeleaf (I plan to remove all JSTL as soon as possible). I am using the Spring MVC framework:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
<!-- Thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="2" />
</bean>
In my controller, I just return the jsp without extenion.
return "folder/page";
Can my JSP pages be renderd first with the JSP resolver and then with the Thymeleaf resolver? If yes, how?
It seems that it is very complicated to chain JSP and Thymeleaf. So, I want to use the Internal resolver for JSP files and Thymeleaf template resolver for HTML files. How can I do it?
According to this post on the Thymeleaf forum, you have two solutions.
First solution :
Remove the suffix property in your bean declaration (<property name="suffix" value=".html" /> and <property name="suffix" value=".jsp" />) and pass the suffix in the return value of your controllers, e.g. :
#RequestMapping("/view1")
public String thymeleafView(){
return "mythymeleafview.html";
}
#RequestMapping("/view2")
public String jspView(){
return "myjspview.html";
}
Second solution :
Add the viewNames property to the resolvers. The value is the name of a folder which contains views depending on their extension. So you will have one folder for JSP files and another for HTML (thymeleaf) files, e.g. :
Configuration
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".html" />
<property name="viewNames" value="thymeleaf/*" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="viewNames" value="jsp/*" />
<property name="suffix" value=".jsp" />
</bean>
Controller
#RequestMapping("/view1")
public String thymeleafView() {
return "thymeleaf/mythymeleafview";
}
#RequestMapping("/view2")
public String jspView() {
return "jsp/myjspview";
}
Project folder
WEB-INF/views/jsp/myjspview.jsp
WEB-INF/views/thymeleaf/mythymeleafview.jsp
Both solutions work but have some contraints. You have to specify one way or another whether you want to resolve with JSP or Thymeleaf.
The "perfect" solution to chain JSP and Thymeleaf — which would consist in trying to resolve the view with JSP when it cannot be resolved with Thymeleaf or vice versa — is not possible, and Daniel Fernández (Thymeleaf team) explained why in this same post :
Thymeleaf allows you to create whichever ITemplateResolver implementation you wish, including some that might not allow to determine whether the template exists or not before actually reading it. [...] So, there is no way for Thymeleaf to be sure whether a template will be resolvable or not before trying to process the template. And that's why the ThymeleafViewResolver has to resort to the "viewNames" property.
Alternatively, two servlets works fine. The key is to keep servlet configuration minimal and include an appConfig.xml for database and other services (this avoids massive duplication of configuration)
Web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC Application</display-name>
<servlet>
<servlet-name>AssessmentAdmin</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AssessmentAdmin</servlet-name>
<url-pattern>/xz/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AssessmentAdminTL</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AssessmentAdminTL</servlet-name>
<url-pattern>/xztl/*</url-pattern>
</servlet-mapping>
........
servlet for jsp:
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- <property name="viewNames" value="jsp/*" />-->
<property name="suffix" value=".jsp" />
</bean>
..........
<import resource="applicationContext.xml" />
</beans>
servlet for thymeleaf
<mvc:annotation-driven />
<!-- Thymeleaf -->
<bean id="templateResolver"
class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/html/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false" />
</bean>
<bean id="templateEngine"
class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
<import resource="applicationContext.xml" />
Tried it and it works fine
Here is the answer based on #Igd response
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="viewNames" value="*.jsp" />
</bean>
<!-- Thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="templateMode" value="HTML5" />
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewNames" value="redirect*" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="viewNames" value="*.html" />
</bean>
And i use this for the mapping:
#RequestMapping("/view1")
public String thymeleafView(){
return "mythymeleafview.html";
}
#RequestMapping("/view2")
public String jspView(){
return "myjspview.jsp";
}
according to #Athanor's answer,we may have another choice.
we use property "viewNames" to control which resolver the template select
<!-- jsp -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
<property name="viewNames" value="*admin/*,*packer/*,*courier/*,/" />
</bean>
<!-- thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine" ref="templateEngine" />
<property name="viewNames" value="*thymeleaf/*" />
<property name="order" value="2" />
</bean>
and the controller
#RequestMapping(value="/test")
public ModelAndView dboxPrint(Model model){
ModelAndView modelAndView = new ModelAndView("thymeleaf/dbox_print");
return modelAndView;
}

Spring Security-acl. Users do not receive permission

It seems to be all right. Authorization is working, and users get the roles. I protected the methods of using annotations (for example #PreAuthorize("hasPermission(#post, 'READ')") ), it works and I get access denied. I created a database in which he described the rights of users to objects. I created a database which contains the user's permission on objects.
My problem is that after the user's authorization, it is not getting permissions, and even if the user has the authority to object, he gets access denied. Also, I noticed that after a user login in the log file of the server should get a string which will write what permission he got, but I have no such line.
Pieces of my files:
web.xml
...
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
/WEB-INF/acl-context.xml
/WEB-INF/mvc-dispatcher-servlet.xml
</param-value>
</context-param>...
mvc-dispatcher-servlet.xml
...
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<context:annotation-config />
<tx:annotation-driven />
<tx:jta-transaction-manager />
<context:component-scan base-package="com.bla-bla.bla.controllers" />
<mvc:annotation-driven />
...
spring-security.xml
...
<security:http auto-config="true" use-expressions="true"
access-denied-page="/auth/denied.html">
<security:intercept-url pattern="/auth/login.html" access="permitAll" />
<security:form-login login-page="/auth/login.html"
authentication-failure-url="/auth/login.html?error=true"
default-target-url="/index.html" />
<security:logout invalidate-session="true"
logout-success-url="/auth/login.html" logout-url="/auth/logout.html" />
</security:http>
<security:authentication-manager>
<security:authentication-provider
user-service-ref="userService">
<security:password-encoder ref="pswEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<bean id="userService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="jndiJboss" />
<property name="usersByUsernameQuery"
value="SELECT login, pass, enabled FROM accounts WHERE login=?" />
<property name="authoritiesByUsernameQuery"
value="SELECT login, authority FROM accounts WHERE login=?" />
</bean>
<bean
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"
id="pswEncoder" />
...
acl-context.xml
...
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"
p:permissionEvaluator-ref="permissionEvaluator"
p:roleHierarchy-ref="roleHierarchy" />
<bean class="org.springframework.security.acls.AclPermissionEvaluator" id="permissionEvaluator">
<constructor-arg ref="aclService"/>
</bean>
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
<constructor-arg ref="jndiJboss"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="jndiJboss"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg ref="auditLogger"/>
</bean>
<bean id="jndiJboss" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/JBossDB"/>
</bean>
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="auditLogger" class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
</value>
</property>
</bean>
...
An example of a protected method of the controller
#Override
#RequestMapping(value = "/post/delete.html", method = RequestMethod.GET)
#Transactional
#PreAuthorize("hasPermission(#post, 'READ')")
public String delete(final Post post) {
//some actions
return "post/view";
}
In what could be the problem?
UPD. My problem was in the wrong filling acl_object_identity
Post the code that uses the ACLs (secured method invocations) and also highlight those classes in the Spring config files. Also, why are you placing the <security:global-method-security /> element in your MVC config file?

How do you implement Restlet Basic HTTP Authentication on a router?

I read the Restlet documentation on how to implement Basic HTTP Authentication but mine is not working when I make a request to a resource. Any reason why mine is not working?
Application Context:
<!-- Used to map routes to Restlet resources -->
<bean id="router" class="org.restlet.ext.spring.SpringRouter">
<property name="attachments">
<map>
<!-- I removed the actual values because it references a company -->
<entry key="/getCompanies" value="ClassResource" />
<entry key="/getList" value="ClassResource" />
<entry key="/getFile" value="ClassResource" />
<entry key="/archiveFile" value="ClassResource" />
</map>
</property>
</bean>
<!-- Used to have login authentication for requests -->
<bean id="challengeAuthenticator" class="org.restlet.security.ChallengeAuthenticator">
<constructor-arg><null /></constructor-arg>
<!-- Sets the Challenge scheme parameter to the static class member -->
<constructor-arg value="#{ T(org.restlet.data.ChallengeScheme).HTTP_BASIC }" />
<constructor-arg value="WSRealm" />
<property name="next" ref="router" />
</bean>
<!-- Creates a restlet component that contains the server and attachs the application -->
<bean id="restletComponent" class="org.restlet.ext.spring.SpringComponent">
<!-- Sets the server in the Restlet component -->
<property name="server" ref="server" />
<!-- Attachs the application to the virtual host -->
<property name="defaultTarget" ref="application" />
</bean>
I was assuming that since I set the challenge Authenticator next method to the router when I make a request it hits the router and hits the authenticator before going to the resource.
Java Code:
ApplicationContext springContext = new GenericXmlApplicationContext("applicationContext.xml");
Component restletComponent = (Component) springContext.getBean("restletComponent");
GetFilesApplication application = (GetFilesApplication) springContext.getBean("application");
ChallengeAuthenticator challengeAuthenticator =
(ChallengeAuthenticator) springContext.getBean("challengeAuthenticator");
Config config = application.getConfig();
MapVerifier mapVerifier = new MapVerifier();
// Puts the user name and password (encrypted) in the map verifier
mapVerifier.getLocalSecrets().put(config.getUsername(), StringCipher.encrypt(
config.getPassword()).toCharArray());
challengeAuthenticator.setVerifier(mapVerifier);
restletComponent.getDefaultHost().attachDefault(challengeAuthenticator);
// Start the component
restletComponent.start();
Like I said earlier, the only thing I can see wrong with it is, I am unsure about setting challenge authenticator next method value to the router.
Also for the client side added:
clientResource.setChallengeResponse(ChallengeScheme.HTTP_BASIC, "correctUser", StringCipher.encrypt("password"));
Forgot to mention that I am testing this on my local machine the client and the web service.
Solved it. It took so long to figure out but here is how I got it to work.
Java Code on Server Side:
// Removed and added to Application Context
restletComponent.getDefaultHost().attachDefault(challengeAuthenticator);
Application Context:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>configuration.properties</value>
<value>log4j.properties</value>
</list>
</property>
</bean>
<bean id="config" class="Config class path location">
<property name="filePath" value="${Properties entry value}"/>
<property name="archivePath" value="${Properties entry value}"/>
<property name="username" value="${Properties entry value}"/>
<property name="password" value="${Properties entry value}"/>
</bean>
<!-- Restlet application -->
<bean id="application" class="Application class path location" scope="singleton">
<!-- Sets the router for the application -->
<property name="root" ref="router" />
<property name="config" ref="config" />
</bean>
<!-- Sets up the server -->
<bean id="server" class="org.restlet.ext.spring.SpringServer">
<constructor-arg value="${Properties entry value}" />
<constructor-arg value="${Properties entry value}" />
</bean>
<!-- Used to map routes to Restlet resources -->
<bean id="router" class="org.restlet.ext.spring.SpringRouter">
<property name="attachments">
<map>
<entry key="/getCompanies" value="Resource class path location" />
<entry key="/getList" value="Resource class path location" />
<entry key="/getFile" value="Resource class path location" />
<entry key="/archiveFile" value="Resource class path location" />
</map>
</property>
</bean>
<!-- Creates a restlet component that contains the server and attachs the application -->
<bean id="restletComponent" class="org.restlet.ext.spring.SpringComponent">
<!-- Sets the server in the Restlet component -->
<property name="server" ref="server" />
<!-- Attachs the application to the virtual host -->
<property name="defaultTarget" ref="application" />
<property name="defaultHost" ref="defaultHost" />
</bean>
<!-- Used to have login authentication for requests -->
<bean id="challengeAuthenticator" class="org.restlet.security.ChallengeAuthenticator">
<constructor-arg><null /></constructor-arg>
<!-- Sets the Challenge scheme parameter to the static class member -->
<constructor-arg value="#{ T(org.restlet.data.ChallengeScheme).HTTP_BASIC }" />
<constructor-arg value="GetWSRealm" />
<property name="next" ref="application" />
</bean>
<bean id="defaultHost" class="org.restlet.ext.spring.SpringHost">
<constructor-arg ref="restletComponent" />
<property name="defaultAttachment" ref="challengeAuthenticator" />
</bean>
Hope this helps others trying to get their application working. It took me a while to get this to work. :)

HttpSession returned null object for SPRING_SECURITY_CONTEXT

I'm trying to integrate the Spring Saml library in a sample webapplication, using Shibboleth as IDP.
I'm able to load the login page, to login and to show the index page.
The problem is that when I click on other links the webapp redirect me to the login page, then the IDP recognizes me and redirects to the requested page (if the network is fast it's very difficult to see this). It's like I'm not logged in for Spring security.
I checked the log and I found this:
org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#fde8fb. A new one will be created.
This is the web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security/securityContext.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Custom error pages -->
<error-page>
<error-code>400</error-code>
<location>/errors/missing-en.html</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/errors/restricted-en.html</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/errors/restricted-en.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/errors/missing-en.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/errors/missing-en.html</location>
</error-page>
<error-page>
<error-code>503</error-code>
<location>/errors/missing-en.html</location>
</error-page>
and the securityContext
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable autowiring -->
<context:annotation-config />
<context:component-scan base-package="org.springframework.security.saml" />
<security:http pattern="/logout.jsp" security="none" />
<security:http pattern="/login.jsp" security="none" />
<security:http pattern="/index.html" security="none" />
<security:http entry-point-ref="samlEntryPoint">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter" />
<security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter" />
</security:http>
<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint" />
<security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter" />
<security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter" />
<security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter" />
<security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter" />
</security:filter-chain-map>
</bean>
<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/" />
</bean>
<!-- Use the following for interpreting RelayState coming from unsolicited response as redirect URL: <bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
<property name="defaultTargetUrl" value="/" /> </bean> -->
<!-- Handler for successful logout -->
<bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="defaultTargetUrl" value="/logout.jsp" />
</bean>
<!-- Register authentication manager with SAML provider -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="samlAuthenticationProvider" />
</security:authentication-manager>
<!-- Logger for SAML messages and events -->
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger" />
<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="/WEB-INF/spring/security/myKeystore.jks" />
<constructor-arg type="java.lang.String" value="betfair" />
<constructor-arg>
<map>
<entry key="tomcat" value="betfair" />
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="tomcat" />
</bean>
<!-- Entry point to initialize authentication, default values taken from properties file -->
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<property name="defaultProfileOptions">
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false" />
</bean>
</property>
</bean>
<!-- IDP Discovery Service -->
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
<property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp" />
</bean>
<!-- Filter automatically generates default SP metadata -->
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator" />
</constructor-arg>
</bean>
<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter" />
<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
<!-- Do no forget to call iniitalize method on providers -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">/WEB-INF/spring/security/shibboleth.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
</bean>
</constructor-arg>
</bean>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">/WEB-INF/spring/security/localhost_sp.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="local" value="true" />
<property name="alias" value="localhost" />
<property name="securityProfile" value="metaiop" />
<property name="sslSecurityProfile" value="pkix" />
<property name="signingKey" value="tomcat" />
<property name="encryptionKey" value="tomcat" />
<property name="tlsKey" value="tomcat" />
<property name="requireArtifactResolveSigned" value="false" />
<property name="requireLogoutRequestSigned" value="false" />
<property name="requireLogoutResponseSigned" value="false" />
</bean>
</constructor-arg>
</bean>
</list>
</constructor-arg>
<!-- OPTIONAL used when one of the metadata files contains information about this service provider -->
<property name="hostedSPName" value="localhost"/>
<!-- OPTIONAL property: can tell the system which IDP should be used for authenticating user by default. -->
<!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
</bean>
<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<!-- OPTIONAL property: can be used to store/load user data after login -->
<!-- <property name="userDetails" ref="bean" /> -->
</bean>
<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl" />
<!-- Processing filter for WebSSO profile messages -->
<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="successRedirectHandler" />
</bean>
<!-- Processing filter for WebSSO Holder-of-Key profile -->
<bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="successRedirectHandler" />
</bean>
<!-- Logout handler terminating local session -->
<bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="false" />
</bean>
<!-- Override default logout processing filter with the one processing SAML messages -->
<bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
<constructor-arg ref="successLogoutHandler" />
<constructor-arg ref="logoutHandler" />
<constructor-arg ref="logoutHandler" />
</bean>
<!-- Filter processing incoming logout messages -->
<!-- First argument determines URL user will be redirected to after successful global logout -->
<bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
<constructor-arg ref="successLogoutHandler" />
<constructor-arg ref="logoutHandler" />
</bean>
<!-- Class loading incoming SAML messages from httpRequest stream -->
<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg>
<list>
<ref bean="redirectBinding" />
<ref bean="postBinding" />
<ref bean="artifactBinding" />
<ref bean="soapBinding" />
<ref bean="paosBinding" />
</list>
</constructor-arg>
</bean>
<!-- SAML 2.0 WebSSO Assertion Consumer -->
<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl" />
<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl" />
<!-- SAML 2.0 Web SSO profile -->
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl" />
<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl" />
<!-- SAML 2.0 ECP profile -->
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl" />
<!-- SAML 2.0 Logout Profile -->
<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl" />
<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
<constructor-arg ref="parserPool" />
<constructor-arg ref="velocityEngine" />
</bean>
<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
<constructor-arg ref="parserPool" />
</bean>
<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<constructor-arg ref="parserPool" />
<constructor-arg ref="velocityEngine" />
<constructor-arg>
<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient" />
</constructor-arg>
<property name="processor">
<bean id="soapProcessor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg ref="soapBinding" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<constructor-arg ref="parserPool" />
</bean>
<bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
<constructor-arg ref="parserPool" />
</bean>
<!-- Initialization of OpenSAML library -->
<bean class="org.springframework.security.saml.SAMLBootstrap" />
<!-- Initialization of the velocity engine -->
<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine" />
<!-- XML parser pool needed for OpenSAML parsing -->
<bean id="parserPool" class="org.opensaml.xml.parse.BasicParserPool" scope="singleton" />
Any idea?
Thanks
emanuele
I've experienced the same problem. After debugging realized that SecurityContext is cleared before it's persisted. After googling I found this: https://jira.springsource.org/browse/SEC-2027
Moving to spring security version 3.1.2 solved it for me.
I hope it will help someone.
If you are not particular about using Spring, or you can try something that works first and move to Spring later, here is a good tutorial. I have tried this, it works:
http://fczaja.blogspot.com/2012/06/idp-initiated-sso-and-identity.html
The blog author Filip is very responsive, you can get clarifications from him if necessary.

How to use multiple ViewResolvers in Spring?

I am working on a web app where I have most of my pages making use of apache tiles (2.1.2), but a few of them need to just be plain jsps.
I am having a problem in that both an InternalResourceViewResolver and a UrlBasedViewResolver will try to resolve the view no matter what, so that no matter which ordering I use, it will either fail on the plain JSP pages, or on the tiles pages.
Here is the config:
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
<property name="order" value="0"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1"/>
</bean>
To make it more clear what I am trying to do, I need to be able to have view states like this:
<view-state id="someState" view="/someDir/foo"><!--render foo.jsp -->
<transition on="foo" to="bar"/>
</view-state>
<view-state id="someState" view="something.core"><!--render tile defintion named 'something.core' -->
<transition on="foo" to="bar"/>
</view-state>
Does anyone know how to configure things so that I can get it to render tiles definitions and plain jsps?
As you say, you cannot chain these together. The javadoc for both states clearly that they must both be at the end of the resolver chain.
I suggest that if you really need to use these togather, then you write a simple custom implementation of ViewResolver which takes the view name, and decides which of your two "real" view resolvers to delegate to. This assumes that you can tell which resolver to call based on the view name.
So you'd define a custom ViewResolver like this:
public class MyViewResolver implements ViewResolver {
private ViewResolver tilesResolver;
private ViewResolver jspResolver;
public void setJspResolver(ViewResolver jspResolver) {
this.jspResolver = jspResolver;
}
public void setTilesResolver(ViewResolver tilesResolver) {
this.tilesResolver = tilesResolver;
}
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (isTilesView(viewName)) {
return tilesResolver.resolveViewName(viewName, locale);
} else {
return jspResolver.resolveViewName(viewName, locale);
}
}
private boolean isTilesView(String viewName) {
.....
}
}
You'd need to implement the isTilesView method to decide which resolver to delegate to.
In the XML config, define this new view resolver, and make sure it appears before the other ones.
<bean class="MyViewResolver">
<property name="tilesResolver" ref="tilesViewResolver"/>
<property name="jspResolver" ref="viewResolver"/>
</bean>
I've just solved the same problem by splitting the *-servlet.xml config file in two; in my case the main application uses Tiles, but I want QUnit tests to be simple JSPs.
app-servlet.xml contains only the Tiles view resolver, tests-servlet.xml only contains the JSP view resolver and web.xml mappings are dispatching requests to the correct servlet basing on the URL.
<servlet-mapping>
<servlet-name>app</servlet-name> <!-- will reach app-servlet.xml -->
<url-pattern>/foo</url-pattern> <!-- will use "foo" Tile -->
<url-pattern>/bar</url-pattern> <!-- will use "bar" Tile -->
</servlet-mapping>
<servlet-mapping>
<servlet-name>tests</servlet-name> <!-- will reach tests-servlet.xml -->
<url-pattern>/foo-test</url-pattern> <!-- will use foo-test.jsp -->
<url-pattern>/bar-test</url-pattern> <!-- will use bar-test.jsp -->
</servlet-mapping>
It looks like you're on the right track, but the thing to bear in mind is that some view resolvers behave as if they have always resolved the view. You need to make sure to put such resolvers last in your ordering. I believe the Tiles view is one such.
Edit: whoops... yes, the other poster is correct, both of these resolvers will do 'always match' so you can't use them both in a chain. Another alterative would be to try to extend the TilesView to do a simple JSP render if it cant find a configured tile view.
Yes you can use any number of view resolver in your your project.
So you can use both 'tiles View resolver' and 'Internal view resolver' in same project. .
you have to configure a ContentNegotiatingViewResolver . .
and give order value in your view resolvers.
<property name="order" value="int Value here" />
like I have given tiles view resolver 2 and internalviewresolver 3. .It will first check in tiles definitions if a view is not found in tiles it will be checked in InternaiViewResolver
here is some configurations that works for me.
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="html" value="text/html" />
</map>
</property>
<property name="parameterName" value="accept"></property>
<property name="favorParameter" value="true"></property>
<property name="defaultContentType" value="text/html"></property>
<property name="viewResolvers">
<list>
<ref bean="tilesViewResolver" />
<ref bean="internalViewResolver" />
</list>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<!-- Configures the Tiles layout system -->
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layouts/layouts.xml</value>
<!-- Scan views directory for Tiles configurations -->
<value>/WEB-INF/views/**/views.xml</value>
</list>
</property>
</bean>
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver"
p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView">
<property name="order" value="3" />
</bean>
<bean id="internalViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
I resolved this issue by simply adding tiles definition for plain jsp's layout, like this:
<definition name="plain-jsp.layout" template="/WEB-INF/layouts/plainJsp.jspx" >
<put-attribute name="content" value=""/>
</definition>
Then you just can use this layout as template for including your simple jsp files.
<definition name="catalog/details" extends="plain-jsp.layout">
<put-attribute name="content" value="/WEB-INF/views/catalog/details.jspx"/>
</definition>
And layout template file:
<html xmlns:tiles="http://tiles.apache.org/tags-tiles"
xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:output doctype-root-element="HTML"/>
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:directive.page pageEncoding="UTF-8" />
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=8" />
</head>
<body>
<div id="content">
<tiles:insertAttribute name="content"/>
</div>
</body>
</html>

Resources