I'm using Spring 4.2.1.RELEASE, Spring Security 4.0.2.RELEASE and Spring Security OAuth 2.0.7.RELEASE to build a web application with a RESTful API.
Previously my login functionality wasn't 100% RESTful because I used cookies for authentication.
Now I need to move to pure RESTful with token authentication through an OAuth endpoint.
I followed many guides, and in particular this one : https://www.youtube.com/watch?v=LnJsspvxE1c
When I try to get an access token I make the following request with Postman.
HTTP GET
http://localhost:8080/oauth/token?grant_type=password&client_id=trusted-client&username=name&password=pass
But I always get a 404 Not Found.
I can't find where I'm wrong.
Below is my spring security configuration file.
```
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
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-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- Definition of the Authentication Service -->
<http pattern="/oauth/token"
create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token"
access="isAuthenticated()"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- Protected resources -->
<http auto-config="true"
use-expressions="true"
pattern="/api/**"
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="/api/**" access="ROLE_USER" />
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<access-denied-handler
ref="oauthAccessDeniedHandler"/>
</http>
<beans:bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="auth"/>
</beans:bean>
<beans:bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="auth/client"/>
<beans:property name="typeName" value="Basic"/>
</beans:bean>
<beans:bean
id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<beans:bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager"
ref="clientAuthenticationManager"/>
</beans:bean>
<beans: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.web.access.expression.WebExpressionVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</beans:bean>
<!-- Authentication in config file -->
<authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<beans:bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails"/>
</beans:bean>
<!-- Token Store -->
<beans:bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
<beans:bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<beans:property name="tokenStore" ref="tokenStore"/>
<beans:property name="supportRefreshToken" value="true"/>
<beans:property name="clientDetailsService" ref="clientDetails"/>
<beans:property name="accessTokenValiditySeconds" value="10"/>
</beans:bean>
<beans:bean id="oAuth2RequestFactory"
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<beans:constructor-arg ref="clientDetails" />
</beans:bean>
<beans:bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<beans:property name="tokenStore" ref="tokenStore"/>
<beans:property name="requestFactory" ref="oAuth2RequestFactory" />
<beans:property name="clientDetailsService" ref="clientDetails"/>
</beans:bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails"
token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler"
token-endpoint-url="/oauth/token">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="auth"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="trusted-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
redirect-uri="/secure/index"
scope="read,write,trust"
access-token-validity="30"
refresh-token-validity="600"/>
</oauth:client-details-service>
<global-method-security pre-post-annotations="enabled"
secured-annotations="enabled"
proxy-target-class="true" order="1" >
<expression-handler ref="oauthExpressionHandler"/>
</global-method-security>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>
Grant type password expects a POST query to /oauth/token, not the GET one.
So it should be:
curl -X POST -d 'grant_type=password&client_id=trusted-client&username=name&password=pass' 'http://localhost:8080/oauth/token'
In addition, your oauth/token endpoint is available for isAuthenticated users only:
<intercept-url pattern="/oauth/token" access="isAuthenticated()"/>
but as far as I understand you make a call as a anonymous user.
Related
I have implemented spring security ajax login. .
I defined my own customAuthenticationEntryPoint, authenticationFilter, securityLoginSuccessHandler. It can successfully authenticate the user. However, when I add the remember me part. It does not work. There is no SQL run in the database to insert token into persistent_logins. I do not know if there is anything wrong with my configuration? Please help.
<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" xmlns:util="http://www.springframework.org/schema/util"
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.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<http pattern="/resources/**" security="none" />
<http auto-config="false" use-expressions="true" entry-point-ref="customAuthenticationEntryPoint">
<intercept-url pattern="/**" access="permitAll" />
<access-denied-handler error-page="/denied" />
<logout invalidate-session="true" delete-cookies="JSESSIONID"
success-handler-ref="securityLogoutSuccessHandler" logout-url="/logout" />
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
<csrf />
<!-- enable remember me -->
<remember-me
services-ref = "rememberMeServices"
key = "_spring_security_remember_me" />
</http>
<beans:bean id="rememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:property name="key" value="_spring_security_remember_me"/>
<beans:property name="alwaysRemember" value="true"/>
<beans:property name="tokenRepository" ref="jdbcTokenRepository"/>
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="createTableOnStartup" value="false"/>
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean id="customAuthenticationEntryPoint"
class="com.tong.beau.service.security.CustomAuthenticationEntryPoint">
<beans:property name="loginPageUrl" value="/login" />
<beans:property name="returnParameterEnabled" value="true" />
<beans:property name="returnParameterName" value="r" />
</beans:bean>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="filterProcessesUrl" value="/security_check" /><!--
change here if customize form action -->
<!-- handler are for login with ajax POST -->
<beans:property name="authenticationFailureHandler"
ref="securityLoginFailureHandler" />
<beans:property name="authenticationSuccessHandler"
ref="securityLoginSuccessHandler" />
<beans:property name="PasswordParameter" value="password" /><!--
change here for password field name in the form -->
<beans:property name="UsernameParameter" value="username" /><!--
change here for username field name in the form -->
</beans:bean>
<beans:bean id="securityLoginSuccessHandler"
class="com.tong.beau.service.security.SecurityLoginSuccessHandler">
<beans:property name="defaultTargetUrl" value="/" />
<beans:property name="targetUrlParameter" value="return-url"/>
</beans:bean>
<beans:bean id="securityLoginFailureHandler"
class="com.tong.beau.service.security.SecurityLoginFailureHandler">
<beans:property name="defaultFailureUrl" value="/login/failure" />
</beans:bean>
<beans:bean id="securityLogoutSuccessHandler"
class="com.tong.beau.service.security.SecurityLogoutSuccessHandler">
</beans:bean>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
</beans:beans>
Since I implemented my CustomAuthenticationEntryPoint, do I need to handle the remember me service in the entry point?
After looking at the source code of Spring Security 4.0.3, I found out that the default parameter is actually defined as this:
public static final String DEFAULT_PARAMETER = "remember-me";
So what I did was to edit the front end to send the data with name "remember-me".
Before Spring Security 4.0.3, the default parameter was _spring_security_remember_me
That would be worth of mention. The configuration also has some problems.
My working configuration is as following.
<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" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<http pattern="/resources/**" security="none" />
<http auto-config="false" use-expressions="true" entry-point-ref="customAuthenticationEntryPoint">
<intercept-url pattern="/**" access="permitAll" />
<access-denied-handler error-page="/denied" />
<logout invalidate-session="true" delete-cookies="JSESSIONID"
success-handler-ref="securityLogoutSuccessHandler" logout-url="/logout" />
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
<custom-filter ref="rememberMeFilter" after="FORM_LOGIN_FILTER" />
<csrf />
<remember-me key = "remember-me" services-ref="rememberMeServices"/>
</http>
<beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<beans:constructor-arg ref="authenticationManager"/>
<beans:constructor-arg ref="rememberMeServices"/>
</beans:bean>
<beans:bean id="rememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="remember-me"/>
<beans:constructor-arg ref="userDetailsService"/>
<beans:constructor-arg ref="jdbcTokenRepository"/>
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<beans:constructor-arg value="remember-me"/>
</beans:bean>
<beans:bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="createTableOnStartup" value="false"/>
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean id="customAuthenticationEntryPoint"
class="com.tong.beau.service.security.CustomAuthenticationEntryPoint">
<beans:property name="loginPageUrl" value="/login" />
<beans:property name="returnParameterEnabled" value="true" />
<beans:property name="returnParameterName" value="r" />
</beans:bean>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="rememberMeServices" ref="rememberMeServices" />
<beans:property name="filterProcessesUrl" value="/security_check" />
<!-- change here if customize form action -->
<!-- handler are for login with ajax POST -->
<beans:property name="authenticationFailureHandler"
ref="securityLoginFailureHandler" />
<beans:property name="authenticationSuccessHandler"
ref="securityLoginSuccessHandler" />
<beans:property name="PasswordParameter" value="password" />
<!-- change here for password field name in the form -->
<beans:property name="UsernameParameter" value="username" />
<!-- change here for username field name in the form -->
</beans:bean>
<beans:bean id="securityLoginSuccessHandler"
class="com.tong.beau.service.security.SecurityLoginSuccessHandler">
<beans:property name="defaultTargetUrl" value="/" />
<beans:property name="targetUrlParameter" value="return-url"/>
</beans:bean>
<beans:bean id="securityLoginFailureHandler"
class="com.tong.beau.service.security.SecurityLoginFailureHandler">
<beans:property name="defaultFailureUrl" value="/login/failure" />
</beans:bean>
<beans:bean id="securityLogoutSuccessHandler"
class="com.tong.beau.service.security.SecurityLogoutSuccessHandler">
</beans:bean>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<authentication-manager alias="authenticationManager">
<authentication-provider ref="rememberMeAuthenticationProvider">
</authentication-provider>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
</beans:beans>
I have an application develop on Spring 4.1.4 and Spring Security 4.0.2, deployed on a server with Apache Tomcat 8 and JDK 1.7.
It happens that after some days some users can't login anymore even if they specity correct user/password combination.
Restarting Tomcat fixes the problem.
Any suggestion?
May it be a session related issue?
This is my security configuration
<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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
">
<http auto-config="true" use-expressions="true">
<custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="ajaxTimeoutRedirectFilter"/>
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<intercept-url pattern="/j_spring_security_switch_user" access="hasRole('ROLE_SUPERVISOR')"/>
<session-management invalid-session-url="/login.html?invalidSession=1" session-fixation-protection="newSession">
<concurrency-control max-sessions="10" error-if-maximum-exceeded="true" />
</session-management>
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS')" requires-channel="https"/>
<intercept-url pattern="/resources/**" access="permitAll" requires-channel="any"/>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" requires-channel="https"/>
<intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" requires-channel="https"/>
<intercept-url pattern="/index" access="hasRole('ROLE_USER')" requires-channel="https"/>
<intercept-url pattern="/upload/**" access="hasRole('ROLE_USER')" requires-channel="https"/>
<headers>
<xss-protection block="false"/>
<frame-options disabled="true"/>
<cache-control/>
</headers>
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login.html"
default-target-url="/index"
always-use-default-target="true"
authentication-failure-url="/login.html?error=1"
username-parameter="username"
password-parameter="password"/>
<logout logout-success-url="/login.html?logout=1" invalidate-session="false" delete-cookies="JSESSIONID"/>
<!-- enable csrf protection -->
<!-- <csrf disabled="true" /> -->
<port-mappings>
<port-mapping http="8080" https="8443"/>
</port-mappings>
</http>
<beans:bean id="ajaxTimeoutRedirectFilter" class="com.finconsgroup.mens.springsecurity.AjaxTimeoutRedirectFilter">
<beans:property name="customSessionExpiredErrorCode" value="419"/>
</beans:bean>
<beans:bean id="switchUserProcessingFilter" class="com.finconsgroup.mens.springsecurity.MensSwitchUserFilter">
<beans:property name="userDetailsService" ref="mensAuthenticationService"/>
<beans:property name="switchUserUrl" value="/j_spring_security_switch_user"/>
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user"/>
<beans:property name="targetUrl" value="/index"/>
</beans:bean>
<beans:bean name="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!-- Select users and user_roles from database -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="mensAuthenticationService">
<password-encoder ref="bcryptEncoder"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="mensAuthenticationService" class="com.finconsgroup.mens.springsecurity.MensAuthenticationProvider">
<beans:property name="dataSource" ref="mensDataSource"/>
<beans:property name="usersByUsernameQuery" value="my_query"/>
<beans:property name="authoritiesByUsernameQuery" value="my_query"/>
<beans:property name="groupAuthoritiesByUsernameQuery" value="my_query"/>
<beans:property name="enableGroups" value="true"/>
</beans:bean>
<!-- Spring Security -->
<beans:bean id="mensPermissionEvaluator" class="com.finconsgroup.mens.springsecurity.MensPermissionEvaluator">
<beans:constructor-arg ref="aclService"/>
</beans:bean>
<beans:bean id="securityExpressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="mensPermissionEvaluator"/>
</beans:bean>
<global-method-security
authentication-manager-ref="authenticationManager"
pre-post-annotations="enabled"
secured-annotations="enabled">
<expression-handler ref="securityExpressionHandler"/>
</global-method-security>
<!-- ================================================================== -->
<!-- ACL service -->
<!-- ================================================================== -->
<beans:bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<beans:constructor-arg ref="mensDataSource" />
<beans:constructor-arg ref="lookupStrategy" />
<beans:constructor-arg ref="aclCache" />
</beans:bean>
<beans:bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<beans:constructor-arg>
<beans:bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<beans:property name="cacheManager">
<beans:ref bean="mensEhCacheManager"/>
</beans:property>
<beans:property name="cacheName" value="aclCache"/>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<beans:constructor-arg>
<beans:bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<beans:constructor-arg value="ROLE_ACL_ADMIN"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<beans:constructor-arg ref="mensDataSource" />
<beans:constructor-arg ref="aclCache" />
<beans:constructor-arg>
<!-- Decides whether current principal can make ACL changes. See
AclAuthorizationStrategyImpl Javadoc for the rules involved. -->
<beans:bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<beans:constructor-arg>
<beans:list>
<!-- Role required to change ACL ownership -->
<beans:ref bean="adminRole" />
<!-- Role required to change auditing details -->
<beans:ref bean="adminRole" />
<!-- Role required to change other ACL/ACE details -->
<beans:ref bean="adminRole" />
</beans:list>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</beans:constructor-arg>
</beans:bean>
<beans:bean id="adminRole" class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<beans:constructor-arg value="ADMIN" />
</beans:bean>
Thank you in advance for your help!
I fixed the problem changing the session-fixation-protection attribute to migrateSession.
Now I have no need to restart Tomcat periodically.
I have project based on Spring Security OAuth 2.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
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.2.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- Definition of the Authentication Service -->
<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"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- Protected resources -->
<http pattern="/employee/**"
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="/employee/**"
access="ROLE_USER"/>
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<access-denied-handler
ref="oauthAccessDeniedHandler"/>
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</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>
<!-- Authentication in config file -->
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service id="userDetailsService">
<user name="admin" password="password" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<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="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
<property name="accessTokenValiditySeconds" value="10"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices"/>
</bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="dstest"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
redirect-uri="/web"
scope="read,write,trust"
access-token-validity="30"
refresh-token-validity="600"/>
</oauth:client-details-service>
<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 want to add Basic Authorozation for /oauth/token.
e.q. :
curl -v --user admin:password "http//localhost:8080/oauthtest/oauth/token?grant_type=password&client_if=my-tr
usted-client&client_secret=2343k242j"
(Authorization: Basic YWRtaW46cGFzc3dvcmQ= in header instead &username=admin&password=password params in url)
How can I do it?
I upgraded Spring Security from 2 to 3
Previously Security.xml has AuthenticationProcessingFilter and AuthenticationProcessingFilterEntryPoint
So my new Security.xml is
<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.3.xsd">
<beans:bean id="userAuthenticationService"
class="com.raykor.core.service.UserAuthenticationService" />
<beans:bean id="shaEncoder"
class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
<global-method-security />
<http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
<intercept-url pattern="/resettingPassword.do**" access="ROLE_ADMIN" />
<intercept-url pattern="/resetPassword.do**" access="ROLE_ADMIN" />
<logout logout-success-url="/index.jsp" invalidate-session="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userAuthenticationService">
<password-encoder ref="shaEncoder">
<salt-source user-property="salt" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="filterProcessesUrl" value="/j_spring_security_check" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationFailureHandler"
ref="failureHandler" />
<beans:property name="authenticationSuccessHandler"
ref="successHandler" />
</beans:bean>
<beans:bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="alwaysUseDefaultTargetUrl" value="false" />
<beans:property name="defaultTargetUrl" value="/home.do" />
</beans:bean>
<beans:bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.do?error=true" />
</beans:bean>
<beans:bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.do" />
<beans:property name="forceHttps" value="false" />
</beans:bean>
`
Also added filter springSecurityFilterChain in web.xml
On login.do it opens Login Page,On Submit it submits to j_spring_security_check with username and password as j_username & j_password
So why is it saying as j_spring_security_checknot avaliable
You instantiate a UsernamePasswordAuthenticationFilter, but it won't be part of the security filter chain just by creating it. Try removing the auto-config="false" from the http config element, and include a <form-login> element within that. I think all the configuration that you have done through the bean definitions can be done using the more concise namespace configuration which should be preferred with Spring Security 3.
I missed to add custom-filter ref i updated
as
<http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
<custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter"/>
<intercept-url pattern="/resettingPassword.do**" access="ROLE_ADMIN" />
<intercept-url pattern="/resetPassword.do**" access="ROLE_ADMIN" />
<logout logout-success-url="/index.jsp" invalidate-session="true" />
</http>
I tried to implement a role hierarchy but it doesn't want to work. everything else works perfectly except that. Here is my spring-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"
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 method-level security via annotations -->
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
<!-- Configure form-based authentication -->
<http auto-config="true" use-expressions="true" entry-point-ref="securityEntryPoint" >
<intercept-url pattern="/resources/script/jquery-ui/**" access="permitAll" />
<intercept-url pattern="/resources/script/jquery*" access="permitAll" />
[....]
<intercept-url pattern="/**" access="isAuthenticated()" />
<session-management invalid-session-url="/login.jsp?info=invalid" >
<concurrency-control max-sessions="1" session-registry-alias="sessionRegistry" expired-url="/login.jsp?info=expired" />
</session-management>
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=credentials" />
<logout logout-url="/logout" invalidate-session="true" logout-success-url="/login.jsp" />
</http>
<!-- Configure a spring security logger listener for logging authentication attempts. -->
<beans:bean id="loggerListener" class="org.springframework.security.access.event.LoggerListener"/>
<!-- Configure a delegating entry point -->
<beans:bean id="securityEntryPoint" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
<!-- Requests of type text/html or application/xhtml+xml should be handled by form-based authentication -->
<beans:constructor-arg>
<beans:map>
<beans:entry>
<beans:key>
<beans:bean class="com.test.security.AcceptHeaderRequestMatcher"/>
</beans:key>
<beans:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.jsp" />
</beans:bean>
</beans:entry>
</beans:map>
</beans:constructor-arg>
<!-- Otherwise use BASIC authentication by default -->
<beans:property name="defaultEntryPoint">
<beans:bean class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<beans:property name="realmName" value="test Web Service" />
</beans:bean>
</beans:property>
</beans:bean>
<!-- Configure an authentication manager via our defaultUserService -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="defaultUserService">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:ref bean="roleVoter" />
<beans:ref bean="authenticatedVoter" />
</beans:list>
</beans:property>
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<beans:constructor-arg ref="roleHierarchy" />
<beans:property name="rolePrefix" value="" />
</beans:bean>
<beans:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<beans:property name="hierarchy">
<beans:value>
PERM_READ_ALL_USER_LIST > PERM_READ_USER_LIST
</beans:value>
</beans:property>
</beans:bean>
If i try to access a resource for which PERM_READ_USER_LIST is required, #PreAuthorize("hasRole('PERM_READ_USER_LIST')"), with a user who has the PERM_READ_ALL_USER_LIST it doesn't work, but if he has PERM_READ_USER_LIST, it works. So obviously the rolevoter is not doing its job but I don't get why...
Thank you.
You have to specify the hirarchy explicite for the MethodSecurityExpressionHandler.
See this Stack Overflow question and answer for more details.
How to use role-hierarchy in Spring Security 3 with Spring EL?