Announcement Announcement Module
Collapse
No announcement yet.
ACEGI Authentication for a RESTful service Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ACEGI Authentication for a RESTful service

    This is may be glaringly obvious but -

    I want to write an API framework that will provide data to the outside world in XML format, as long as they are authenticated (like the Google API).

    Is this possible with ACEGI? What do I have to do.

    I'm really a novice when it comes to web services, but if you can point me in the right direction - hopefully I'll get it sooner than later.

    Thanks,

    Murali

  • #2
    Hi Murali,

    Yes, it is possible to use Acegi with RESTful web services in Spring. I've actually just managed to do that myself within the last few days. In order to get Acegi to automatically authenticate all your requests, you'll have to change your Acegi configuration to use HTTP BASIC authentication for any requests along your APIs URL paths. (or some other authentication scheme such as certificate based authentication).

    You can do this by specifying a pattern for your RESTful API paths in your filterChainProxy (ie I just copied from my default and made changes as needed).

    Here's what I did :
    Code:
    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
    		<property name="filterInvocationDefinitionSource">
    			<value>
    				CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    				PATTERN_TYPE_APACHE_ANT
    				/restful-api/**/*=httpSessionContextIntegrationFilter,logoutFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,basicExceptionTranslationFilter,filterInvocationInterceptor
    				/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,formExceptionTranslationFilter,filterInvocationInterceptor
    			</value>
    		</property>
    	</bean>
    The changes I had to make were to change from the form processing filter to a BASIC processing filter and change to from the form processing exception translation filter to a BASIC translation filter, which you can see in the paths above. The beans I had to use for BASIC filters looked like this :
    Code:
    	<bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
    		<property name="authenticationManager"		ref="authenticationManager"/>
    		<property name="authenticationEntryPoint"	ref="basicAuthenticationEntryPoint"/>
    	</bean>
    	
    	<bean id="basicAuthenticationEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
    		<property name="realmName" value="My Authentication Realm"/>
    	</bean>
    	
    	<bean id="basicExceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
    		<property name="authenticationEntryPoint" ref="basicAuthenticationEntryPoint"/>
    	</bean>
    Note that the difference between using BASIC based authentication versus form based authentication isn't as simple as the Acegi manual would imply. You have to change the exception translation filter as well as the processing filter, otherwise all your failed authentication requests will get redirected to the login screen (as mine did until I figured this out). That little bit isn't mentioned in the Acegi documentation last I checked (which was a couple days ago).

    Comment


    • #3
      Re ACEGI Authentication for a RESTful service

      Alex - thank you.

      Before I start off implementing this ....

      Would you be able to post an example of how your request / response takes place
      i.e
      <yoururl>/restful/yourname/listbookmarks

      If a person accessed that page would it throw an exception?
      Whats the first page you authenticate at?
      Do you send a token back and forth?

      Thanks,

      Murali

      Comment


      • #4
        The request / response typically does not take place through a browser (though in the case of GETs it can). Because the Web Service is restful, everything is done through HTTP response codes, there should be no exceptions thrown (unless you have some kind of framework for mapping them to HTTP response codes). If a person accesses a page that does not exist, an HTTP 404 response should be returned, possibly with errors (in the form of some XML structure) in the body of the response to indicate what went wrong or give suggestions.

        Whats the first page you authenticate at?
        The first page you should get authenticated at is the first page in your web service that you try to access. Whoever's trying to access your web service should ensure that they send the BASIC authentication token within the header of their request (pre-emptively), or ensure that whatever library they're using can handle BASIC authentication challenges.

        Do you send a token back and forth?
        Yes, a token has to be sent between the requestor and the server each time an API request is made, barring the chance that you setup and maintain some kind of session in which the token can be stored.

        I also notice that you have /listbookmarks in your URL. I know this could be just an example, but this type of element in your path is redundant to the whole concept of a RESTful web service. The type of request the requestor wants to make of your web service is determined with HTTP methods (ie verbs). Your URL should be something like
        Code:
        <yourserver>/restful/bookmarks
        and to get a list of them, the method should be GET. If you wanted to get a specific bookmark, the URL should be something like
        Code:
        <yourserver>/restful/bookmarks/123
        where 123 is the ID of the bookmark the requestor wants to retrieve.

        Having 'yourname' in the URL path would be redundant in the case of authentication. Since you're already using Acegi, you can get the Principal token from the Acegi context to determine who's accessing the service since it would already have been authenticated, and if your code's structured the right way, you could also use that to determine whose bookmarks should be read.

        Comment


        • #5
          The request / response typically does not take place through a browser (though in the case of GETs it can). Because the Web Service is restful, everything is done through HTTP response codes, there should be no exceptions thrown (unless you have some kind of framework for mapping them to HTTP response codes). If a person accesses a page that does not exist, an HTTP 404 response should be returned, possibly with errors (in the form of some XML structure) in the body of the response to indicate what went wrong or give suggestions.
          This is what I'm trying to target first. A GET response, but authenticated, via a browser token.

          Secondly, doing the same thing, is it possible, that I assign a unique "token" of sorts to every user who's allowed to access the data via this GET, and ACEGI authenticates based on that token?

          To test this, what framework would I use? (Some mock framework I assume?)

          Thank you very much for this valuable information

          Comment


          • #6
            A GET response, but authenticated, via a browser token.
            If you want to be able to do the GETs through your browser, whenever a requestor opens the URL, they'll be prompted for credentials by the browser.

            Secondly, doing the same thing, is it possible, that I assign a unique "token" of sorts to every user who's allowed to access the data via this GET, and ACEGI authenticates based on that token?
            Yes, you'll have to integrate Acegi's roles into your system. You can read up about them in the Acegi manual.

            To test this, what framework would I use? (Some mock framework I assume?)
            I've had great success using JUnit with Spring's mocks. If you use maven 2, you can get them with the spring-mock dependency. It looks like this :

            Code:
            			<dependency>
            				<groupId>org.springframework</groupId>
            				<artifactId>spring-mock</artifactId>
            				<version>2.0.7</version>
            				<scope>provided</scope>
            			</dependency>

            Comment


            • #7
              How do I handle

              In the sense, being novice in spring also , say I just wanted
              Code:
              url.com/bookmarks/3
              which would give out the 3rd bookmark in a list, how do I get the controller to respond to bookmarks/
              Code:
              
              <bean id="urlMapping"	class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
              		<property name="alwaysUseFullPath">
              			<value>true</value>
              		</property>
              		<property name="mappings">
              <prop key="/restful-api/**">restfulAPITestController</prop>
              </bean>
              Here's my controllers name resolver

              Code:
              <!-- Restful API Controller -->
              	<bean id="restfulAPIController" class="llr.web.impl.RestfulAPITestController">	
              		<property name="methodNameResolver">
              			<ref bean="restfulMethodAdminNameResolver" />
              		</property>
              	</bean>
              
              <bean id="restfulMethodAdminNameResolver"
              		class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
              		<property name="mappings">
              			<value>
              			/bookmarks/*=list
              			</value>
              		</property>
              	</bean>
              </bean>
              But I'm also using InternalViewResolver for other parts of my app

              Code:
              <bean id="viewResolver"
              		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              		<property name="viewClass">
              			<value>org.springframework.web.servlet.view.JstlView</value>
              		</property>
              		<property name="prefix">
              			<value>/WEB-INF/jsp/</value>
              		</property>
              		<property name="suffix">
              			<value>.jsp</value>
              		</property>
              	</bean>
              Can someone please tell me how I get the controller to resolve to "verbs" for the restful api, instead of pushing to a .jsp page?

              Thanks,

              Murali
              PS: I realize this is cross posting, but I was hoping to keep this thread together.

              Comment

              Working...
              X