PDA

View Full Version : Separate Resource Server and Authorization Server



blindingillusion
Feb 29th, 2012, 04:00 PM
In my teams project we are separating out the Resource Server and the Authorization Server. I am shooting from the hip on this one using the user guide, the github source, and some trial and error. I am wondering what the purpose of the "authentication manager" configuration is in the resource-server config. My config currently has a copy-pasted authentication manager at the moment, but I don't see how it is ever going to be used.


<oauth:resource-server id="resourceServerFilter"
resource-id="class" token-services-ref="resourceServerTokenService" />

<bean id="resourceServerTokenService" class="gov.noaa.cls.m2m.auth.ClassResourceServerTokenServ ices" />

<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="marissa" password="koala" authorities="ROLE_USER" />
<user name="paul" password="emu" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>

<!-- The OAuth2 protected resources are separated out into their own block
so we can deal with authorization and error handling separately. This isn't
mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/**" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/**" access="ROLE_USER,SCOPE_READ" />
<custom-filter ref="resourceServerFilter" before="EXCEPTION_TRANSLATION_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error .MediaTypeAwareAuthenticationEntryPoint">
<property name="realmName" value="class" />
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.Unanimous Based">
<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.Authentic atedVoter" />
</list>
</constructor-arg>
</bean>

<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error .MediaTypeAwareAccessDeniedHandler" />

<mvc:annotation-driven />

<mvc:default-servlet-handler />

<sec:global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>

Dave Syer
Mar 1st, 2012, 02:18 AM
The authentication-manager isn't needed in a pure ResourceServer (at least the way it is implemented right now - but I have been thinking about maybe making changes). It's just a "feature" of the Spring Security XML namespace that an authentication manager is mandatory - you can install an empty one because it isn't used at run time.

willcainsvg
Apr 3rd, 2012, 02:25 PM
Is there an example anywhere of having these 2 servers in at least separate servlets? (Or separate servers.) I am having difficulty trying to set that up. Thanks!

Dave Syer
Apr 4th, 2012, 03:50 AM
See here: https://github.com/cloudfoundry/uaa/blob/master/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml. It's pretty straightforward, if annoying.

willcainsvg
Apr 4th, 2012, 08:57 AM
Thank you; that will help a lot!

kldavis4
Jul 23rd, 2012, 03:18 PM
Is this the corresponding stand alone authorization server? https://github.com/cloudfoundry/uaa/blob/master/samples/login/src/main/webapp/WEB-INF/spring-servlet.xml

Dave Syer
Jul 23rd, 2012, 03:49 PM
Not quite vanilla (although it is an authorization server). The vanilla auth server is https://github.com/cloudfoundry/uaa/blob/master/uaa/src/main/webapp/WEB-INF/spring-servlet.xml.

kldavis4
Jul 23rd, 2012, 03:53 PM
Not quite vanilla (although it is an authorization server). The vanilla auth server is https://github.com/cloudfoundry/uaa/blob/master/uaa/src/main/webapp/WEB-INF/spring-servlet.xml.

great, thanks for the quick reply

kldavis4
Jul 30th, 2012, 04:09 PM
Another question... if I split the authorization and resource server for sparklr2 and run them in different app servers, do I need to use a different token store implementation besides InMemoryTokenStore, so that resource and authorization server have access to the same tokens?

Dave Syer
Jul 31st, 2012, 07:06 AM
Correct. Either the tokens have to be decodable locally by the resource server or it has to share storage with the auth server.

kldavis4
Jul 31st, 2012, 07:11 PM
Thanks. I switched to the jdbc token store implementation and was able to separate out the auth / resource server for sparklr / tonr.

I am running into something odd, though. I am running each webapp in a different app server instance on separate ports. This works fine. I have further modified things so that each app is running at the root context ('/') on the app server. This is working for the resource server (sparklr) and client app (tonr), but when I change the context for the authorization service, things start breaking. I have changed the access token and user authorization urls in tonr to point to the authorization on the root context, but for some reason when I get redirected from the authorization service back to tonr, I seem to lose the session and I am asked to log back in to tonr (and don't have a valid token for sparklr either). This only occurs if I switch from any web context (/authorization, /authservice, etc) on the authorization service to '/'. Any ideas what might be happening?

Dave Syer
Aug 1st, 2012, 03:41 AM
I don't think it's possible to say specifically what's wrong without more information, but it sounds like a generic Spring Securit config issue. The cloudfoundry UAA runs on / (as well as /uaa) if you want to look at an example. I never tried it with sparklr2.

kldavis4
Oct 23rd, 2012, 05:38 PM
I've spent some more time characterizing this issue, so I can provide a few more details and hopefully resolve it.

The error that I get on the client side, after authorizing the client application in the authorizationservice (/oauth/authorize), I get this exception when the oauth resttemplate makes the request to the resource server:



HTTP ERROR 500

Problem accessing /service/myservice. Reason:

Possible CSRF detected - state parameter was present but no state could be found
Caused by:

error="invalid_request", error_description="Possible CSRF detected - state parameter was present but no state could be found"
at org.springframework.security.oauth2.client.token.g rant.code.AuthorizationCodeAccessTokenProvider.get ParametersForTokenRequest(AuthorizationCodeAccessT okenProvider.java:199)
at org.springframework.security.oauth2.client.token.g rant.code.AuthorizationCodeAccessTokenProvider.obt ainAccessToken(AuthorizationCodeAccessTokenProvide r.java:161)
at org.springframework.security.oauth2.client.token.A ccessTokenProviderChain.obtainNewAccessTokenIntern al(AccessTokenProviderChain.java:120)
at org.springframework.security.oauth2.client.token.A ccessTokenProviderChain.obtainAccessToken(AccessTo kenProviderChain.java:100)
at org.springframework.security.oauth2.client.OAuth2R estTemplate.acquireAccessToken(OAuth2RestTemplate. java:194)
at org.springframework.security.oauth2.client.OAuth2R estTemplate.getAccessToken(OAuth2RestTemplate.java :148)
at org.springframework.security.oauth2.client.OAuth2R estTemplate.createRequest(OAuth2RestTemplate.java: 89)
at org.springframework.web.client.RestTemplate.doExec ute(RestTemplate.java:434)
at org.springframework.security.oauth2.client.OAuth2R estTemplate.doExecute(OAuth2RestTemplate.java:122)
at org.springframework.web.client.RestTemplate.execut e(RestTemplate.java:415)
at org.springframework.web.client.RestTemplate.getFor Object(RestTemplate.java:213)
at com.acme.prototype.oauth.client.impl.ServiceImpl.g etIds(ServiceImpl.java:35)
at com.acme.prototype.oauth.client.mvc.ClientControll er.photos(ClientController.java:38)


The other thing I noticed is that the code stored by my authorizationcodeservices impl is never removed.

Attached is the spring configuration for the AuthorizationService which was originally based on the sparklr demo 5262

Let me know if there is anything else that might help figure out what is happening.

Dave Syer
Oct 24th, 2012, 02:32 AM
The code is never consumed on the server because the CSRF protection kicks in and prevents the client from using it. CSRF protection is a clientside feature so we'd have to see your client configuration to get an idea what that's about. I would guess that maybe you aren't managing the state of the OAuth2RestTemplate. The best way is to use the <oauth:rest-template/> DSL convenience.

kldavis4
Oct 24th, 2012, 08:17 AM
Here is the client spring context configuration. Note that I am using oauth:rest-template. The only difference between the working configuration and the one that triggers the CSRF protection is that the auth server is at the root context ('/').



<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.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/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.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<http access-denied-page="/login.jsp?authorization_error=true" xmlns="http://www.springframework.org/schema/security" entry-point-ref="casEntryPoint">
<intercept-url pattern="/j_spring_cas_security_check" access="ROLE_USER" />
<intercept-url pattern="/service/**" access="ROLE_USER"/>
<intercept-url pattern="/login.jsp" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />

<logout logout-success-url="/index.jsp" logout-url="/logout.do" />
<anonymous />
<custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER" />
<custom-filter position="CAS_FILTER" ref="casFilter" />
</http>

<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />

<!--define an oauth 2 resource for service -->
<oauth:resource id="service" type="authorization_code" client-id="client" client-secret="secret"
access-token-uri="https://localhost:8105/oauth/token" user-authorization-uri="https://localhost:8105/oauth/authorize" scope="service_read,service_write" />

<!--define an oauth 2 resource for trusted client on service -->
<oauth:resource id="trusted" type="client_credentials" client-id="my-client-with-registered-redirect"
access-token-uri="https://localhost:8105/oauth/token" scope="trust" />

<mvc:default-servlet-handler />

<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.BufferedImageHt tpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>

<bean id="contentViewResolver" class="org.springframework.web.servlet.view.ContentNegoti atingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJ acksonJsonView" />
</property>
</bean>

<!--Basic application beans. -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResou rceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<bean id="serviceClientController" class="com.acme.prototype.oauth.client.mvc.ClientControll er">
<property name="service" ref="service" />
</bean>

<bean id="service" class="com.acme.prototype.oauth.client.impl.ServiceImpl">
<property name="trustedMessageURL" value="http://localhost:8084/accounts/trusted/message" />
<property name="serviceListURL" value="http://localhost:8084/service?format=xml" />
<property name="serviceURLPattern" value="http://localhost:8084/service/%s" />
<property name="serviceRestTemplate">
<oauth:rest-template resource="service" />
</property>
<property name="trustedClientRestTemplate">
<oauth:rest-template resource="trusted" />
</property>
</bean>

<bean id="userDetailsServiceRestTemplate" class="org.springframework.web.client.RestTemplate"/>

<bean id="userDetailsServiceClient" class="com.acme.oauth2.UserDetailsServiceClient" xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<ref local="userDetailsServiceRestTemplate"/>
</constructor-arg>
<constructor-arg>
<value>http://localhost:8103</value>
</constructor-arg>
</bean>

<bean id="userDetailsService" class="com.acme.oauth2.AcmeUserDetailsService">
<constructor-arg>
<ref local="userDetailsServiceClient"/>
</constructor-arg>
</bean>


<!-- CAS SSO Configuration -->
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="http://localhost:8080/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>

<bean id="casFilter" class="org.springframework.security.cas.web.CasAuthentica tionFilter">
<property name="filterProcessesUrl">
<value>/j_spring_cas_security_check</value>
</property>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.Si mpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed.jsp"/>
</bean>
</property>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.Sa vedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
</bean>

<bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthentica tionEntryPoint">
<property name="loginUrl" value="https://localhost:8104/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>

<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>

<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.Ca sAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicket Validator">
<constructor-arg index="0" value="https://localhost:8104/" />
</bean>
</property>
<property name="key" value="ServiceClient"/>
</bean>

</beans>

kldavis4
Oct 26th, 2012, 11:10 PM
I finally figured this out. In my dev environment I am running the resource server, the authorization server and the client web application on separate ports on the same machine in different jetty instances. When I login to the client app (at localhost:8080/), it sets the session cookie for the root context. When I hit the authorization server (at localhost:8105) it sets another cookie for the root context, which clobbers the one that the client web app sets. After access confirmation when I am redirected back to the client web app the previous session is lost and the CSRF protection gets triggered. When I run the authorization server at a different context besides the root, the client web app cookie doesn't get clobbered. If I access my client web application at a different address (besides localhost), I am also able to avoid the issue. So problem solved and something to watch out for I guess if any others are running with similar dev configurations.

kldavis4
Nov 9th, 2012, 08:24 PM
Just a quick follow-up on this issue in case it helps someone else. Instead of using a different address, the session cookie name can be changed from the default (usually jsessionid) on the authorization server.