I have a problem to properly configure Spring oauth using xml, as I have to add this support to an existing project is required to perform the configuration from XML, I have to integrate Spring MVC, Spring and Spring Security OAuth. I have a project which I have set for trial purposes Spring MVC and Spring security and I have another project where I could configure Spring Oauth it performs authentication password, I could not make it work integrating OAuth (safely through verification code) in the first project, not to me this missing, any suggestion or tip to configure this?
*File: spring-security.xml
<?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"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
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-3.2.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
</security:global-method-security>
<security:http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<security:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
<!-- This is where we tells spring security what URL should be protected and what roles have access to them -->
<security:http pattern="/oauth/api/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/oauth/api/**" access="hasAnyRole('ROLE_USER')" />
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
<!-- Configuracion de spring global -->
<security:http pattern="/login**" security="none" />
<security:http pattern="/login/**" security="none" />
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER') or #oauth2.clientHasRole('ROLE_USER')"/>
<security:intercept-url pattern="/main" access="hasAnyRole('ROLE_USER') or #oauth2.clientHasRole('ROLE_USER')"/>
<security:form-login authentication-success-handler-ref="authenticationSuccessRedirectHandler"
login-page="/login" default-target-url="/" authentication-failure-url="/login/fail" />
<security:logout logout-success-url="/login" delete-cookies="true" invalidate-session="true" />
</security:http>
<bean id="authenticationSuccessRedirectHandler" class="mx.oauth.resourceserver.AuthenticationHandler" />
<security:authentication-manager id="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="marcos" password="pwd" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<!-- Configuracion 2 Oauth -->
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<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:password authentication-manager-ref="authenticationManager"/>
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<!-- client -->
<oauth:client client-id="restapp2" authorized-grant-types="authorization_code,client_credentials" authorities="ROLE_USER" scope="read,write,trust" secret="secret" />
<oauth:client client-id="restapp" authorized-grant-types="password,authorization_code,refresh_token,implicit" secret="restapp" authorities="ROLE_USER" />
</oauth:client-details-service>
<!-- This defined token store, we have used inmemory tokenstore for now but this can be changed to a user defined one -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" />
<!-- This is where we defined token based configurations, token validity
and other things -->
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="120" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="userApprovalHandler" class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenServices" ref="tokenServices" />
</bean>
<bean id="accessConfirmationController" class="mx.oauth.resourceserver.AccessConfirmationController">
<property name="clientDetailsService" ref=""clientDetails />
<property name="approvalStore" ref="clientDetails" />
</bean>
</beans>
Related
Can't seem to get spring oauth2 server configuration to successfully authenticate with a token.
I feel like I'm missing something very minute, but I'll take any pointers.
I'm attempting a password grant. I keep running into a 404 on /oauth/token. See my config and curl below (userAuthenticationProvider is injected by #Configuration on a custom provider):
CONFIGURATION:
<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" xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-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/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<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 authentication-manager-ref="clientAuthenticationManager" />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT, ROLE_USER" scope="read,write,trust"
access-token-validity="60" />
<oauth:client client-id="my-trusted-client-with-secret"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="somesecret" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT, ROLE_USER"
scope="read,write,trust" />
<oauth:client client-id="my-client-with-secret"
authorized-grant-types="client_credentials" authorities="ROLE_CLIENT, ROLE_USER"
scope="read" secret="secret" />
<oauth:client client-id="my-less-trusted-client"
authorized-grant-types="authorization_code,implicit" authorities="ROLE_CLIENT, ROLE_USER" />
<oauth:client client-id="my-less-trusted-autoapprove-client"
authorized-grant-types="implicit" authorities="ROLE_CLIENT, ROLE_USER" />
<oauth:client client-id="my-client-with-registered-redirect"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_CLIENT, ROLE_USER" redirect-uri="http://anywhere?key=value"
scope="read,trust" />
<oauth:client client-id="my-untrusted-client-with-registered-redirect"
authorized-grant-types="authorization_code" authorities="ROLE_CLIENT, ROLE_USER"
redirect-uri="http://anywhere" scope="read" />
<oauth:client client-id="tonr" resource-ids="sparklr"
authorized-grant-types="authorization_code,implicit" authorities="ROLE_CLIENT"
scope="read,write" secret="secret" />
</oauth:client-details-service>
<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" />
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.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" />
</bean>
<bean id="oAuth2RequestFactory"
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore" />
<property name="requestFactory" ref="oAuth2RequestFactory" />
</bean>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<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>
<http pattern="/oauth/check_token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager
xmlns="http://www.springframework.org/schema/security" alias="userAuthenticationManager">
<authentication-provider ref="userAuthenticationProvider">
<!-- <user-service> <user name="admin" password="adminpassword" authorities="ROLE_USER"
disabled="true" locked="true" /> <user name="user" password="userpassword"
authorities="ROLE_USER" /> </user-service> -->
</authentication-provider>
</authentication-manager>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<!-- <property name="realmName" value="test" /> -->
</bean>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test" />
</bean>
<!-- ACCESS DECISION AND ROLE VOTERS -->
<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" />
</list>
</constructor-arg>
</bean>
<sec:global-method-security
jsr250-annotations="enabled" access-decision-manager-ref="accessDecisionManager" />
CURL:
curl my-trusted-client-with-secret:somesecret#localhost:8080/oauth/token -d grant_type=password -d username=admin -d password=adminpassword
I'll take any pointers on on anything wrong.
I kept getting a 404 on /oauth/token even after spring security filter chain had authenticated my client because deployment descriptor ie web.xml was missing a Spring Dispatcher servlet configuration. Added the following and all was good:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/oauth/token</url-pattern>
</servlet-mapping>
I have a web application which implements oauth2 and spring security. Also I have a mobile version of my web application which will access some protected resources of my web application. When I access my token url, it gives the access token ,refresh token, token_type, expires_in. I have a method which I want the android to have access to.
So this is the url to get an access token:
http://localhost:8080/LEAVE/oauth/token?scope=read,write,trust&grant_type=password&client_id=testclient&client_secret=testsecret&username=john&password=smith
And it gives me this:
{
"access_token": "23ac9377-6de7-47b7-aab9-8aebc9c499d4",
"token_type": "bearer",
"refresh_token": "e8e0238c-a98e-4be3-93a9-fbe24bcf6e1d",
"expires_in": 119,
"scope": "read,write,trust"
}
And now to access the protected resource:
http://localhost:8080/LEAVE/api/users?access_token=23ac9377-6de7-47b7-aab9-8aebc9c499d4
When I call this url , it gives me the following error:
{
"error": "invalid_token",
"error_description": "Invalid access token: 23ac9377-6de7-47b7-aab9-8 aebc9c499d4"
}
The class that is protected:
#Scope("session")
#RequestMapping("/api/users")
#Component("ParParkingRequestComponent")
public class LeaveComponentImpl implements LeaveComponent {
#RequestMapping(value = "/", method = RequestMethod.GET)
#ResponseBody
public String test(){
return "Yes It's working";
}
Here is my spring-security.xml:
<?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:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
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-3.1.xsd">
<!-- This is default url to get a token from OAuth -->
<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"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- This is where we tells spring security what URL should be protected
and what roles have access to them -->
<http 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_APP" />
<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="test" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/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-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- This defined token store, we have used inmemory tokenstore for now
but this can be changed to a user defined one -->
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<!-- This is where we defined token based configurations, token validity
and other things -->
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="120" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices" />
</bean>
<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="test" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<!-- client -->
<oauth:client client-id="restapp"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_APP" scope="read,write,trust" secret="secret" />
<oauth:client client-id="restapp"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="restapp" authorities="ROLE_APP" />
</oauth:client-details-service>
<security:global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the
http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<security:expression-handler ref="oauthExpressionHandler" />
</security:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<!-- Spring security -->
<!-- <security:global-method-security
secured-annotations="enabled" />
-->
<security:http auto-config="false" authentication-manager-ref="authenticationManager" use-expressions="true" >
<!-- Override default login and logout pages -->
<security:form-login authentication-failure-handler-ref="failureClass" authentication-success-handler-ref="successClass"
login-page="/login.xhtml" default-target-url="dashboard.xhtml" />
<security:logout invalidate-session="true" logout-url="/j_spring_security_logout" success-handler-ref="LogoutAction" />
<security:session-management>
<security:concurrency-control max-sessions="10" error-if-maximum-exceeded="true" />
</security:session-management>
<security:intercept-url pattern="/jsf/**" access="isAuthenticated()" />
<security:intercept-url pattern="/run**" access="isAuthenticated()" />
<security:intercept-url pattern="/login.xhtml" access="permitAll" />
</security:http>
<bean id="successClass" class="com.car.SuccessAction"/>
<bean id="failureClass" class="com.car.FailureAction" >
<property name="defaultFailureUrl" value="/?login_error=true"/>
</bean>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userDetailsService" >
<security:password-encoder ref="passwordEncoder" hash="sha"/>
</security:authentication-provider>
</security:authentication-manager>
Using :
spring-security 3.2.5
spring-security-oauth 2.0.7 (oauth2)
grant_type : authentication_code
I have no problem getting authentication_code and access token.
The problem I have is that if I call a "protected" resource, I can access it with no token at all. Here is the security config of the "not-really-protected" resource :
<security:http pattern="/api/user/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
The Oauth2AuthenticationProcessingFilter is saying
No token in request, will continue chain.
I found this other post wich seems to describe the same problem, but the solution presented is to add <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />, wich I already have.
Also, tough maybe not related, the request to the protected resource receive à Set-cookie header, defining a jsessionid. It seems not normal to me since I specify create-session="never".
I expected an unauthorized call to this resource to return a 403 since I use OAuth2AccessDeniedHandler.
Can someone help me with this ?
Note that I am pretty sure that this security config is kicking in because in my protected resource(a spring-mvc controller), SecurityContextHolder.getContext().getAuthentication() returns null. If I completely disable the above security config, the same line returns an anonymous authentication.
EDIT : Detailed configuration information.
First I have the token enpoint configuration :
<security:http pattern="/api/oauth/token"
create-session="stateless"
authentication-manager-ref="clientAuthenticationManager">
<security:intercept-url pattern="/api/oauth/token"
access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
Then the resource endpoint configuration (as shown at the beginning of the question) :
<security:http pattern="/api/user/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/api/user/**"
access="IS_AUTHENTICATED_FULLY" />
<security:custom-filter ref="userResourceServer"
before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
And then the "generic" url configuration :
<security:http name="genericSecurityConfiguration" entry-point-ref="customLoginEntrypoint">
<security:form-login authentication-failure-url="/index.jsp"
authentication-success-handler-ref="customAuthenticationSuccessHandler"
authentication-failure-handler-ref="customAuthenticationFailureHandler"
login-page="/index.jsp"
login-processing-url="/solapCore/identification2"
username-parameter="username"
password-parameter="password"
/>
<security:session-management invalid-session-url="/index.jsp?invalidSession=true" session-authentication-strategy-ref="sas" />
<security:custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
<security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="monitoringFilter"/>
<security:access-denied-handler ref="solapcoreAccessDeniedHandler"/>
</security:http>
Other oauth specific configuration in the same file :
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="oauth" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="oauth/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<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>
<security:authentication-manager id="clientAuthenticationManager">
<security:authentication-provider user-service-ref="clientDetailsUserService" />
</security:authentication-manager>
<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" />
<oauth:authorization-server
client-details-service-ref="clientDetails"
token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
</oauth:authorization-server>
<oauth:resource-server id="userResourceServer"
resource-id="oauth2/user"
token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="someClientID"
authorized-grant-types="authorization_code"
authorities="SOME_AUTHORITY" scope="read" secret="secret" />
</oauth:client-details-service>
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<security:expression-handler ref="oauthExpressionHandler" />
</security:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.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" />
</bean>
Finaly, my dispatcher servlet and filterChain configuration in web.xml :
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/api/*</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>
i believe that you are missing "Authorization" header.
you need to have value of "Bearer" in the header value.
ref:
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/authentication/OAuth2AuthenticationProcessingFilter.java
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/authentication/BearerTokenExtractor.java
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java
The problematic part in your configuration is <security:http pattern="/api/user/**" ...>
Since the "pattern" attribute is set to /api/user/**, your intercept-url "pattern" attribute
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
won't have any effect unless it has the same prefix (/api/user/**).
If you're trying to use IS_AUTHENTICATED_FULLY only for the /api/user/** pattern, then the intercept-url should be
<security:http pattern="/api/user/**" ...>
<security:anonymous enabled="false" />
<security:intercept-url pattern="/api/user/**" access="IS_AUTHENTICATED_FULLY" />
<security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
If you want to apply that rule for full application, then something like this should work:
<security:http create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/api/user/**" access="IS_AUTHENTICATED_FULLY" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
I found the cause of the problem, and it is very specific to our application.
Somewhere else in a config, we override the built-in FilterInvocationSecurityMetadataSource (using an evil bean post-processor) to add a Custom one. This have the effect to disable all <intercept-url> in config files. We did this because we migrated a legacy custom security framework to spring-security and wanted to keep url security in our already existing files.
Thanks to all that tried to help.
I have a Spring 4.1 web app, I use spring-security and spring session, spring session I want to use with websockets to keep the session without timeout as long as the websocket is working.
It all works fine but what I find is that I obviously have two sessions running, one for spring security and one for spring session.
This is my session.xml:
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="localhost"/>
<property name="port" value="6379" />
</bean>
<bean class="org.springframework.session.data.redis.RedisOperationsSessionRepository" name="sessionRepository" >
<constructor-arg name="redisConnectionFactory" ref="jedisConnFactory" />
<!--<property name="defaultMaxInactiveInterval" value="60" />-->
</bean>
<bean class="org.springframework.session.web.http.HeaderHttpSessionStrategy" name="sessionStrategy" />
<bean name="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
<constructor-arg name="sessionRepository" ref="sessionRepository" />
</bean>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" >
<property name="httpSessionStrategy" ref="sessionStrategy"/>
</bean>
And here is my security.xml:
<!-- Security -->
<bean id="userDetailsService" class="com.fg.ts.base.security.userdetails.CustomUserDetailsService" />
<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<constructor-arg value="${encoder.password}" />
</bean>
<sec:authentication-manager id="authenticationManager">
<sec:authentication-provider user-service-ref="userDetailsService">
<sec:password-encoder ref="passwordEncoder" />
</sec:authentication-provider>
</sec:authentication-manager>
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="disabled"
jsr250-annotations="enabled" authentication-manager-ref="authenticationManager" />
<!-- Exclude the resources+error+auth pages from security filter -->
<sec:http pattern="/javax.faces.resource/**" security="none" />
<sec:http pattern="/images/**" security="none" />
<sec:http pattern="/css/**" security="none" />
<sec:http pattern="/ico/**" security="none" />
<sec:http pattern="/lib/**" security="none" />
<sec:http pattern="/js/**" security="none" />
<sec:http pattern="/auth/**" security="none" />
<sec:http pattern="/error/**" security="none" />
<sec:http pattern="/api/concordancer/search/**" security="none" />
<sec:http pattern="/concordancer/search" security="none"/>
<sec:http pattern="/assets/cdSearch.xhtml" security="none"/>
<sec:http pattern="/api/tmGroup/**" security="none"/>
<sec:http pattern="/api/reports/download/**" security="none"/>
<sec:http pattern="/api/socket/tasks/info/**" security="none"/>
<!-- Security Configuration for Faces Pages -->
<!-- Start Customization for Faces -->
<!-- ***************************** -->
<!-- Failure Login Handler -->
<bean id="authenticationFailureHandler" class="com.fg.ts.web.util.security.LoginFailureHandler">
<property name="defaultFailureUrl" value="/auth/login" />
</bean>
<!-- Faces Redirect -->
<bean id="facesRedirectStrategy" class="com.fg.ts.web.util.security.FacesRedirectStrategy">
<property name="invalidSessionUrl" value="/auth/login/sessionExpired" />
</bean>
<!-- Shared Objects -->
<bean id="securityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- Session Authentication Strategy -->
<bean id="sessionFixationAuthenticationStrategy" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
<bean id="registerSessionStrategy" class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg name="delegateStrategies">
<list>
<!-- <ref bean="concurrentSessionStrategy" /> -->
<ref bean="sessionFixationAuthenticationStrategy" />
<ref bean="registerSessionStrategy" />
</list>
</constructor-arg>
</bean>
<!-- Remember-Me Service -->
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<constructor-arg name="key" value="${encoder.password}" />
<constructor-arg name="userDetailsService" ref="userDetailsService" />
<property name="parameter" value="j_remember_me" />
<property name="cookieName" value="TMS_REME" />
</bean>
<!-- Filters -->
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy" />
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<constructor-arg name="securityContextRepository" ref="securityContextRepository" />
<constructor-arg name="sessionStrategy" ref="sessionAuthenticationStrategy" />
<property name="invalidSessionStrategy" ref="facesRedirectStrategy" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="concurrentSessionFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<constructor-arg name="expiredUrl" value="/auth/login/expiredDueToConcurrentAccess" />
<property name="redirectStrategy" ref="facesRedirectStrategy" />
</bean>
<bean id="authEntryPoint" class="com.fg.ts.web.util.security.FacesLoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/auth/login"/>
</bean>
<!-- End Customization for Faces -->
<!-- ***************************** -->
<sec:http use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="authenticationManager"
entry-point-ref="authEntryPoint"> <!--security-context-repository-ref="securityContextRepository"-->
<sec:http-basic />
<sec:custom-filter ref="usernamePasswordAuthenticationFilter" before="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="sessionManagementFilter" position="SESSION_MANAGEMENT_FILTER" />
<sec:anonymous />
<sec:remember-me key="${encoder.password}" services-ref="rememberMeServices" />
<sec:form-login login-page="/auth/login" authentication-failure-handler-ref="authenticationFailureHandler" />
<sec:logout logout-url="/logout" invalidate-session="true" delete-cookies="TMS_SES,TMS_REME"
logout-success-url="/auth/login" />
<sec:session-management session-fixation-protection="none" />
<!-- General Access Control -->
<sec:intercept-url pattern="/projects/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/assets/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/setup/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/tm/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/termBase/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/quality/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/editor/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/api/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
</sec:http>
How can I make spring security use the session created by spring-session ?
I found the issue, the reason was that in the FilterChain, springSecurityFilterChain Filter always loaded first before the springSessionRepositoryFilter, and so the Spring Session was not yet created, so the security filter created it's own.
this was happening because my springSessionRepositoryFilter was configured specifically for each servlet like this:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<servlet-name>mvc-dispatcher</servlet-name>
</filter-mapping>
but when I removed it and made it a global filter it then worked, much like this:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
We already have an OAuth2 authorization server set up, so I need to create a corresponding resource server (separate server). We plan to use the Spring Security OAuth2 project. Their documentation for setting up a resource server:
https://github.com/spring-projects/spring-security-oauth/wiki/oAuth2#resource-server-configuration
token-services-ref should point to the token-handling bean. However it seems like the token handling is done by the server itself even though it is the resource server. There doesn't seem to be any remote token services class or any configuration relating to a remote server. This is in contrast with the CloudFoundary UAA (https://github.com/cloudfoundry/uaa/blob/master/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml) which has:
<bean id="tokenServices"
class="org.cloudfoundry.identity.uaa.oauth.RemoteTokenServices">
<property name="checkTokenEndpointUrl" value="${checkTokenEndpointUrl}" />
Is there any way to use Spring Security OAuth2 for a resource server that communicates with a separate OAuth2 Authorization server? How can I set the communication endpoint?
This is possible as long as the authorization server and resource server(s) access a shared tokenStore (e.g. using JdbcTokenStore with a common dataSource). You can just use DefaultTokenServices with a reference to your shared tokenStore. Below is an example Spring config which you should be able to tweak to fit your needs:
<?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"
xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
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://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="myRealm" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<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>
<!-- This is not actually used, but it's required by Spring Security -->
<security:authentication-manager alias="authenticationManager" />
<oauth2:expression-handler id="oauthExpressionHandler" />
<oauth2:web-expression-handler id="oauthWebExpressionHandler" />
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<security:expression-handler ref="oauthExpressionHandler" />
</security:global-method-security>
<oauth2:resource-server id="myResource" resource-id="myResourceId" token-services-ref="tokenServices" />
<security:http pattern="/myPattern/**" create-session="never"
entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="GET" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="HEAD" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="OPTIONS" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="PUT" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="POST" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="DELETE" />
<security:custom-filter ref="myResource" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
</beans>
Yes its possible. Like you have already mentioned in your question, RemoteTokenServices is the solution.
I have created one sample which has separate auth and resource server. Its just a sample to give a quick idea about the concept and open for extension.
Spring-AngularJS-OAuth2-Sample