Announcement Announcement Module
Collapse
No announcement yet.
Separate Resource Server and Authorization Server Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Separate Resource Server and Authorization Server

    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.
    Code:
    <oauth:resource-server id="resourceServerFilter"
    		resource-id="class" token-services-ref="resourceServerTokenService" />
    
    	<bean id="resourceServerTokenService" class="gov.noaa.cls.m2m.auth.ClassResourceServerTokenServices" />
    
    	<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.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>
    
    	<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>

  • #2
    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.

    Comment


    • #3
      Example?

      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!

      Comment


      • #4
        See here: https://github.com/cloudfoundry/uaa/...ng-servlet.xml. It's pretty straightforward, if annoying.

        Comment


        • #5
          Thank you; that will help a lot!

          Comment


          • #6
            Is this the corresponding stand alone authorization server? https://github.com/cloudfoundry/uaa/...ng-servlet.xml

            Comment


            • #7
              Not quite vanilla (although it is an authorization server). The vanilla auth server is https://github.com/cloudfoundry/uaa/...ng-servlet.xml.

              Comment


              • #8
                Originally posted by Dave Syer View Post
                Not quite vanilla (although it is an authorization server). The vanilla auth server is https://github.com/cloudfoundry/uaa/...ng-servlet.xml.
                great, thanks for the quick reply

                Comment


                • #9
                  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?

                  Comment


                  • #10
                    Correct. Either the tokens have to be decodable locally by the resource server or it has to share storage with the auth server.

                    Comment


                    • #11
                      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?

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          More details

                          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:

                          Code:
                          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.grant.code.AuthorizationCodeAccessTokenProvider.getParametersForTokenRequest(AuthorizationCodeAccessTokenProvider.java:199)
                          	at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:161)
                          	at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:120)
                          	at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:100)
                          	at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:194)
                          	at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:148)
                          	at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:89)
                          	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:434)
                          	at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:122)
                          	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:415)
                          	at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:213)
                                  at com.acme.prototype.oauth.client.impl.ServiceImpl.getIds(ServiceImpl.java:35)
                                  at com.acme.prototype.oauth.client.mvc.ClientController.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 Attachment

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

                          Comment


                          • #14
                            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.

                            Comment


                            • #15
                              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 ('/').

                              Code:
                              <?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.BufferedImageHttpMessageConverter" />
                              		</mvc:message-converters>
                              	</mvc:annotation-driven>
                              
                              	<bean id="contentViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
                              		<property name="mediaTypes">
                              			<map>
                              				<entry key="json" value="application/json" />
                              			</map>
                              		</property>
                              		<property name="defaultViews">
                              			<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                              		</property>
                              	</bean>
                              
                              	<!--Basic application beans. -->
                              	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                              		<property name="prefix" value="/WEB-INF/jsp/" />
                              		<property name="suffix" value=".jsp" />
                              	</bean>
                              
                              	<bean id="serviceClientController" class="com.acme.prototype.oauth.client.mvc.ClientController">
                              		<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.CasAuthenticationFilter">
                                    <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.SimpleUrlAuthenticationFailureHandler">
                                              <property name="defaultFailureUrl" value="/casfailed.jsp"/>
                                          </bean>
                                      </property>
                                      <property name="authenticationSuccessHandler">
                                          <bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
                                              <property name="defaultTargetUrl" value="/"/>
                                          </bean>
                                      </property>
                                  </bean>
                              
                                  <bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
                                      <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.CasAuthenticationProvider">
                                    <property name="userDetailsService" ref="userDetailsService"/>
                                    <property name="serviceProperties" ref="serviceProperties" />
                                    <property name="ticketValidator">
                                      <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                                        <constructor-arg index="0" value="https://localhost:8104/" />
                                        </bean>
                                    </property>
                                    <property name="key" value="ServiceClient"/>
                                  </bean>
                              
                              </beans>

                              Comment

                              Working...
                              X