Authorising Pages

Having got the basic pages in we now need to restrict access to those page that change the database: adding and deleting. First of all we need a suitable login and logout page:

/examples/sql/login.xml
<page:content> <t:heading level="1">Paloose Login</t:heading> <t:p>Please enter your login details for the SQL Example:</t:p> <form:form> <form:start url="checkLogin.html">Login</form:start> <form:field name="username" type="text">User name</form:field> <form:field name="password" type="password">Password</form:field> </form:form> </page:content>
/examples/sql/logout.xml
<page:content> <t:heading level="1">Paloose SQL Example</t:heading> <t:p>You have now been logged out.</t:p> <t:p><link:link type="uri" ref="/examples/sql/sql.html">Return to SQL Example index</link:link></t:p> </page:content>

We also need a suitable error notification page:

/examples/sql/loginError.xml
<page:content> <t:heading level="1">Paloose SQL Example</t:heading> <t:p>Sorry that user/password combination does not seem to work, please try again:</t:p> <form:form> <!-- Will become the form's action attribute --> <form:start url="checkLogin.html">Login</form:start> <form:field name="username" type="text">User name</form:field> <form:field name="password" type="password">Password</form:field> </form:form> </page:content>

We now have to add in the various authorisation bits into the siteamp. First declare the components:

pp/examples/sql/sitemap.xmap
<map:components> <map:generators default="file"/> <map:transformers default="xslt"> <map:transformer name="mysql" src="resource://lib/transforming/SQLTransformer"> <map:parameter name="type" value="mysql"/> <map:parameter name="host" value="localhost:3306"/> <map:parameter name="user" value="hsfr"/> <map:parameter name="password" value="fof-hyd"/> <!-- Only time I use this password so don't get excited! :-) --> </map:transformer> <map:transformer name="password" src="resource://lib/transforming/PasswordTransformer"/> </map:transformers> <map:actions> <map:action name="auth-protect" src="resource://lib/acting/AuthAction"/> <map:action name="auth-login" src="resource://lib/acting/LoginAction"/> <map:action name="auth-logout" src="resource://lib/acting/LogoutAction"/> </map:actions> <map:serializers default="xml"/> <map:matchers default="wildcard"/> </map:components>

Then the authorisation manager:

pp/examples/sql/sitemap.xmap
<map:pipelines> <map:component-configurations> <map:authentication-manager> <!-- This is the means that Paloose checks whether a user is authenticated and is allowed to see pages protected within the pipeline. If the handler does not authenticate the use then go to redirect --> <map:handlers> <map:handler name="adminHandler"> <!-- Run this if the user needs login (diverts to this sitemap) --> <map:redirect-to uri="cocoon:/login"/> <!-- The pipeline used to authenticate the user --> <map:authentication uri="cocoon:/authenticate-user.html"/> </map:handler> </map:handlers> </map:authentication-manager> </map:component-configurations> <!-- pipelines --> </map:pipelines>

Finally the internal pipeline that processes the above:

pp/examples/sql/sitemap.xmap
<map:pipeline internal-only="true"> <map:match pattern="authenticate-user.html"> <map:generate src="context://configs/adminUsers.xml" label="xml-content"/> <map:transform src="context://resources/transforms/admin-getLoginQuery.xsl"> <map:parameter name="username" value="{request-param:username}"/> <map:parameter name="password" value="{request-param:password}"/> </map:transform> <!-- Encrypt the password --> <map:transform type="password"/> <map:transform src="context://resources/transforms/admin-buildAuthenticateDOM.xsl"/> <map:serialize type="xml"/> <!-- The output here is a standard Cocoon authenticate structure and is returned to the authentication-manager --> </map:match> <!-- Login form action --> <map:match pattern="login"> <!-- We come here when we need the user to log in. It produces a login form for the user to fill in. --> <map:aggregate element="root" label="aggr-content"> <map:part src="cocoon:/menus.xml" element="menus" strip-root="true"/> <map:part src="cocoon:/login.xml" element="content" strip-root="true"/> </map:aggregate> <map:call resource="outputPage"/> </map:match> <map:match pattern="checkLogin.html"> <!-- Match pattern must be the same match as that on the login form URL --> <map:act type="auth-login"> <map:parameter name="handler" value="adminHandler"/> <map:parameter name="username" value="{request-param:username}"/> <map:parameter name="password" value="{request-param:password}"/> <!-- Logged in so must have given password and username --> <map:redirect-to uri="cocoon:/sql.html"/> </map:act> <!-- Oops, not logged in properly so give appropriate screen back --> <map:aggregate element="root" label="aggr-content"> <map:part src="cocoon:/menus.xml" element="menus" strip-root="true"/> <map:part src="cocoon:/loginError.xml" element="content" strip-root="true"/> </map:aggregate> <map:call resource="outputPage"/> </map:match> </map:pipeline>

The format of the list of admin users is:

context://configs/adminUsers.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <authentication> <users> <user> <username>hsfr</username> <password>672b86ff.............33a92040c5</password> <data> <fullname>Hugh Field-Richards</fullname> <email>hsfr@hsfr.org.uk</email> </data> </user> </users> </authentication>

This is processed by the transform admin-getLoginQuery.xsl:

context://resources/transforms/admin-getLoginQuery.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:param name="password"/> <xsl:param name="username"/> <xsl:template match="//authentication"> <xsl:element name="authentication" > <xsl:attribute name="username"><xsl:value-of select="$username" /></xsl:attribute> <xsl:attribute name="password"><xsl:value-of select="$password" /></xsl:attribute> <xsl:apply-templates mode="pass"/> </xsl:element> </xsl:template> <xsl:template match="@*|node()" mode="pass"> <xsl:copy> <xsl:apply-templates select="@*|node()" mode="pass" /> </xsl:copy> </xsl:template> </xsl:stylesheet>

This is then run through the password transformer and then the build authenticate DOM transform:

context://resources/transforms/admin-buildAuthenticateDOM.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:variable name="gPassword" select="//authentication/@password" /> <!-- encrypted --> <xsl:variable name="gUsername" select="//authentication/@username" /> <!-- -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* --> <xsl:template match="authentication"> <authentication> <xsl:apply-templates select="users"/> </authentication> </xsl:template> <!-- -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* --> <xsl:template match="users"> <xsl:apply-templates select="user"/> </xsl:template> <!-- -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* --> <xsl:template match="user"> <xsl:if test="normalize-space( username ) = $gUsername and normalize-space( password ) = $gPassword"> <ID><xsl:value-of select="username"/></ID> <data> <ID><xsl:value-of select="username"/></ID> <username><xsl:value-of select="username"/></username> <password><xsl:value-of select="password"/></password> <fullname><xsl:value-of select="data/fullname"/></fullname> <xsl:if test="data/telephone"> <telephone><xsl:value-of select="data/telephone"/></telephone> </xsl:if> <xsl:if test="data/email"> <email><xsl:value-of select="data/email"/></email> </xsl:if> </data> </xsl:if> </xsl:template> </xsl:stylesheet>

Which outputs the necessary data for the authentication manager. Individual pages are protected with the following additions:

/examples/sql/sitemap.xmap
<map:pipeline> <map:match pattern="addComposer.html"> <map:act type="auth-protect"> <map:parameter name="handler" value="adminHandler"/> <map:call function="AddComposer::add"/> </map:act> </map:match> <map:match pattern="addComposer.kont"> <map:call function="AddComposer::add"/> </map:match> </map:pipeline>

Only externally accessible pages need be protected in the sitemap, all "internal-only" pipelines are protected naturally.

More information on authorising pages can be found in the documentation on authorising

Copyright 2006 — 2010 Hugh Field-Richards. All Rights Reserved.