I am using Spring Security in one of my project. The web-app requires the user to login. Hence I have added few usernames and passwords in the spring-security-context.xml file as follows:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user_1" password="password_1" authorities="ROLE_USER" />
<user name="user_2" password="password_2" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
My question is, how to move these username-password pairs to a different file (like some properties file) instead of keeping them in spring-security-context.xml? And how to read that file properties file?
You can store the usernames and passwords in a separate .properties file.
<user-service id="userDetailsService" properties="users.properties"/>
users.properties should have the following format:
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled
If you want to store it in a database, I would recommend you to read this article: http://www.mkyong.com/spring-security/spring-security-form-login-using-database/
Reference: Spring Security In-Memory Authentication
You can use the PropertyPlaceholderConfigurer - put them in properties file and then reference them using EL:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-placeholderconfigurer
You can find a way to move them to a database or LDAP. Spring Security surely supports both.
I have tried the suggested ways lastly I did the following seemed to work nicely
Added these changes in your web xml
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>service</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>
Add these changes in your spring-security xml
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="${resource.service.authentication.name}"
authorities="${resource.service.authentication.authorities}"
password="${resource.service.authentication.password}"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
Add these changes into your application context xml or if you have property-loader xml even
better
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="placeholderPrefix" value="${" />
<property name="placeholderSuffix" value="}" />
<property name="locations">
<list>
<value>classpath:resourceservice.properties</value>
</list>
</property>
</bean>
Then Add these changes in your property file resourceservice.properties
memberservice.authentication.name=usename
memberservice.authentication.authorities=AUTHORISED
memberservice.authentication.password=password
Add these changes in you resource that uses Jersey
#PUT
#Path("{accountId}")
#Consumes("application/xml")
#PreAuthorize("hasRole('AUTHORISED')")
public Response methodName
This works for me for Spring security authentication and authorization using Properties file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<mvc:annotation-driven />
<bean id="webPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:abc.properties</value>
</list>
</property>
</bean>
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/stat/login" access="permitAll"/>
<security:intercept-url pattern="/stat/summary" access="hasRole('ROLE_ADMIN')" />
<security:form-login login-page="/stat/login"
default-target-url="/stat/summary" authentication-failure-url="/stat/loginError" />
</security:http>
<!-- Username and password used from xml -->
<!-- <security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="xyz" password="xyz" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager> -->
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="${stat.user}" password="${stat.pwd}" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
The abc.properties file:
stat.user=xyz
stat.pwd=xyz
The web.xml entry for spring-security implementation:
<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>
You can simply add Bean inside your Spring Security Configuration :
#Bean
public UserDetailsService userDetailsService() {
Properties users = PropertiesLoaderUtils.loadAllProperties("users.properties");
return new InMemoryUserDetailsManager(users);
}
and users.properties looks like :
admin={noop}password,ROLE_USER,ROLE_ADMIN,enabled
bob={noop}password,ROLE_USER,enabled
123={noop}123,ROLE_USER,enabled
Related
I am implementing spring security in an existing spring mvc project. I had used xml to configure the spring security. I have used this tutorial for implementing spring security
http://www.mkyong.com/spring-security/spring-security-form-login-using-database/
In my project I have a db-source file(MySQL_Datasource.xml) in resources folder just under main (outside of webapp). And the way spring security is implemented in tutorial, the datasource needs to be under webapp folder. I am facing this problem of integration.
Below is the snap of my project structure and on the right side config. code of web.xml, I have commented on the line in image where i have to define my dataSource location.
This is code of spring security where dataSource will be used
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="usr"
password-parameter="pwd" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select username,password, enabled from users where username=?"
authorities-by-username-query=
"select username, role from user_roles where username =? " />
</authentication-provider>
</authentication-manager>
</beans:beans>
I am doing this first time. I need help so that I can get this done.
UPDATE:
MYSQL_DataSource.xml code:
<bean id="dataSource" class= "org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>db.properties</value>
</property>
</bean>
and below is the db.properties values:
jdbc.url = jdbc:mysql://localhost/bhaiyag_prod_grocery
jdbc.username = newuser
jdbc.password = kmsg
If your project is correctly configured, src/main/resources folder will be packaged during project build under WEB-INF/classes.
So, if maven configuration or deployment-assembly section in project/properties is Ok, the path that you should use in your web.xml is like this:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/groceryapp-servlet.xml
/WEB-INF/spring-security.xml
/WEB-INF/classes/MySQL_DataSource.xml
</param-value>
</context-param>
It should work this way.
Once it works, have a look at this question and answers spring-scheduler-is-executing-twice and this one too web-application-context-root-application-context-and-transaction-manager-setup. In many of the Mkyong's tutorials the application context is loading twice, and I'm pretty sure it would happen the same with your project once it starts working.
As your groceryapp-servlet.xml is already loaded by Spring MVC's dispatcher servlet, you could try just removing it from contextConfigLocation setting, just this way:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
/WEB-INF/classes/MySQL_DataSource.xml
</param-value>
</context-param>
Properties loading problem:
To load correctly the db.properties, try this config in DB config xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:/db.properties</value>
</property>
</bean>
You can also specify context location relatively to current classpath. Make sure the resources folder is on your classpath and if it is. Then you can load the configuration file in your resources folder like,
<context-param>
<param-value>classpath:MySQL_DataSource.xml</param-value>
</context-param>
I'm having some throblems when I try to deploy an application which use spring securety on Jboss, the error is:
Caused by: 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
This is my applicationContext-securety.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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 security configurations -->
<!--<global-method-security pre-post-annotations="enabled"/>-->
<http pattern="/ext/**" security="none" />
<http pattern="/resources/**" security="none" />
<http pattern="/**" security="none" />
<http auto-config="true" use-expressions="true" disable-url-rewriting="true" entry-point-ref="tendwebEntryPoint">
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/index.jsp" access="isAuthenticated()" />
<!-- Filter -->
<custom-filter ref="mockimiAuthenticationFilter" after="FORM_LOGIN_FILTER"/>
</http>
<authentication-manager alias="authenticationManager" />
<beans:bean id="imiAuthenticationFilter" class="com.tend.imi.web.security.imiAuthenticationFilter">
<beans:property name="tendwebFilter" ref="tendWebFilter" />
<beans:property name="imiUserDetailsService" ref="imiUserDetailsService"/>
</beans:bean>
<!-- Filtro de la tendweb -->
<beans:bean id="tendWebFilter" class="Gci.utils.http.LoginFilter" />
<beans:bean id="tendwebEntryPoint" class="com.tend.imi.web.security.imiwebEntryPoint" />
<beans:bean id="imiUserDetailsService" class="com.tend.imi.web.security.imiUserDetailsService" />
And I'm using this in the 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>
Can anybody help me? I searched a lot but it didn't work.
Possibly a double for this question.
The problem is that you say /** is open to any user, but then you try to use auto-config.
According to the error code, this causes conflict because spring doesn't know whether /index.jsp is supposed to be open for all users or only authenticated ones.
Thanks Sir Celius for your answer.
Finally I resolved my problem. The error was in the declaration of contextConfigLocation in the web.xml, I had this:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
I don't know why, but the use of the special character "*" doesn't like to Jboss, I just change this and everything works.
I deployed this application in tomcat and weblogic and this never happend ... I think its an error that Jboss has to fix.
What's the minimal setup for spring-security OAuth2 if I want to secure a REST server for one client? I don't want to use any unnecessary setup or implement any unnecessary beans. Maybe there's an "easy" tutorial / example out there already for spring-security + OAuth2? (Though I'm trying to avoid being too hopeful about that)
My current working setup (working with the copy+past+wtf from the sparklr context) feels like too much:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:client-credentials />
</oauth:authorization-server>
<sec:authentication-manager alias="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<oauth:resource-server id="resourceServerFilter"
resource-id="rest_server" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="the_client" authorized-grant-types="client_credentials"
authorities="ROLE_RESTREAD" secret="1234567890" />
</oauth:client-details-service>
<http pattern="/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/rest/**" access="ROLE_RESTREAD" method="GET" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="false" />
<property name="clientDetailsService" ref="clientDetails" />
<property name="accessTokenValiditySeconds" value="400000" />
<property name="refreshTokenValiditySeconds" value="0" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="theRealm" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="theRealm/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
I already have implemented the authenticationManager (UserDetailsService) as a part of implementing basic spring-security so that accounts and roles are persisted against our database.
The beans I don't really get are:
userApprovalHandler: Why would I need any user approval in a client_credentials flow / grant? It seems, sparklr overrides the default TokenServicesUserApprovalHandler to auto-approve one client. Do I need to do that as well for the communication between my trusted client(s) and the server?
oauthAuthenticationEntryPoint: all sparklr does about this is:
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="sparklr2" />
</bean>
What's that supposed to do?
clientCredentialsTokenEndpointFilter
It says, I should include this only if I want to authenticate via request parameters.. So what I have in mind is exactly that: Send a GET(?) request to my server with the secret and get a token and with that token access the resources? So I'm thinking, the request for the token should contain the secret as request parameter..?
resourceServerFilter
It seems to me that this indicates a separate resource server? How does that apply if my resources are on the same server as the authentication provider?
accessDecisionManager
I don't remember having to use this when setting up my custom spring-security implementation, why would I want to do so now?
Thanks for reading through! Hope someone can answer a few of my questions..
Update
I've updated the setup to the current working state. I can now request an access token with the client credentials:
$ curl -X -v -d 'client_id=the_client&client_secret=secret&grant_type=client_credentials' -X POST "http://localhost:9090/our-server/oauth/token"
and use that token to access protected resources:
$ curl -H "Authorization: Bearer fdashuds-5432fsd5-sdt5s5d-sd5" "http://localhost:9090/our-server/rest/social/content/posts"
It still feels like a lot of setup and my questions remain. Also I'm wondering if this is the right way to go for securing the communication between trusted client and REST server in general.
It also still feels like the initial request for the token is not secure except if done via https, but will that suffice?
Also what about the token itself, should I give it a long lifetime and persist it on the client? that would in any case mean catching a token expiration exception and then requesting a new one. Or should I do the handshake for every request? What about refreshing the token? I think I read somewhere that refresh token is not secure for the client credentials grant type..? Is it necessary to send the token as HTTP header or can I change that? I don't want to use the spring-security client stack for our client as it has a rather legacy setup (jboss 5) and all we did so far was integrate REST communication capabilities with request parameters..
It would also help to know more about all the spring-security setup but the documentation is quite thin..
EDIT
Updated the spring security configuration to our current state. Also, here's our web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>the-display-name</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml</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>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>base.package.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<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/servlet-context.xml
</param-value>
</init-param>
<load-on-startup>2</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>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.appServlet</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Note: The spring-security-context.xml from above will get initialized by the servlet-context. The spring-context.xml itself only initializes the beans.
(Also: Our Server also has a few views so all rest resources run under /rest hence the url-pattern. But: It is always necessary to have a separate servlet and spring context.)
userApprovalHandler: if you only have one client in your system, I agree the users should not have to approve it accessing their data.
oauthAuthenticationEntryPoint: Normally, if authentication fails, the response type is JSON. Documentation says "If authentication fails and the caller has asked for a specific content type response, this entry point can send one, along with a standard 401 status."
clientCredentialsTokenEndpointFilter: Issuing an access token is a two-step process. First, you send the user to the resource server to authenticate. This redirect is authenticated by the client, ideally with the HTTP Headers (key + secret). In return, the client gets a code, which can be exchanged for a token.
You do not directly trade the key+secret for a token, as it contains no approval from the user.
resourceServerFilter: I think the purpose of this is indicating what clients have access to what resources, if you have many different resources.
accessDecisionManager: For OAuth2 you need a ScopeVoter, so the default Manager is not good enough.
Generally:
If you will only have one client accessing the resources on behalf of the users, then maybe consider using Digest instead of OAuth2?
And if you only want to authenticate the client (not the user), then OAuth2 is overkill. Client authentication in OAuth2 is really same as Basic Authentication over https.
A good example of oauth2 for REST clients and users with spring security ouath 2.0:
http://www.e-zest.net/blog/rest-authentication-using-oauth-2-0-resource-owner-password-flow-protocol/
I'm setting up REST services that requires simple Basic Auth on top of an existing application. The thing is that the security context already has a http tag from the actual application so as simple as it is to set up Basic Auth using the tag, I can't use it because there is already one there with totally different config (see why: https://jira.springsource.org/browse/SEC-1171 I'm using 3.0.4, waiting until 3.1 is released is a possibility but undesired).
How could I exclude my REST services from the pre-existing config and give them Basic Auth?
This is the aplicationContext-security.xml I've been playing around on top of the tutorial sample application. As it is, it has never prompted me to enter my credentials and I don't know what to add.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<global-method-security pre-post-annotations="enabled">
</global-method-security>
<beans:bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map path-type="ant">
<filter-chain pattern="/**" filters="basicAuthenticationFilter" />
</filter-chain-map>
</beans:bean>
<beans:bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<beans:property name="authenticationManager" ref="authManager" />
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
</beans:bean>
<beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<beans:property name="realmName" value="ems" />
</beans:bean>
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authManager"/>
<beans:property name="accessDecisionManager" ref="accessDecisionManager"/>
<beans:property name="securityMetadataSource">
<filter-security-metadata-source>
<intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR"/>
<intercept-url pattern="/secure/**" access="ROLE_USER" />
<intercept-url pattern="/**" access="" />
</filter-security-metadata-source>
</beans:property>
</beans:bean>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
</beans:bean>
<beans:bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
<!--
Usernames/Passwords are
rod/koala
dianne/emu
scott/wombat
peter/opal
-->
<authentication-manager alias="authManager">
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
<user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
<user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
<user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
I managed to do it by creating a second dispatcherServlet and filterChainProxy on the web.xml, and then creating a second security-context.xml specified on the of the servlets, where I could use the tag again as it was a new context. The gotcha was to set the servletContext attribute of the filters on the web.xml so that they belonged to the appropriate spring context. This is an example of one of the filters and it corresponding servlet.
<filter>
<filter-name>filterChainProxy</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.servletName</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
pathTo/servletName-servlet.xml,
pathTo/spring-security.xml
</param-value>
</init-param>
</servlet>
I am running NTLM using Spring Security, I am getting the following error
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
How can I resolve this error?
I have the following defined in 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>
Update 1
I resolved that error, now I am getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'filterSecurityInterceptor' is defined
and I have the following
<bean id="springSecurityFilterChain" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter, exceptionTranslationFilter, ntlmFilter, filterSecurityInterceptor
</value>
</property>
</bean>`
I changed my applicationContext.xml as follows because like #Sean Patrick Floyd mentioned some elements were old and dead and buried. However I have other errors now which needs to be fixed :-)
Thanks
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
<!--<authentication-manager alias="_authenticationManager"></authentication-manager>-->
<security:authentication-provider>
<security:user-service>
<security:user name="testuser" password="PASSWORD" authorities="ROLE_USER, ROLE_ADMIN"/>
<security:user name="administrator" password="PASSWORD" authorities="ROLE_USER,ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
<bean id="userDetailsAuthenticationProvider"
class="com.icesoft.icefaces.security.UserDetailsAuthenticationProvider">
<security:custom-authentication-provider/>
</bean>
<bean id="ntlmEntryPoint"
class="org.springframework.security.ui.ntlm.NtlmProcessingFilterEntryPoint">
<property name="authenticationFailureUrl" value="/accessDenied.jspx"/>
</bean>
<bean id="ntlmFilter" class="org.springframework.security.ui.ntlm.NtlmProcessingFilter">
<security:custom-filter position="NTLM_FILTER"/>
<property name="stripDomain" value="true"/>
<property name="defaultDomain" value="domain"/>
<property name="netbiosWINS" value="domain"/>
<property name="authenticationManager" ref="_authenticationManager"/>
</bean>
<bean id="exceptionTranslationFilter"
class="org.springframework.security.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="ntlmEntryPoint"/>
</bean>
<security:http access-decision-manager-ref="accessDecisionManager"
entry-point-ref="ntlmEntryPoint">
<security:intercept-url pattern="/accessDenied.jspx" filters="none"/>
<security:intercept-url pattern="/**" access="ROLE_USER"/>
</security:http>
<bean id="accessDecisionManager" class="org.springframework.security.vote.UnanimousBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<bean id="roleVoter" class="org.springframework.security.vote.RoleVoter"/>
</list>
</property>
</bean>
</beans>
From the DelegatingFilterProxy docs:
Notice that the filter is actually a
DelegatingFilterProxy, and not the
class that will actually implement the
logic of the filter. What
DelegatingFilterProxy does is delegate
the Filter's methods through to a bean
which is obtained from the Spring
application context. This enables the
bean to benefit from the Spring web
application context lifecycle support
and configuration flexibility. The
bean must implement
javax.servlet.Filter and it must have
the same name as that in the
filter-name element. Read the Javadoc
for DelegatingFilterProxy for more
information
You need to define a bean named springSecurityFilterChain that implements javax.servlet.Filter in your application context.
From Getting Started with Security Namespace Configuration:
If you are familiar with pre-namespace
versions of the framework, you can
probably already guess roughly what's
going on here. The <http> element is
responsible for creating a
FilterChainProxy and the filter beans
which it uses. Common problems like
incorrect filter ordering are no
longer an issue as the filter
positions are predefined.
So you need at least A Minimal <http> Configuration
Sean Patrick Floyd is absolutely right but I think it is worth mention one solution, which took to much time for me.
You simply add #ImportResource annotation.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"org.company"})
#ImportResource({"classpath:security.xml"})
public class CompanyWebMvcConfiguration extends WebMvcConfigurerAdapter {
}
security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http use-expressions="true">
<access-denied-handler error-page="/error"/>
</http>
In Java configuration, you can use the following annotations:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
}
That will import the org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration configuration class which defines the springSecurityFilterChain bean.
Please provide spring security file with minimal configuration
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_USER" />
</http>