I am trying to secure my RESTful API using Spring 3.2.4 and Spring Security 3.2 using the #Secured annotations. I have the following setup:
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:spring/*.xml
/WEB-INF/classes/security/security-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring Security -->
<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>
<!-- Servlet configuration -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/servlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
servlet-context.xml:
<context:component-scan base-package="com.mycompany.rest.controller" />
<security:global-method-security secured-annotations="enabled" />
security-context.xml
<beans:bean id="merchantUserDetailsService" class="com.mycompany.rest.security.CustomUserDetailsService" />
<http auto-config="false" create-session="never">
<http-basic />
</http>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService" />
</authentication-manager>
I am programmatically assigning custom roles (ROLE_GROUP, ROLE_DIVISION, ROLE_READ, ROLE_WRITE) in the customUserDetailsService to the user and this works fine.
One of my controllers:
#Secured("ROLE_DIVISION")
#RequestMapping(method = RequestMethod.GET)
ResponseEntity<List<CustomerResource>> getCustomer() throws ResourceDoestNotExistException {
List<Customer> providers = // retrieve providers from DAO
List<CustomerResource> resources = customerResourceAssembler.toResources(customers);
return new ResponseEntity<>(resources, HttpStatus.OK);
}
Now to my problem, the #Secured annotations are being ignored. I want to use the #Secured annotation to avoid having to define multiple 's in the configuration. Spring Security works fine when I add at least one , but how can avoid defining them and instead rely on the #Secured annotations?
I can now access the method above with an user with the role "ROLE_GROUP".
Looks like you have everything right except that you've enabled the wrong type of annotations. If you check the documentation for global-method-security you'll see there's a separate attribute called secured-annotations which enables #Secured.
Related
I wasn't able to "autowire" inside a class that extends Spring security class (org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler).
I made it working by adding, in security-config.xml, the following code, already written inside the xml spring configuration file: <context:annotation-config />, <context:component-scan base-package="packagename...."/> and the beans that I autowired.
I have two questions:
Why have I to write twice that code (both inside the xml spring
configuration file and security-config.xml)
Is there a way to tell security-config.xml to "look" for the code
written inside the xml spring configuration file? This way I
shouldn't write the code twice.
Thank you
Try to import your security-beans.xml from your main beans.xml.
Both files should be in the same folder. the import, for example:
<import resource="spring-security.xml"/>
In your web.xml, write something like this:
<!-- to integrate Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</context-param>
2nd Approach - single beans.xml
Another approach, if you are afraid of imports, is to hold a single beans.xml that will include all beans - both the security beans as well as other beans. In this case, your web.xml will look like this:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
and your spring beans file will be spring-servlet.xml.
HTH.
I have a problem when trying to introduce Spring Security to my webapp. Here's my web.xml:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:application-context.xml
classpath:web-context.xml
classpath:security-context.xml
</param-value>
</context-param>
<context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/admin</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<session-config>
<session-timeout>30</session-timeout>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<!-- Spring Security config -->
<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>
security-context.xml:
<security:http auto-config='true'>
<security:intercept-url pattern="/admin.html" />
<security:http-basic />
</security:http>
<security:http pattern="/services/**" security="none" />
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="analyzer4321"
authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
When I'm trying to run server I have this exception on start:
java.lang.IllegalArgumentException: A universal match pattern ('/**')
is defined before other patterns in the filter chain, causing them to be ignored.
Please check the ordering in your <security:http> namespace or
FilterChainProxy bean configuration.
I have no idea what I'm doing wrong. Any suggestions?
This section in your security-context.xml file:
<security:http auto-config='true'>
<security:intercept-url pattern="/admin.html" />
<security:http-basic />
</security:http>
is processed before this (the second) one (because of their order):
<security:http pattern="/services/**" security="none" />
The first section says: restrict access to /admin.html and allow free access to any other page.
The second section is useless. It says: allow access to all pages that match /services/**. But this has already been allowed by the first section.
You can remove the second section, or put it before the first.
See the Spring Security Reference for more details on using multiple <http> tags.
BTW, <intercept-url> tag usually has an access attribute. I am not sure whether <intercept-url> can be used without access. See here for details.
The first pattern Spring security takes up is from the http tag in the pattern attribute. If no pattern attribute is declared in the http tag, it defaults to <security:http pattern="/**">
the intercept-url tag attribute is allways taken up in second place ie after de http pattern tag.
If you have two or more http tags, you should allways declare the pattern attribute with values so no conflicts occur
Most recent project I working where I trying to use Spring (3.1.1.RELEASE) Managed Hibernate Session into Seam (2.3.0.Final).
In JBoss Seam Documentation where they explain How to use Seam Managed Hibernate Session in Spring. But our requirement is invert than the documentation.
I got another solution Using Spring PlatformTransactionManagement but my requirement is use Spring Managed Hibernate Session in Seam. I don't want to use Seam manage Hibernate Session/Hibernate Entity Manager/Transaction. Only want to use Seam manage dependency injection to inject Spring bean into Seam manage bean via seam #In not Spring #Autowire.
If anybody faces such type of challenge please either help to configure Seam components.xml & Spring applicationContext.xml or provide me guide line to overcome this.
First Configure applicationContext.xml as usually you configured:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- hibernate Properties Here -->
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven/>
Then Configure components.xml as following:
<core:init debug="true" transaction-management-enabled="true" />
<spring:context-loader config-locations="classpath*:/META-INF/spring/applicationContext.xml"/>
<core:manager concurrent-request-timeout="500" conversation-timeout="120000" conversation-id-parameter="cid" parent-conversation-id-parameter="pid" />
<persistence:managed-hibernate-session name="hibernateSession" auto-create="true" session-factory="#{sessionFactory}"/>
<spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>
Its very much easy to interact Spring(3.1.1.RELEASE) with Seam (2.3.0.Final) but never forget to configure web.xml for seam.
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
For facelets your should add variable resolver in faces-config.xml
<application>
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
</application>
Better to download Seam-2.3.0.Final. Uzip it, inside examples\spring\ folder you will got your desired configuration
I would like to configure settings both blazeds and Struts2 running on springframework at the same time.
I configured web.xml like below. But one works another doesn't work.
Becaouse Struts2 filters AMF protocol.
If I comment out one of them, It works property. vice versa.
Is there any way to configure struts2 settings to work both?
web.xml
<!-- Struts2 Settings
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<!-- Flex Settings -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<!-- MessageBroker Servlet -->
<servlet>
<servlet-name>MessageBrokerServlet</servlet-name>
<display-name>MessageBrokerServlet</display-name>
<servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MessageBrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
For Devlopment
JDK1.6
Spring3.0.1
Tomcat6.0
Flex4.6
You could exclude some patterns from Struts2 filter. Define struts.action.excludePattern constant in your struts.xml file.
<constant name="struts.action.excludePattern" value=".*unfiltered.*,.*\\.nofilter"/>
I am using Spring MVC 3.0.6 and Spring security 3.0.7. I cannot #Autowire the RoleDao class to my user class when in the security context.
my web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/security-app-context.xml
</param-value>
</context-param>
<!-- 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>appServlet</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>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
The security-app-context.xml:
<beans:bean id="chineseCheckersEntryPoint" class="com.nike.golf.security.ChineseCheckersAuthenticationEntryPoint" />
<beans:bean id="chineseCheckersFilter" class="com.nike.golf.security.ChineseCheckersAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<http use-expressions="true" auto-config="false" entry-point-ref="chineseCheckersEntryPoint">
<intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')" />
<intercept-url pattern="/user/**" access="permitAll" />
<intercept-url pattern="/profile/**" access="isAuthenticated()" />
<intercept-url pattern="/secure/**" access="isAuthenticated()" />
<custom-filter position="PRE_AUTH_FILTER" ref="chineseCheckersFilter" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="chineseCheckersAuthenticationProvider" />
</authentication-manager>
<beans:bean id="chineseCheckersAuthenticationProvider" class="com.nike.golf.security.ChineseCheckersAuthenticationProvider" />
In my user object where it uses the roleDao, it's null. It has not been autowired. From all the research I have done online it seems to be related to the different contexts, and not being able to autowire between them.
Can someone help me understand these contexts and how I can get them into the same context?
Thank you everyone for your help. I managed to figure this out.
This question was similar to mine and got me moving in the right direction:
Declaring Spring Bean in Parent Context vs Child Context
This forum post really simplified the idea for me.
In your web.xml file you define the servlet context and the application context.
The application context is configured through these pieces of 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/security-app-context.xml
</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
any number of *context.xml files you pass into the context-param > contextConfigLocation are in the application context. This is the parent context.
The servlet context gets created in the web.xml file by this bit of xml:
<servlet>
<servlet-name>appServlet</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>
The servlet context as the child context has access to the application context (parent).
This was the key thing for me to understand. So I moved all configuration I had in the servlet context, up to the application context.
Like the answer in the other question I linked to above says #Autowired still does not work. Anyone know the reason for that?
So to get around this I defined the beans and the properties in the xml all the way from the property I was concerned with down to the sessionFactory.
The thing is now I could wire up the beans I needed in xml all the way up the hierarchy to sessionFactory because it was in the same context, since I moved it up to the application context from the servlet context where it was before.
In my question I didn't even post the servlet-context.xml file because I didn't think it needed to be touched, but in fact I needed to move the configuration up to the app context if I wanted to wire things up to my security beans.
I hope that makes sense.
You can imagine a context as a set of Spring beans.
Contexts can be nested, so that the outer context can access the beans from the inner one, but not the other way around. An example for this are typical web application, the have two contexts: the inner one specified with the contextConfigLocation and loaded by ContextLoaderListener, and the outer one configured with the DispatcherServlet.
One way to merge two xml files to one context, is introducing a third apllication configuration xml file, that only include then other xml files via bean:include. And then you have only to specify this third xml files for the loader. But I am not sure if you really have 2 application contexts configured for ContextLoaderListener. -- Anyway you can try the trick with the 3. xml file.