Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: OAuth 2 without Spring MVC?

  1. #1
    Join Date
    Nov 2011
    Posts
    9

    Default OAuth 2 without Spring MVC?

    I have been using spring-security for our web application and would now like to use oauth 2 for our REST APIs. The web application does not use Spring MVC. spring-security-oauth2, however, seems to depend on Spring MVC which would mean it can be used only in web-apps that use Spring MVC.

    Is my understanding correct?

    Thanks!

  2. #2
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    Not precisely. The OAuth2 provider support is implemented using Spring MVC, but your app only needs to use Spring for that, not for anything else if you don't want to. Since you are already using Spring Security it doesn't seem like a big difference. Just keep the DispatcherServlet on it's own path.

  3. #3
    Join Date
    Nov 2011
    Posts
    9

    Default

    Quote Originally Posted by Dave Syer View Post
    Just keep the DispatcherServlet on it's own path.
    Thanks for the pointer.

    How would I go about wiring the REST API's along with this. The REST APIs are built using Jersey.
    Currently web.xml contains (among other things):

    Code:
    	
             <servlet>
    		<servlet-name>jersey</servlet-name>
    		<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    	</servlet>
    	<servlet-mapping>
    		<servlet-name>jersey</servlet-name>
    		<url-pattern>/api/*</url-pattern>
    	</servlet-mapping>
    What url-mapping would I use for the DispatcherServlet and how would that work with Jersey? I am sorry if the question is fairly basic. I am not familiar with Spring MVC.

  4. #4
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    Look at the web.xml for the OAuth2 samples (or any Spring MVC application). You need to add a DispatcherServlet for the OAuth endpoints and tell it where to get its application context from. The samples map DispatcherServlet to /, and that might work because it doesn't clash with your Jersey servlet. I would try that first and see if you can get it working before you go off piste with the OAuth endpoint URLs (they are set to /oauth/{token,authorize} by default, and to change them requires adding another filter in web.xml - something I haven't got round to documenting yet, but you will be a perfect guinea pig).

  5. #5
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    But, actually, now I come to think of it, you don't need the endpoints do you, if it's just a resource server? So you don't need a DispatcherServlet. You should be able to add the protected resource filter (via <oauth:resource-server/>) to your jersey endpoints via the regular Spring Security context wherever you put that.

  6. #6
    Join Date
    Nov 2011
    Posts
    9

    Default

    Quote Originally Posted by Dave Syer View Post
    Look at the web.xml for the OAuth2 samples (or any Spring MVC application). You need to add a DispatcherServlet for the OAuth endpoints and tell it where to get its application context from. The samples map DispatcherServlet to /, and that might work because it doesn't clash with your Jersey servlet. I would try that first and see if you can get it working before you go off piste with the OAuth endpoint URLs (they are set to /oauth/{token,authorize} by default, and to change them requires adding another filter in web.xml - something I haven't got round to documenting yet, but you will be a perfect guinea pig).
    Unfortunately / conflicts with the Struts 2 dispatcher. I guess you are referring to setting up the oauth2EndpointUrlFilter?

    But, actually, now I come to think of it, you don't need the endpoints do you, if it's just a resource server? So you don't need a DispatcherServlet. You should be able to add the protected resource filter (via <oauth:resource-server/>) to your jersey endpoints via the regular Spring Security context wherever you put that.
    If I am to provide the tokens don't I need the end points?

  7. #7
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    To your first point: I didn't say you had to use / for your DispatcherServlet, just that the samples are wired like that. Did you try it?

    To your second point, yes you need the endpoints to provide tokens. I didn't get that requirement from your original post - you only mentioned REST APIs, which would be protected resources.

  8. #8
    Join Date
    Jan 2012
    Posts
    1

    Default

    Hi krishy,

    I was wondering if you were ever able to get the authorization server working while in a webapp that has struts2 handling the /* context.

    I have tried specifying the custom oauth2 endpoints via the authorization server configuration and specifying the necessary filter before spring security in the web.xml with no luck. Whenever I hit the authorization URL /<appName>/api-access/oauth/authorize?client_id=tonr&redirect_uri=http%3A%2F%2 Flocalhost%3A8080%2Ftonr2%2Ftraits%2F&response_typ e=code&scope=read, I get a 404.

    Also, when I come from the client (in this case, a modified tonr2 sample app), the request that comes into tomcat is /<appName>/api-access/oauth/authorize, but when I do the app login, I get sent to /<appName>/oauth/authorize. This also results in a 404.

    Is there something I'm missing?

    Thanks,
    Harleen
    Quote Originally Posted by krishy View Post
    Unfortunately / conflicts with the Struts 2 dispatcher. I guess you are referring to setting up the oauth2EndpointUrlFilter?



    If I am to provide the tokens don't I need the end points?

  9. #9
    Join Date
    Nov 2011
    Posts
    9

    Default

    Quote Originally Posted by harleen View Post
    I have tried specifying the custom oauth2 endpoints via the authorization server configuration and specifying the necessary filter before spring security in the web.xml with no luck. Whenever I hit the authorization URL /<appName>/api-access/oauth/authorize?client_id=tonr&redirect_uri=http%3A%2F%2 Flocalhost%3A8080%2Ftonr2%2Ftraits%2F&response_typ e=code&scope=read, I get a 404.

    Also, when I come from the client (in this case, a modified tonr2 sample app), the request that comes into tomcat is /<appName>/api-access/oauth/authorize, but when I do the app login, I get sent to /<appName>/oauth/authorize. This also results in a 404.
    No, I did not follow this through. I ended up forking the project and adding some rudimentary Jersey support for the RO authorization type (since the web app I am working is built with Struts 2 and Jersey).

    To answer your question: could you please paste your web.xml configuration? More specifically the mappings for /*?

  10. #10
    Join Date
    May 2005
    Location
    Denver, CO, USA
    Posts
    57

    Question Getting contexed out...

    I too am making use of Jersey to create a Spring based SaaS app that serves only RESTful APIs. I was in the process of updating the various frameworks in use, and wanted to move from 1.0.0.M4 to 1.0.0.M5, but also to Spring 3.1.0.RELEASE since there are some new features (e.g. profiles) that I would like to work with.

    Anyway, the security config is seriously different going from M4 to M5, and I ended up with the "not found" problem when trying to access .../appcontext/oauth/{token,authorize}. My application does not contain any user specific data, only tenant specific data. Tenant applications use their client credentials to obtain bearer tokens on behalf of user agents accessing their sites.

    I'm trying to untangle what I need for working with M5 (and beyond?). My application is both the authorization server and the resource server. Looking at documentation on github, the M5 samples etc. and this thread, I managed to configure security in the context of the DispatcherServlet (the authorization server?), since it wants to load WEB-INF/servletname-servlet.xml. I had simply used ContextLoaderListener, now I have them both.

    Sticking with the naming ("spring") in the examples for the time being, here is WEB-INF/spring-servlet.xml:

    Code:
    <?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: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-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/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd">
    		
    	<!-- Note that ISEC is both an OAuth authorization server as well as the 
    		resource server.
    	-->
    	<http auto-config="true" create-session="never" access-decision-manager-ref="accessDecisionManager">
    		<intercept-url pattern="/api/rest/v1/client/**" access="ROLE_CLIENT,SCOPE_READ" />
    		<intercept-url pattern="/api/rest/v1/partner/**" access="ROLE_PARTNER,SCOPE_WRITE" />
    		<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    		<intercept-url pattern="/oauth/authorize" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    		<intercept-url pattern="/oauth/**" access="ROLE_CLIENT,ROLE_PARTNER" />
    			
    		<custom-filter ref="resourceServerFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
    	</http>
    	
    	<oauth:resource-server id="resourceServerFilter" resource-id="isecApi" token-services-ref="tokenServices"/>
    	
    	<oauth:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices">
    		<oauth:client-credentials />
    	</oauth:authorization-server>
    	
    	<authentication-manager/>
    	
    	<beans:bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.RandomValueTokenServices">
    		<beans:property name="tokenStore" ref="tokenStore"/>
    		<beans:property name="supportRefreshToken" value="false" />
    	</beans:bean>
    
    	<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
    		<beans:constructor-arg>
    			<beans:list>
    				<beans:bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
    				<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
    				<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
    			</beans:list>
    		</beans:constructor-arg>
    	</beans:bean>
    		
    </beans:beans>
    The beans named tokenServices and clientDetailsService are defined in a different context file.

    And web.xml:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>
    			classpath:base-appContext.xml 
    			classpath:cassandra-appContext.xml 
    			classpath:search-appContext.xml 
    			classpath:service-appContext.xml 
    			classpath:resource-appContext.xml
    			classpath:integration-appContext.xml
    		</param-value>
    	</context-param>
    	
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    	
    	<filter>
    	    <filter-name>resourceServerFilter</filter-name>
    	    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    	    <init-param>
    	        <param-name>contextAttribute</param-name>
    	        <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
    	    </init-param>
    	</filter>
    
    	<filter>
    		<filter-name>springSecurityFilterChain</filter-name>
    		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    	    <init-param>
    	        <param-name>contextAttribute</param-name>
    	        <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
    	    </init-param>
    	</filter>
    	
    	<!-- Accept header filter. Enable API content type suffixes for Jersey -->
    	<filter>
    		<filter-name>acceptHeaderFilter</filter-name>
    		<filter-class>com.company.isec.util.AcceptHeaderServletFilter</filter-class>
    		<!-- Map suffixes to content types -->
    		<init-param>
    			<param-name>xml</param-name>
    			<param-value>application/xml</param-value>
    		</init-param>
    		<init-param>
    			<param-name>json</param-name>
    			<param-value>application/json</param-value>
    		</init-param>
    	</filter>
    
    	<!-- Jersey (JAX-RS) servlet for implementing RESTful APIs -->
    	<servlet>
    		<servlet-name>jerseySpringServlet</servlet-name>
    		<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    		<init-param>
    			<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    			<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
    		</init-param>
    		<init-param>
    			<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    			<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
    		</init-param>
    		<init-param>
    			<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
    			<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
    		</init-param>
    		<init-param>
    			<param-name>com.sun.jersey.config.property.packages</param-name>
    			<param-value>com.company.isec.ws.resource,com.company.isec.ws.provider</param-value>
    		</init-param>
    	</servlet>
    	
    	<servlet>
    		<servlet-name>spring</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    	
    	<filter-mapping>
    	    <filter-name>resourceServerFilter</filter-name>
    	    <url-pattern>/*</url-pattern>
    	</filter-mapping>
    	
    	<filter-mapping>
    		<filter-name>springSecurityFilterChain</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    		
    	<filter-mapping>
    		<filter-name>acceptHeaderFilter</filter-name>
    		<url-pattern>/api/rest/*</url-pattern>
    	</filter-mapping>
    
    	<servlet-mapping>
    		<servlet-name>jerseySpringServlet</servlet-name>
    		<url-pattern>/api/rest/*</url-pattern>
    	</servlet-mapping>
    	
    	<servlet-mapping>
    		<servlet-name>spring</servlet-name>
    		<url-pattern>/notused</url-pattern>
    	</servlet-mapping>
    
    </web-app>
    In the log output I see:

    Code:
    ...
    2012-01-29 21:01:16 INFO  annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/oauth/token] onto handler 'tokenEndpoint'
    2012-01-29 21:01:16 INFO  annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/oauth/token.*] onto handler 'tokenEndpoint'
    2012-01-29 21:01:16 INFO  annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/oauth/token/] onto handler 'tokenEndpoint'
    2012-01-29 21:01:16 INFO  servlet.DispatcherServlet - FrameworkServlet 'spring': initialization completed in 376 ms
    2012-01-29 21:01:16.284:INFO::Started SelectChannelConnector@0.0.0.0:9090
    [INFO] Started Jetty Server
    That's very encouraging. However, using an existing test command to acquire a bearer token results in:

    Code:
    [imac:~] jas% curl -w "\nhttp code: %{http_code}\n" -d "grant_type=client_credentials&client_id=myClientId&client_secret=myClientSecret" "http://localhost:9090/isec/oauth/token"
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
    <title>Error 404 Not Found</title>
    </head>
    <body><h2>HTTP ERROR 404</h2>
    <p>Problem accessing /isec/oauth/token. Reason:
    <pre>    Not Found</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>                                                
    <br/>
    That results in a POST to the token endpoint, which all worked great in my prior incarnation.

    Any ideas on why authorization server functionality is not quite right for me?

    Thanks,

    Jeff

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •