I am trying to setup Spring 3 security using JDBC auth. Everything is working fine apart from when I try to specify multiple access roles to an intercept-url. Eg I want anyone with the roles ROLE_USER and ROLE_ADMIN to be able to access all pages, I use the follwoing line in my spring config file -
<security:intercept-url pattern="/**" access="ROLE_USER, ROLE_ADMIN" />
However this throws the following error -
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Unsupported configuration attributes: [ ROLE_ADMIN]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1401)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:512)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:289)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:286)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:188)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:558)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:852)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:422)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:261)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:192)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4342)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.core.StandardService.start(StandardService.java:516)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
Caused by: java.lang.IllegalArgumentException: Unsupported configuration attributes: [ ROLE_ADMIN]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.afterPropertiesSet(AbstractSecurityInterceptor.java:154)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1460)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1398)
... 27 more
If specify that only one of the roles can access any url then it is fine (fine for either role). Changing the order in which i specify the roles makes no difference either. It is as though something has changed in Spring Security 3 that now cannot handle mulitple access roles being specified.
I have successfully got this working previously with Spring Security 2, and am using virtually the same configuration. Any ideas?
My security config file is listed below -
<?xml version="1.0" encoding="UTF-8"?>
<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"
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">
<security:http auto-config="true" access-denied-page="/denied.jsp" >
<security:form-login
default-target-url="/app/home"
always-use-default-target="true" />
<security:intercept-url pattern="/**" access="ROLE_USER, ROLE_ADMIN" />
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security: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", "authority" from user_roles where "username" = ?' />
</security:authentication-provider>
</security:authentication-manager>
</beans>
I had the same issue but used expressions to get around this issue:
You should embed
use-expressions="true"
in your existing config. So:
<security:http auto-config="true" access-denied-page="/denied.jsp" >
becomes
<security:http auto-config="true" access-denied-page="/denied.jsp" use-expressions="true">
And then:
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
I am not sure about this problem, actually I am using it currently in my project and don't see an issue. try removing the space after the "," I mean try using ROLE_USER,ROLE_ADMIN
I had the same problem when was trying to migrate from Spring 3.x to 4.x. Finally I found that parameter "use-expressions" of "http" tag became "true" by default in Spring 4.x instead of false (as it was in old versions).
P.S. This question is very old for now, but I found this in Google. So somebody else can find it too and this info might be useful then.
I had the same problem and found the answer here.
Use that line to grant access to user with both roles: <security:intercept-url pattern="/**" access="hasRole('ROLE_USER') and hasRole('ROLE_ADMIN')" />
If you want to grant access to user with one of the listed roles, use: <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN')" />
Also, you need to add ability to use SpEL in your security *.xml, add use-expressions="true" to <http> tag.
I decided to downgrade to Spring Security 2.0.5 without changing anything else to check whether this was a bug in 3, and lo-and-behold it was!
I think I also found a related open bug here - https://jira.springsource.org/browse/SEC-1342
Solution - use 2.0.5 if want to use this feature.
Related
I'm using Spring security 5.1.1. I'm trying to create two security entryPoints for my application: one for REST and another for the secured urls of the application. I've created CustomAuthenticationProvider by implementing AuthenticationProvider for the authenticationManager.
I'm following the examples in :
Spring Security for a REST API and
Spring Security – Two Security Realms in one Application
But on the login page, when I enter username and password it doesn't hit the CustomAuthenticationProvider.authenticate() method at all, rather it goes to logout.html.
Below is my xml snippet of http:
<!-- Configuration for API -->
<security:http entry-point-ref="restAuthEntryPoint" pattern="/api/**" use-expressions="true">
<intercept-url pattern="/api/**" access="hasAnyRole('ROLE_DRIVER','ROLE_PARENT') and isAuthenticated()"/>
<intercept-url pattern="/api/driver/**" access="hasRole('ROLE_DRIVER') and isAuthenticated()"/>
<intercept-url pattern="/api/parent/**" access="hasRole('ROLE_PARENT') and isAuthenticated()"/>
<form-login
authentication-success-handler-ref="apiSuccessHandler"
authentication-failure-handler-ref="apiFailureHandler" />
<custom-filter ref="apiAuthenticationFilter" after="BASIC_AUTH_FILTER" />
<logout />
</security:http>
<beans:bean id="apiAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<beans:constructor-arg name="authenticationEntryPoint" ref="restAuthEntryPoint"/>
<beans:constructor-arg name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<beans:bean id="restAuthEntryPoint"
class="com.main.sts.api.security.RestAuthenticationEntryPoint"/>
<beans:bean id="apiSuccessHandler"
class="com.main.sts.api.security.MySavedRequestAwareAuthenticationSuccessHandler"/>
<beans:bean id="apiFailureHandler" class=
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/>
<!-- Configuration for Rest-API finished-->
<security:http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/school_admin/*"
access="hasAnyRole('ROLE_SCHOOLADMIN','ROLE_GUEST','ROLE_SCHOOLTEACHER','ROLE_PARENT')" />
<form-login login-page="/login" authentication-failure-url="/loginfailed"/>
<!-- <custom-filter before="FORM_LOGIN_FILTER" ref="userAuthenticationProcessingFilter" /> -->
<logout invalidate-session="true" logout-success-url="/logout" />
<access-denied-handler error-page="/404" />
<session-management invalid-session-url="/logout.html">
</session-management>
<sec:headers >
<sec:cache-control />
<sec:hsts/>
</sec:headers>
</security:http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="com.main.sts.util.CustomAuthenticationProvider">
<beans:property name="loginService" ref="loginService" />
</beans:bean>
Even if I commented out the configuration for the REST-api, still I don't get hit to that class.
Here's my CustomAuthenticationProvider:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) {
// **I never hit this class**
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
filter is defined correctly in web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
springSecurityFilterChain /*
In the login jsp, I've setup form as below:
<form class="form-vertical login-form" name='f' action="<c:url value='j_spring_security_check' />" method="post">
I can't access secured urls, it takes me to the login page; this means - this filter works. But why can't I hit CustomAuthenticationProvider? Why does it go to logout.html???
I've also tried by implementing custom filter (which eventually sets authenticationManager as the property); but still no luck.
I've also checked the log files but nothing in there.
BTW, if I try to access through curl, I get Http status 403 (forbidden). The server understood the request but refuses to authorize it.
curl -i -X POST -d username=admin -d password=Admin123 http://localhost:8080/sts/api/login
Please help me to find out the issue.
Alhamdulillah, finally I've found the issue.The code base which I originally started with was implemented on Spring 2.5. I've upgraded Spring version to 5.1. Basically /j_spring_security_check , j_username and j_password have been deprecated.
Now I've changed my jsp accordingly and it works now.
It's weird that there was no error or warning message.
Help me with the advice please.
I need to disable/enable spring security on my application by some variable in xml file.
my spring-security.xml file
<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.1.xsd">
<http auto-config="true">
<intercept-url pattern="/*" access="ROLE_ADMIN" />
<logout logout-success-url="/mainpage" />
<login login-success-url="/mainpage" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="hey" password="there" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
How can be this perfomed?
Thanks.
security
A request pattern can be mapped to an empty filter chain, by setting this attribute to none. No security will be applied and none of Spring Security's features will be available.
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/appendix-namespace.html#nsa-http-security
so:
<http auto-config="true" security="none">
and as usual the "none" parameter can be a springEL expression (well a subset anyways).
hope this is what you were looking for
EDIT:
forgot to mention that it's a new feature is Spring Security 3.1
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/new-3.1.html#new-3.1-highlevel
EDIT2:
For a more dynamic solution use bean profiles. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html#d0e1293 and http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
I want my Spring application to try two pre-authentication methods (Siteminder and Java EE container authentication).
If either of these filters locates a username - I want to check that username against my database of users and assign roles based on what I see in the database. (I have an implementation of AuthenticationUserDetailsService, which does that for me.)
If not - show a login page to the user. Check the credentials they enter in the form against my database of users.
The Siteminder integration is working. The login form is working too. My problem is with the Java EE pre-authentication. It never kicks in.
My applicationContext-security.xml:
<!-- HTTP security configurations -->
<sec:http auto-config="true" use-expressions="true">
<sec:form-login login-processing-url="/resources/j_spring_security_check" always-use-default-target="true" default-target-url="/" login-page="/login"
authentication-failure-url="/login?login_error=t" />
<sec:logout logout-url="/resources/j_spring_security_logout" />
<sec:access-denied-handler error-page="/accessDenied" />
<sec:remember-me user-service-ref="customUserDetailsService" token-validity-seconds="86400" key="OptiVLM-VaultBalance" />
<sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter"/>
<sec:custom-filter after="PRE_AUTH_FILTER" ref="jeePreAuthenticatedFilter"/>
<!-- various intercept-url elements here, skipped for brevity -->
</sec:http>
<!-- Authentication Manager -->
<sec:authentication-manager alias="authenticationManager">
<!-- J2EE container pre-authentication or Siteminder -->
<sec:authentication-provider ref="customPreAuthenticatedAuthenticationProvider" />
<!-- Default provider -->
<sec:authentication-provider user-service-ref="customUserDetailsService" />
</sec:authentication-manager>
<!-- Siteminder pre-authentication -->
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER" />
<property name="authenticationManager" ref="authenticationManager" />
<property name="exceptionIfHeaderMissing" value="false" />
</bean>
<!-- J2EE pre-authentication -->
<bean id="jeePreAuthenticatedFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<!-- Custom pre-authentication provider -->
<bean id="customPreAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="customAuthenticationUserDetailsService" />
</bean>
I have Java 2 security enabled in Websphere, and I am logged in as 'admin5'. (I have a user with this username in my user database.) But when I access the application, there is never a call to the 'customAuthenticationUserDetailsService' bean to verify the username. I know this, because 'customAuthenticationUserDetailsService' does extensive logging which clearly shows what it is doing. When I am using the Siteminder pre-authentication - the 'customAuthenticationUserDetailsService' works just fine, I get some trace output in the log. But not for the J2EE authentication...
My guess is that one of these things is happening:
a) Java EE pre-authentication filter is not locating the username, so it never calls the authentication manager
b) Java EE pre-authentication filter works fine, but my custom authentication provider is never called by the authentication manager for some reason
By the way, the default authentication provider, which uses 'customUserDetailsService' does not kick in either. Again, I can tell that because there is no output from 'customUserDetailsService' in the log.
Can you advise on what could be the problem here? If not a solution, then a suggestion on how to approach this would be greatly appreciated.
OK, I figured this out. The problem is that even though I had J2EE security setup in Websphere and was authenticated, my web.xml contained no security constraints. Because of this, Websphere was not supplying the principal for my requests. This is apparently an intentional feature. If you are not accessing a protected URL, you should not need the pre-authentication information.
To overcome this, I added a security constraint to my web.xml, which allowed ALL users to access the resources. Effectively, the resources were not secured, but still - there was a constraint now.
This is it:
<security-constraint>
<web-resource-collection>
<web-resource-name>All areas</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
This tricks the Websphere into filling in the user principal information in the request.
Thank you #Ralph for his comments on this this question: request.getUserPrincipal() got null
If I keep remember-me element in security.xml file and startup a server then I got following error.
No UserDetailsService registered.......
If I remove this remember-me element then it works fine.
How to get rid of this error...
<?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"
xmlns:p="http://www.springframework.org/schema/p"
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">
<http auto-config="false" use-expressions="true"
access-denied-page="/login.jsp?error=true" entry-point-ref="authenticationEntryPoint">
<remember-me key="abcdefgh" />
<logout invalidate-session="true" />
<intercept-url pattern="/login.jsp" access="permitAll" />
<intercept-url pattern="/index.jsp" access="permitAll" />
<intercept-url pattern="/pub" access="isAuthenticated()" />
<intercept-url pattern="/*" access="permitAll" />
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
</http>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:authenticationManager-ref="customAuthenticationManager"
p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler" />
<!-- Custom authentication manager. In order to authenticate, username and
password must not be the same -->
<beans:bean id="customAuthenticationManager" class="com.cv.pub.cmgt.framework.security.CustomAuthenticationManager" />
<!-- We just actually need to set the default failure url here -->
<beans:bean id="customAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
p:defaultFailureUrl="/login.jsp?error=true" />
<!-- We just actually need to set the default target url here -->
<beans:bean id="customAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"
p:defaultTargetUrl="/pub" />
<!-- The AuthenticationEntryPoint is responsible for redirecting the user
to a particular page, like a login page, whenever the server sends back a
response requiring authentication -->
<!-- See Spring-Security Reference 5.4.1 for more info -->
<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login.jsp" />
<!-- The tag below has no use but Spring Security needs it to autowire the
parent property of org.springframework.security.authentication.ProviderManager.
Otherwise we get an error A probable bug. This is still under investigation -->
<authentication-manager />
</beans:beans>
Spring Security's provided RememberMeServices requires a UserDetailsService in order to work. This means you have two options:
1) If possible, I recommend this as your best option. Instead of writing a custom AuthenticationProvider, write a custom UserDetailsService. You can find an example UserDetailsService looking at InMemoryDaoImpl You can then wire it similar to the configuration below. Note you would remove your custom AuthenticationManager too.
<http ..>
...
<remember-me key="abcdefgh" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserService"/>
</authentication-manager>
<beans:bean id="myUserService" class="MyUserService"/>
2) Write your own RememberMeServices implementation that does not require a UserDetailsService. You can take a look at TokenBasedRememberMeServices for an example (but it requires UserDetailsService). If you want to use the namespace configuration your RememberMeServices implementation will need to implement LogoutHandler. You can then use the namespace to wire it.
<http ..>
...
<remember-me ref="myRememberMeServices"/>
</http>
<beans:bean id="myRememberMeServices" class="sample.MyRememberMeServices"/>
I'm trying to add <session-management> in my Spring Security namespace configuration so that I can provide a different message than the login page when the session times out. As soon as I add it to my configuration it starts throwing "IllegalStateException: Cannot create a session after the response has been committed" when I access the app.
I'm using Spring Security 3 and Tomcat 6. Here's my configuration:
<http>
<intercept-url pattern="/go.htm" access="ROLE_RESPONDENT" />
<intercept-url pattern="/complete.htm" access="ROLE_RESPONDENT" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-processing-url="/j_spring_security_check"
login-page="/login.htm"
authentication-failure-url="/login.htm?error=true"
default-target-url="/go.htm"
/>
<anonymous/>
<logout logout-success-url="/logout_message.htm"/>
<session-management invalid-session-url="/login.htm" />
</http>
Everything works great until I add in the <session-management> line. What am I missing?
You are probably hitting this bug:
https://jira.springsource.org/browse/SEC-1346
Try using the up-to-date version (3.0.2.RELEASE).
This works for me
<session-management invalid-session-url="/taac/login">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
Maybe including the auto-config="true" attribute in the <http> tag helps, you might be missing some required filters or settings.