SpringSurf - Authenticating users against an Alfresco repository

cancel
Showing results for 
Search instead for 
Did you mean: 

SpringSurf - Authenticating users against an Alfresco repository

kevinr1
Established Member
0 11 4,180

Introduction



An example of how to modify the SpringSurf quickstart application to authenticate users against an Alfresco server, ready to retrieve data from Alfresco REST APIs.



For simplicity in this article, I have renamed the spring-surf-application-quickstart-1.0.0-RC2.war to ssqs.war - so all referenced URLs and files will use the shorter name. Also we will edit the deployed files directly to quickly show what you would add or change based on the SpringSurf example WAR. Obviously you wouldn't do this normally, but it keeps things simple - as the interesting parts of the article are what you need to do to get something useful working against Alfresco!



The article also provides information on what happens under the covers during user login - you can skip the detail in those parts if you wish.

Modifying the Sample Application



1. Test initial deployment.



Download spring-surf-application-quickstart-1.0.0-RC2.war file and rename it to ssqs.war.



Deploy the ssqs.war to TomCat.



Start the server and check it is working by navigating to http://YOURSERVER/ssqs



You will see a home page with a number of components on, including a component with the message Welcome to Alfresco Surf!

2. Surf User Factory and Remote Configuration.



Stop Tomcat.



Open file: \ssqs\WEB-INF\surf.xml



All SpringSurf apps have this config file by default. It is where you can set a number of important boot configuration options, including the developer/production mode flag I mentioned in a previous post, plus other important framework defaults. The change here is to uncomment the following section:

 <!-- User factory for Alfresco 3.3 -->

<user-factory>webframework.factory.user.alfresco</user-factory>


This informs SpringSurf to make use of the Spring bean with the given ID when it needs to create a User instance. This bean is part of the SpringWebScripts project and will make a remote call back to an Alfresco Repository to the /api/login REST API to authenticate a user. The Alfresco UserFactory makes use of the 'alfresco' endpoint. The 'alfresco' endpoint is also part of SpringWebScripts configuration and is already wired up to the 'alfresco' connector which in turn uses the 'alfresco-ticket' authenticator. It is those objects that perform the hard work of authenticating and maintaining user credential information. If you are interested the default configuration for those objects can be found here:

\SpringSurf\spring-webscripts\spring-webscripts\src\main\resources\org\springframework\extensions\webscripts\spring-webscripts-config.xml


Like all SpringSurf configuration, this can be overridden in your surf.xml file. It is a simple matter to set the location of your Alfresco repository by overriding the endpoint configuration, so add the following in surf.xml as a new child element:

   <config evaluator='string-compare' condition='Remote'>

      <remote>

         <endpoint>

         <id>alfresco</id>

         <name>Alfresco - user access</name>

         <description>Access to Alfresco Repository WebScripts that require user authentication</description>

         <connector-id>alfresco</connector-id>

         <endpoint-url>http://ALFRESCOSERVER/alfresco/s</endpoint-url>

         <identity>user</identity>

         </endpoint>

      </remote>

   </config>


Edit ALFRESCOSERVER value with the server name and port as appropriate. The default install location is usually localhost:8080.

3. Page Authentication.



The sample app currently does not have any pages that require authentication to view, so we'll change that now.



Open file: ssqs\WEB-INF\pages\home\home.xml



Edit the authentication element as follows:

<authentication>user</authentication>


This informs SpringSurf that a valid authenticated user (not the default user instance of 'guest') is required to view this page. When the SpringSurf page dispatcher processes this information during the home page url request, it will automatically perform a redirect to the 'login' page-type (more on this below). This will begin the authentication process.

4. Login template.



Open file: \ssqs\WEB-INF\templates\sample\login.ftl



This is the example login template. The important parts to note here if you want to modify or create your own are the folllowing:

<form accept-charset='UTF-8' method='post' action='${url.context}/dologin'>


The 'action' element for this Form references the SpringMVC controller with the id 'dologin'. This is a SpringSurf controller bean that is wired to attempt a login based on a POST request, and that POST must contain two fields as defined in our Form:

<input name='username' type='text' />


<input name='password' type='password' />


These are the mandatory values it expects. Once the mandatory parameters are confirmed, the controller class will retrieve the appropriate UserFactory (as we configured above) and ask it to perform authentication. As mentioned above, this starts the process of the AlfrescoUserFactory authenticating via the 'alfresco' endpoint and it's associated authenticator class. If everything was successful, then a new User instance will be placed in the session with the Alfresco authentication information (usually a ticket value, but might be a cookie or similar) maintained by the framework for the life of that User instance, generally until their web session expires. We'll discuss it in detail shortly, but this means any further remote calls made by that user via the same 'alfresco' endpoint, such as Alfresco REST APIs, will automatically use the authentication information retrieved during login. This is how it works! And how Alfresco Share and other applications hide away the messy business of authentication from WebScript UI component writers - they simply work with a nice clean remoting API.



If you are interested, the dologin controller is implemented by the class: org.springframework.extensions.surf.mvc.LoginController.



It also has two other useful parameters 'success' and 'failure' which provide the redirect URLs SpringSurf should use after a login attempt. In Alfresco Share we redirect to the user dashboard page after a successful login attempt.



Finally, edit the following form values so that the correct pages are shown after a successful or failed login to our application:

<input name='success' type='hidden' value='${url.context}/home' />


<input name='failure' type='hidden' value='${url.context}/type/login' />


This ensures the 'home' page is shown on success, otherwise the 'login' page-type is shown again to allow retry.

5. Login challenge page.



Start TomCat.



Navigate to the root of the example app as before.



You will see that our simple login form has appeared! As expected SpringSurf has detected that as the guest user we are not authenticated to the appropriate level to view the home page.



How did SpringSurf know what login page to display? There are a number of ways to inform the framework as to what page you would like to use to authenticate users. In our surf.xml config for this example application, see the following section:

   <!-- Set up our sample login and logout pages -->

   <page-type>

      <id>login</id>

      <page-instance-id>sample/login</page-instance-id>

   </page-type>

   <page-type>

      <id>logout</id>

      <page-instance-id>sample/logout</page-instance-id>

   </page-type>


This configuration informs SpringSurf of the page instances to use for the 'special' login and logout page-types. A 'page-type' is really just a well known page that the framework may reference by id. So in this case the 'login' page-type has been defined as 'sample/login' and if you look in \ssqs\WEB-INF\templates\sample you will see two FreeMarker templates that implement those pages. Wondering why there are no page XML definition files in the \ssqs\WEB-INF\pages folder? The answer is that if no specific definition files are provided then SpringSurf will automatically work out what page id->page definition->template instance->template would be required and find those objects by declaration i.e. using the ID as the file name to look for. This saves having to create lots of little XML definition files that point to each other and eventually point to a concrete template file. So having a template with the same name as the page id is enough.



Login as a valid Alfresco user!



Use something like admin/admin or any user you have already created in your Alfresco server.



The home page will appear! This means our authentication configuration has worked, and we can now create components that get data from Alfresco. Exciting.



If you want to force a user logout, there is another SpringMVC controller called dologout that implements this. So navigate to http://YOURSERVER/ssqs/dologout and you will no longer be authenticated and the user session invalidated.

6. Remote calls to Alfresco REST APIs



We are now ready to make remote APIs call to Alfresco! Any component bound into a page that has been marked as requiring user authentication can now safely make a remote call. You can use the CMIS APIs or the various Alfresco Share APIs if you are looking for site specific data. In my next post we look at the remote APIs in more detail, for now take a look at the various CMIS examples or examples in the Share components.
11 Comments
blog_commenter
Active Member
Hi Kevin, Thx for this.

Will this also work if the SpringSurf app is on another server than Alfresco or is that complicating matters?
kevinr1
Established Member
Yes indeed it will, in the examples where I mention modifying the Remote config section, the ALFRESCOSERVER just needs to point to your Alfresco server. I always run my tests with two separate server instances. As it's no fun waiting for Alfresco to start, it's much easier to have your Surf app in a separate tomcat instance for quick restarts etc.
blog_commenter
Active Member
Thanks Kevin, great article! You saved me a bunch of time. My SpringSurf app on my local Tomcat instance now remoting to an Alfresco server for authentication.
blog_commenter
Active Member
Thanks, you saved me
blog_commenter
Active Member
Anyone still out here?  I have tried to implement this on an alfresco web quick start site and am having problems.  My webquickstart.log is showing the following error:



Unable to locate template for page: sample/login





Following the instructions here for the ssqs site works fine, but not when I try to make the same changes to my web quick start site.  Any ideas? 



Thank you.





Scott
kevinr1
Established Member
The sample/login template is included as part of the SpringSurf quickstart app - I don't think it's part of the webquickstart though - it's a different app just has a similar name. You can copy that template out of the SpringSurf app or create your own login page based on it.
blog_commenter
Active Member
Kevin,



I did copy the login templates from the SpringSurf quickstart app.  I first tried them in my own folder (templates/pace), and in the original templates/sample folder, with the appropriate changes to surf.xml but had no luck in either case.  Same error message in the log file.



Scott
blog_commenter
Active Member
I should also mention that I am not a unix/java/tomcat guy, so it makes everything that much more difficult.  This may be something as simple as a configuration setting somewhere, but I wouldn't know where to begin to look. 



Scott
blog_commenter
Active Member
Great explanation!!!
blog_commenter
Active Member
Hi Kevin



I have implemented SSO with site-minder and when user logs into site-minder he will be directly redirected to alfresco home page with our asking alfresco username and password. But when user hits any alfresco web-scripts its asking for username and password. Is there any way we can achieve(calling webscript) this without asking username and password to user.



regards,

alfsender
kevinr1
Established Member
Yes - using either the cookie or header based connector config and setting the endpoint config url to the appropriate webscripts service url e.g.

http://localhost:8080/alfresco/wcs

Please post your question on the Alfresco forums (or point me to it if already exists) and I can reply with a full example.