<?xml version="1.0" encoding="UTF-8"?><rss xmlns:i18n="http://apache.org/cocoon/i18n/2.1" xmlns:p="http://outerx.org/daisy/1.0#publisher" xmlns:d="http://outerx.org/daisy/1.0" version="2.0"><channel><title>Wiki</title><link>http://new.cocoondev.org/wiki</link><description>A wiki for Daisy users.</description><item><title>Creating a multi role authentication scheme</title><link>http://new.cocoondev.org/wiki/620-cd</link><description>&lt;html&gt;
&lt;head&gt;
&lt;META http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
&lt;base href="http://new.cocoondev.org"&gt;
&lt;link href="/resources/skins/default/css/daisy.css" type="text/css" rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 xmlns:d="http://outerx.org/daisy/1.0" xmlns:lt="http://outerx.org/daisy/1.0#linktransformer" xmlns:einclude="http://outerx.org/daisy/1.0#externalinclude" xmlns:p="http://outerx.org/daisy/1.0#publisher" xmlns:i18n="http://apache.org/cocoon/i18n/2.1" xmlns:urlencoder="xalan://java.net.URLEncoder" id="dsy620-cd" class="daisy-document-name"&gt;Creating a multi role authentication scheme&lt;/h1&gt;


&lt;p xmlns:jx="http://apache.org/cocoon/templates/jx/1.0" xmlns:ns="http://outerx.org/daisy/1.0"&gt;This step by step instruction explains how to extend the Daisy CMS with your
own authentication scheme that fits your needs.&lt;/p&gt;


&lt;p&gt;
&lt;strong&gt;Assumption&lt;/strong&gt;: You already set up daisy on a windows system and
everything's working great. Your also doing the codeing and compiling on a
separate system (a mac) because you too lazy to install the dev tool on the
windows server...&lt;/p&gt;


&lt;p&gt;
&lt;strong&gt;Task&lt;/strong&gt;: You would like new daisy users to be allocated a given
role when they first logon. The system admin chaps would ideally like the group
the user belongs to on a windows network to dictate this role allocation.&lt;/p&gt;


&lt;p class="note"&gt;This solution is useful where there are a number of different
users who need to see different resources on the same server (ie. student and
staff at a university).&lt;/p&gt;


&lt;h2&gt;Step 1: Checking out the sources&lt;/h2&gt;


&lt;p&gt;Download the daisy sources daisy-x.x.x.tar.gz of the latest stable (or
milestone) release at the
&lt;a href="http://svn.cocoondev.org/dist/daisy/"&gt;download area&lt;/a&gt; (or
&lt;a href="http://cocoondev.org/daisydocs-1_3/152.html"&gt;check out&lt;/a&gt; the latest
version from SVN, whatever you prefer). Extract the tarball into a directory on
your local machine (although you do not have to create that environment
variable, I will refer to that directory as DAISY_SRC during the rest ot this
tutorial):&lt;/p&gt;


&lt;pre&gt;$ tar xvzf daisy-x.x.x.tar.gz&lt;/pre&gt;


&lt;h2&gt;Step 2: Copy the sources of the Ntlm-authentication&lt;/h2&gt;


&lt;p&gt;Descend to the dircectory $DAISY_SRC/services/ and make a copy of the
directory ntlm-auth, which contains the sources for the Ntlm authentication
scheme. We take these sources as starting point and we will modify them to fit
our needs.&lt;/p&gt;


&lt;pre&gt;$ cp -R ntlm-auth/ ntlm-group-auth&lt;/pre&gt;


&lt;h2&gt;Step 3: Create the java classes for authentication&lt;/h2&gt;


&lt;h3&gt;Step 3a: Rename the existing sourcefiles for AuthenticationFactory and
AuthenticationScheme&lt;/h3&gt;


&lt;p&gt;Descend into the directory
$DAISY_SRC/services/ssh-auth/src/java/org/outerj/daisy/authentication/impl&lt;br&gt;
Rename the both existing sourcefiles for the AuthenticationFactory and the
AuthenticationScheme&lt;/p&gt;


&lt;pre&gt;$ mv NtlmAuthenticationFactory.java NtlmGroupAuthenticationFactory.java
$ mv NtlmAuthenticationScheme.java NtlmGroupAuthenticationScheme.java&lt;/pre&gt;


&lt;h3&gt;Step 3b: Edit NTLMGroupAuthenticationFactory.java&lt;/h3&gt;


&lt;p&gt;In your favourite editor or IDE, edit the source file for the NTLM Group
Authentication Factory and change it to:&lt;/p&gt;


&lt;pre&gt;package org.outerj.daisy.authentication.impl;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.outerj.daisy.authentication.spi.*;
import org.outerj.daisy.plugin.PluginRegistry;

import javax.annotation.PreDestroy;
import java.util.Map;
import java.util.HashMap;

/**
 * Constructs and registers NtlmGroupAuthenticationSchemes with the UserAuthenticator.
 *
 */
public class NtlmGroupAuthenticationFactory  {
    private PluginRegistry pluginRegistry;
    private Map&amp;lt;String, AuthenticationScheme&amp;gt; schemes = new HashMap&amp;lt;String, AuthenticationScheme&amp;gt;();

    public NtlmGroupAuthenticationFactory(Configuration configuration, PluginRegistry pluginRegistry) throws Exception {
        this.pluginRegistry = pluginRegistry;
        this.configure(configuration);
        registerSchemes();
    }

    @PreDestroy
    public void destroy() {
        unregisterSchemes();
    }

    private void registerSchemes() throws Exception {
        for (Map.Entry&amp;lt;String, AuthenticationScheme&amp;gt; entry : schemes.entrySet()) {
            pluginRegistry.addPlugin(AuthenticationScheme.class, entry.getKey(), entry.getValue());
        }
    }

    private void unregisterSchemes() {
        for (Map.Entry&amp;lt;String, AuthenticationScheme&amp;gt; entry : schemes.entrySet()) {
            pluginRegistry.removePlugin(AuthenticationScheme.class, entry.getKey(), entry.getValue());
        }
    }

    private void configure(Configuration configuration) throws ConfigurationException {
        Configuration[] schemeConfs = configuration.getChildren("scheme");
        for (Configuration schemeConf : schemeConfs) {
            String name = schemeConf.getAttribute("name");
            String description = schemeConf.getAttribute("description");
            String domainControllerAddress = schemeConf.getChild("domainControllerAddress").getValue();
            String domain = schemeConf.getChild("domain").getValue();
			
			String file1 = schemeConf.getChild("fileLocation1").getValue();
			String file2 = schemeConf.getChild("fileLocation2").getValue();
			
			Configuration subUserCreator1 = schemeConf.getChild("subUserCreator1");
			UserCreator userCreator1 = UserCreatorFactory.createUser(subUserCreator1, name);
			
			
			Configuration subUserCreator2 = schemeConf.getChild("subUserCreator2");			
			UserCreator userCreator2 = UserCreatorFactory.createUser(subUserCreator2, name);

		
			AuthenticationScheme scheme = new NtlmGroupAuthenticationScheme(name, description, domainControllerAddress, domain, file1, userCreator1, file2, userCreator2);
			Configuration cacheConf = schemeConf.getChild("cache");
			if (cacheConf.getAttributeAsBoolean("enabled")) {
				int maxCacheSize = cacheConf.getAttributeAsInteger("maxCacheSize", 3000);
				long maxCacheDuration = cacheConf.getAttributeAsLong("maxCacheDuration", 30 * 60 * 1000); // default: half an hour
				scheme = new CachingAuthenticationScheme(scheme, maxCacheDuration, maxCacheSize);
			}

			if (schemes.containsKey(name))
				throw new ConfigurationException("Duplicate authentication scheme name: " + name);
			
			schemes.put(name, scheme);
				

            
        }
    }
}&lt;/pre&gt;


&lt;p&gt;Note that this authentication factory reads in the configuration for two
files and userCreators which are then passed to the authentication scheme.&lt;/p&gt;


&lt;h3&gt;Step 3c: Edit NTLMGroupAuthenticationScheme.java&lt;/h3&gt;


&lt;p&gt;In your favourite editor or IDE, edit the source file for the NTLM Group
Authentication Scheme and change it to:&lt;/p&gt;


&lt;pre&gt;package org.outerj.daisy.authentication.impl;

import org.outerj.daisy.authentication.spi.AuthenticationScheme;
import org.outerj.daisy.authentication.spi.AuthenticationException;
import org.outerj.daisy.authentication.spi.UserCreator;
import org.outerj.daisy.repository.Credentials;
import org.outerj.daisy.repository.user.User;
import org.outerj.daisy.repository.user.UserManager;
import jcifs.smb.SmbException;
import jcifs.smb.SmbAuthException;
import jcifs.smb.SmbSession;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.*;
import jcifs.UniAddress;

import java.net.UnknownHostException;
import java.net.MalformedURLException;

public class NtlmGroupAuthenticationScheme implements AuthenticationScheme {
    private final String name;
    private final String description;
    private final String domainControllerAddress;
    private final String domain;
	private final String file1;
    private final UserCreator userCreator1;
	private final String file2;
    private final UserCreator userCreator2;

    public NtlmGroupAuthenticationScheme(String name, String description, String domainControllerAddress, String domain, String file1, UserCreator userCreator1, String file2, UserCreator userCreator2) {
        this.name = name;
        this.description = description;
        this.domainControllerAddress = domainControllerAddress;
        this.domain = domain;
		this.file1 = file1;
		this.userCreator1 = userCreator1;
		this.file2 = file2;
        this.userCreator2 = userCreator2;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public boolean check(Credentials credentials) throws AuthenticationException {
		if ( check1(credentials) ) {
			return true;
		}
		if ( check2(credentials) ) {
			return true;
		}			
		return false;
    }

    public boolean check1(Credentials credentials) throws AuthenticationException {
        UniAddress mydomaincontroller;
        try {
            mydomaincontroller = UniAddress.getByName(domainControllerAddress);
        } catch (UnknownHostException e) {
            throw new AuthenticationException("Error authenticating using NTLM.", e);
        }
        NtlmPasswordAuthentication mycreds = new NtlmPasswordAuthentication(domain, credentials.getLogin(), credentials.getPassword());		
		jcifs.Config.registerSmbURLHandler();
		SmbFile smbf;
		try {
			smbf = new SmbFile(file1, mycreds);

		}	catch( MalformedURLException seed ) {
            // NETWORK PROBLEMS?
            throw new AuthenticationException("Can't find the file specified", seed);
        }

        try {			
            return smbf.exists();	
        } catch( SmbAuthException sae ) {
            // AUTHENTICATION FAILURE
            return false;
        } catch( SmbException se ) {
            // NETWORK PROBLEMS?
            throw new AuthenticationException("Error authenticating using NTLM.", se);
        }
    }

    public boolean check2(Credentials credentials) throws AuthenticationException {
        UniAddress mydomaincontroller;
        try {
            mydomaincontroller = UniAddress.getByName(domainControllerAddress);
        } catch (UnknownHostException e) {
            throw new AuthenticationException("Error authenticating using NTLM.", e);
        }
        NtlmPasswordAuthentication mycreds = new NtlmPasswordAuthentication(domain, credentials.getLogin(), credentials.getPassword());
		
		jcifs.Config.registerSmbURLHandler();
		
		SmbFile smbf;
		
		try {
			smbf = new SmbFile(file2, mycreds);
		}	catch( MalformedURLException seed ) {
            // NETWORK PROBLEMS?
            throw new AuthenticationException("Can't find the file specified", seed);
        }

        try {
									
			return smbf.exists();
			
        } catch( SmbAuthException sae ) {
            // AUTHENTICATION FAILURE
            return false;
        } catch( SmbException se ) {
            // NETWORK PROBLEMS?
            throw new AuthenticationException("Error authenticating using NTLM.", se);
        }
    }

    public void clearCaches() {
        // do nothing
    }

    public User createUser(Credentials crendentials, UserManager userManager) throws AuthenticationException {
        if (userCreator1 != null) {
		if (check1(crendentials)) {
				User aUser = userCreator1.create(crendentials.getLogin(), userManager);
				return aUser;				
			}
        }
		if (userCreator2 != null) {
			if (check2(crendentials)) {
				User aUser = userCreator2.create(crendentials.getLogin(), userManager);
				return aUser;					
			}
        }
        return null;
    }
}

&lt;/pre&gt;


&lt;p&gt;The jcifs library which daisy uses to perform NTLM authentication does not
provide a simple method for checking if a user belongs to a certain windows
group. However, by using the SmbFile() method for the jcifs library we can see
if a user with a siven set of creidentials can access a file on a windows share.
As a windows server can restrict access using groups this provides a cunning
workaround.&lt;/p&gt;


&lt;p&gt;The location of the file and other parameters are read from a the
configuration file myconfig.xml, which we will create later on. This information
is used inside the constructor of a new instance of our SSHAuthenticationScheme,
which we created above.&lt;/p&gt;


&lt;p&gt;You'll notice this section of code contains a number of fairly similar
methods [i.e. check1() and check2()]. The methods which Daisy itself uses&amp;nbsp; [i.e.
check() and createUser()] calls these in order to perform the authentication at
the two different levels .&lt;/p&gt;


&lt;p class="note"&gt;I'm sure there a more elegent way of doing this....&lt;/p&gt;


&lt;h2&gt;Step 4: Building the authentication scheme&lt;/h2&gt;


&lt;h3&gt;Step 4a: Compiling and packing your classes&lt;/h3&gt;


&lt;p&gt;I compile the files on my mac something like this:&lt;/p&gt;


&lt;p class="note"&gt;Use the method of your choice to compile the code (Ant, Maven,
your IDE, ...). When using the command below, we hope you know enough about this
that everything should be on one line. For Windows, replace $DAISY_HOME with
%DAISY_HOME% and the colons with semicolons)&lt;/p&gt;


&lt;pre&gt;javac -classpath 
   ~/Documents/intranet/daisy-2.2/lib/daisy/jars/daisy-repository-api-2.2.jar:
   ~/Documents/intranet/daisy-2.2/lib/daisy/jars/daisy-repository-server-spi-2.2.jar:
   ~/Documents/intranet/daisy-2.2/lib/daisy/jars/daisy-pluginregistry-api-2.2.jar:
   ~/Documents/intranet/daisy-2.2/lib/daisy/jars/daisy-pluginregistry-api-2.2.jar:
   ~/Documents/intranet/daisy-2.2/lib/avalon-framework/jars/avalon-framework-api-4.3.jar:
   ~/Documents/intranet/daisy-2.2/lib/jcifs/jars/jcifs-1.1.11.jar:
   ~/Documents/intranet/daisy-2.2/lib/javax.annotation/jars/jsr250-api-1.0.jar:
   ~/Documents/intranet/daisy-2.2/lib/javax.servlet/jars/servlet-api-2.4.jar:
   ~/Documents/intranet/ntlm-group-auth/src/org/outerj/daisy/authentication/impl/NtlmGroupAuthenticationScheme.class 
   ~/Documents/intranet/ntlm-group-auth/src/org/outerj/daisy/authentication/impl/NtlmGroupAuthenticationFactory.java 
   ~/Documents/intranet/ntlm-group-auth/src/org/outerj/daisy/authentication/impl/NtlmGroupAuthenticationScheme.java

jar cvf ntlm-group-auth.jar *&lt;/pre&gt;


&lt;p&gt;I run this command from the directory shown below:&lt;/p&gt;


&lt;pre&gt;~/Documents/intranet/ntlm-group-auth/src/&lt;/pre&gt;


&lt;h3&gt;Step 4b: Copying the jar-file into place&lt;/h3&gt;


&lt;p&gt;Copy the newly created jar file both into the lib directory of your daisy
binary distribution ($DAISY_HOME/lib). Copy the file
daisy-auth-ssh-&amp;lt;version&amp;gt;.jar into the directory daisy/jars/.&lt;/p&gt;


&lt;pre&gt;$ cp target/daisy-auth-ssh-&amp;lt;version&amp;gt;.jar $DAISY_HOME/lib/daisy/jars/&lt;/pre&gt;


&lt;p class="note"&gt;If you don't want to create a binary distribution of daisy it
might be sufficient to copy the jar-file to the $DAISY_HOME/lib directory only.
&lt;/p&gt;


&lt;p class="warn"&gt;Details from this point on are a little sketchy, need to check
the info on a different PC.&lt;/p&gt;


&lt;h2&gt;Step 5: Registering and configuring the new component&lt;/h2&gt;


&lt;h3&gt;Step 5a: Registering the new component&lt;/h3&gt;


&lt;p&gt;Edit the file $DAISY_HOME/repository-server/conf/block.xml. Inside the
container named authentication, include your newly created scheme. The element
&amp;lt;container&amp;gt; of block.xml now should look like (adapt the versions of your
jar files for ntlm and ssh authentication!):&lt;/p&gt;


&lt;pre&gt;&amp;lt;container name="authentication"&amp;gt;
  &amp;lt;services&amp;gt;
    &amp;lt;service type="org.outerj.daisy.authentication.UserAuthenticator"&amp;gt;
      &amp;lt;source&amp;gt;authenticator&amp;lt;/source&amp;gt;
    &amp;lt;/service&amp;gt;
    &amp;lt;service type="org.outerj.daisy.authentication.AuthenticationSchemeRegistrar"&amp;gt;
      &amp;lt;source&amp;gt;authenticator&amp;lt;/source&amp;gt;
    &amp;lt;/service&amp;gt;
  &amp;lt;/services&amp;gt;

  &amp;lt;component name="authenticator" class="org.outerj.daisy.authentication.impl.UserAuthenticatorImpl"/&amp;gt;

  &amp;lt;component name="daisy-native" class="org.outerj.daisy.authentication.impl.DaisyAuthenticationFactory"&amp;gt;
    &amp;lt;configuration&amp;gt;
      &amp;lt;cache enabled="true" maxCacheSize="3000" maxCacheDuration="1800000"/&amp;gt;
    &amp;lt;/configuration&amp;gt;
  &amp;lt;/component&amp;gt;

  &amp;lt;component name="ldap" class="org.outerj.daisy.authentication.impl.LdapAuthenticationFactory"&amp;gt;
    &amp;lt;configuration&amp;gt;
      &amp;lt;!-- See myconfig.xml.template for an example configuration --&amp;gt;
    &amp;lt;/configuration&amp;gt;
  &amp;lt;/component&amp;gt;

  &amp;lt;include name="ntlm" id="daisy:daisy-auth-ntlm" version="1.4-dev"/&amp;gt;
  &amp;lt;include name="ssh" id="daisy:daisy-auth-ssh" version="1.4-dev"/&amp;gt;
  &amp;lt;include name="ntlm-group" id="daisy:daisy-auth-ssh" version="1.4-dev"/&amp;gt;

&amp;lt;/container&amp;gt;&lt;/pre&gt;


&lt;h3&gt;Step 5b: Configuring the new component&lt;/h3&gt;


&lt;p&gt;Inside the directory $DAISY_HOME/repository-server/conf/ you will find a file
myconfig.xml.template. Copy this file into the directory conf/ inside your
repository and rename it to myconfig.xml&lt;/p&gt;


&lt;pre&gt;$ cp $DAISY_HOME/repository-server/conf/myconfig.xml.template /path/to/your/repository/conf/myconfig.xml&lt;/pre&gt;


&lt;p&gt;Edit the newly created file myconfig.xml. Add a target in order to configure
your authentication scheme, inside that target, fill in the IP or host name of
your SSH-server. Also, in order to enable automatically creation of user
accounts once the user logs in to daisy for the first time, define our newly
created scheme as authentification scheme for user creation as shown below:&lt;/p&gt;


&lt;pre&gt;&amp;lt;targets&amp;gt;
  &amp;lt;target path="..."
    ...
  &amp;lt;/target&amp;gt;

  ... many more targets

  &amp;lt;target path="/daisy/repository/authentication/authenticator"&amp;gt;
    &amp;lt;configuration&amp;gt;
      &amp;lt;!-- Indicates which authentication scheme to use, if any, to automatically create new users. --&amp;gt;
      &amp;lt;authenticationSchemeForUserCreation&amp;gt;ntlmgroup1&amp;lt;/authenticationSchemeForUserCreation&amp;gt;
    &amp;lt;/configuration&amp;gt;
  &amp;lt;/target&amp;gt;

  ... many more targets

  &amp;lt;target path="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"&amp;gt;
    &amp;lt;configuration&amp;gt;
       &amp;lt;!-- You can configure one or more NTLM-based authentication schemes here --&amp;gt;
          &amp;lt;!-- Notes:
                - the name of a scheme should not be daisy, no two schemes can have the same name
                - the autoCreateUser element is optional
          --&amp;gt;
          &amp;lt;scheme name="ntlmgroup1" description="Test NTLM Group config"&amp;gt;
            &amp;lt;domainControllerAddress&amp;gt;127.0.0.1&amp;lt;/domainControllerAddress&amp;gt;
            &amp;lt;domain&amp;gt;yum&amp;lt;/domain&amp;gt;
            &amp;lt;cache enabled="true" maxCacheSize="3000" maxCacheDuration="1800000"/&amp;gt;
			&amp;lt;fileLocation1&amp;gt;afilelocation&amp;lt;/fileLocation1&amp;gt;
			&amp;lt;fileLocation2&amp;gt;afilelocation&amp;lt;/fileLocation2&amp;gt;
			&amp;lt;subUserCreator1&amp;gt;
			   &amp;lt;autoCreateUser&amp;gt;
				  &amp;lt;roles&amp;gt;
					&amp;lt;role&amp;gt;User&amp;lt;/role&amp;gt;
				  &amp;lt;/roles&amp;gt;
				  &amp;lt;defaultRole&amp;gt;User&amp;lt;/defaultRole&amp;gt;
				  &amp;lt;updateableByUser&amp;gt;true&amp;lt;/updateableByUser&amp;gt;
				&amp;lt;/autoCreateUser&amp;gt;
				&amp;lt;test&amp;gt;astring&amp;lt;/test&amp;gt;
                         &amp;lt;/subUserCreator1&amp;gt;
			 &amp;lt;subUserCreator2&amp;gt;
			   &amp;lt;autoCreateUser&amp;gt;
				  &amp;lt;roles&amp;gt;
					&amp;lt;role&amp;gt;User&amp;lt;/role&amp;gt;
				  &amp;lt;/roles&amp;gt;
				  &amp;lt;defaultRole&amp;gt;User&amp;lt;/defaultRole&amp;gt;
				  &amp;lt;updateableByUser&amp;gt;true&amp;lt;/updateableByUser&amp;gt;
				&amp;lt;/autoCreateUser&amp;gt;
                         &amp;lt;/subUserCreator2&amp;gt;
	&amp;lt;/scheme&amp;gt;
    &amp;lt;/configuration&amp;gt;
  &amp;lt;/target&amp;gt;
&amp;lt;/targets&amp;gt;&lt;/pre&gt;


&lt;h2&gt;Step 6: Running and testing the new scheme&lt;/h2&gt;


&lt;p&gt;Now we are ready to test our new scheme! Restart the repository server and
the daisy wiki.&lt;br&gt;
Try to log on to daisy with any username/password combination which should have
permissions to access one of the files at either FileLocation1 or FileLocation2.
&lt;/p&gt;


&lt;p&gt;Log in should be successfull, you should be logged on with the role defined
in the myconfig.xml configuration file. Login as an administrator, invoke the
user administration. In the user list, an account should exist with the username
you just logged on as. Also, if you create a new user or edit an existing user,
in the drop-down box for the authentication scheme, you now should have the
choice between the daisy built in scheme and the scheme we newly created.&lt;/p&gt;


&lt;p&gt;It's worth noting a couple of points:&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;if a user can access both files at FileLocation1 and FileLocation2 they
don't get both sets of roles&lt;/li&gt;

&lt;li&gt;the roles associated with FileLocation1 and subUserCreator1 are checked
before&amp;nbsp; FileLocation2 and subUserCreator1&lt;/li&gt;

&lt;/ul&gt;


&lt;p&gt;Best of luck getting it to work. A working example is provided
&lt;a title="ntlm-group-auth" href="/wiki/621-cd/version/default/part/AttachmentData/data/ntlm-group-auth.jar"&gt;here&lt;/a&gt; (application/octet-stream, 11.4 kB, &lt;a href="/wiki/621-cd.html"&gt;info&lt;/a&gt;).&lt;/p&gt;


&lt;p class="warn"&gt;Java's not my strong point; I'd never coded in it before tying
this. I'm sure that there's a better way of structuring this code, possibly
involving passing arrays of FileLocations and subUserCreators from the
authentication factory to the authentication scheme. &lt;em&gt;Please leave some
hints. :)&lt;/em&gt;
&lt;/p&gt;


&lt;div class="doclinks"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="mailto:t_mcdonald@meng.ucl.ac.uk"&gt;Author: Tim McDonald&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</description></item><item xmlns:s="http://outerx.org/daisywiki/1.0#serializer"><title>New document browser</title><link>http://new.cocoondev.org/wiki/614-cd</link><description>&lt;html&gt;
&lt;head&gt;
&lt;META http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
&lt;base href="http://new.cocoondev.org"&gt;
&lt;link href="/resources/skins/default/css/daisy.css" type="text/css" rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 xmlns:d="http://outerx.org/daisy/1.0" xmlns:lt="http://outerx.org/daisy/1.0#linktransformer" xmlns:einclude="http://outerx.org/daisy/1.0#externalinclude" xmlns:p="http://outerx.org/daisy/1.0#publisher" xmlns:i18n="http://apache.org/cocoon/i18n/2.1" xmlns:urlencoder="xalan://java.net.URLEncoder" id="dsy614-cd" class="daisy-document-name"&gt;New document browser&lt;/h1&gt;


&lt;h2 xmlns:jx="http://apache.org/cocoon/templates/jx/1.0" xmlns:ns="http://outerx.org/daisy/1.0"&gt;Concept&lt;/h2&gt;


&lt;p&gt;A rewrite(?) of the existing document browser with some new features:&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;chunking&lt;/li&gt;

&lt;li&gt;sorting&lt;/li&gt;

&lt;li&gt;more search possiblities:&lt;/li&gt;

&lt;ul&gt;

&lt;li&gt;facet browsing&lt;/li&gt;

&lt;li&gt;predefined filters&lt;/li&gt;

&lt;/ul&gt;


&lt;li&gt;lookup of related WFs and possible transitions in the various tasks (?)&lt;/li&gt;

&lt;li&gt;multi-document-selection (useful for making multi-value daisy-link field
editors friendlier)&lt;/li&gt;

&lt;li&gt;pdf export&lt;/li&gt;

&lt;ul&gt;

&lt;li&gt;some standard listing of the current resultset to pdf&lt;/li&gt;

&lt;li&gt;bonus for having a pluggable xsl-fo of some sort (pulling in logos and stuff
&lt;/li&gt;

&lt;/ul&gt;


&lt;li&gt;extra actions:&lt;/li&gt;

&lt;ul&gt;

&lt;li&gt;in the search-result list, there could be buttons to various actions.&amp;nbsp; These
could be general actions (like "show", "edit", "start workflow"...) or
user-defined actions (i.e.
/daisy/site/ext/some-custom-action?documentId={docId})&lt;/li&gt;

&lt;/ul&gt;


&lt;/ul&gt;


&lt;p&gt;There are several places where the document browser could be used, with
different configuration requirements (e.g. when linking to a document,
multi-selection would not make sense).&amp;nbsp; Hence, there would be an xml document
that configures the document browser instance, a query parameter can then be
used&lt;br&gt;
to select the right configuration:&lt;br&gt;
http://.../daisy/site/documentBrowser?config=images&lt;br&gt;
would match ${wikidata}/conf/documentbrowser-{config}.xml&lt;/p&gt;


&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;docbrowser&amp;gt;
  &amp;lt;aspects&amp;gt;
    &amp;lt;daisy-meta/&amp;gt;
    &amp;lt;fulltext/&amp;gt;
    &amp;lt;facets&amp;gt;
      &amp;lt;!-- ... configuration for facets --&amp;gt;
    &amp;lt;predefined&amp;gt;
      &amp;lt;predef label="predef.withnavpart"&amp;gt;hasPart("NavigationData")&amp;lt;/predef&amp;gt;
      &amp;lt;predef label="predef.summercollection"&amp;gt;InCollection("summer")&amp;lt;/predef&amp;gt;
      ...
    &amp;lt;/predefined&amp;gt;
  &amp;lt;/aspects&amp;gt;

  &amp;lt;results multiselect="true"&amp;gt;
    &amp;lt;columns&amp;gt;
      &amp;lt;column label="docbrowser.id" select="id"/&amp;gt;
      &amp;lt;column label="docbrowser.name" select="name"/&amp;gt;
      &amp;lt;column label="docbrowser.lastModifierLogin" select="lastModifierLogin"/&amp;gt;
      &amp;lt;column label="docbrowser.lastModified" select="lastModified"/&amp;gt;
      &amp;lt;column label="docbrowser.pubYear" select="Year(Publication)"/&amp;gt;
      &amp;lt;column label="docbrowser.somethingelse" select="Random()"/&amp;gt;
      &amp;lt;column label="docbrowser.aMultiValueField" select="$Gimmicks"/&amp;gt;
      &amp;lt;!-- NTH: this may be a good place to say something about date formatting as well --&amp;gt;
    &amp;lt;/columns&amp;gt;
    &amp;lt;row-actions&amp;gt;
      &amp;lt;builtin-action label="showPreview" type="showPreview"/&amp;gt;
      &amp;lt;custom-action label="startWorkflow" url="{pageContext.mountPoint}/{site}/workflow/new?documentId={row.id}" icon="{pageContext.mountPoitn}/resources/skins/{skin}/img/wf.png"/&amp;gt;
      &amp;lt;custom-action label="mailTo" url="mailto:user@example.com?subject=Daisy Document: {row.name}&amp;amp;body=Click here for to for an interesting document: {pageContext.baseurl}/{pageContext.mountPoint}/{site}/workflow/new?documentId={row.id}" icon="{pageContext...}/email.png"/&amp;gt;
      &amp;lt;custom-action label="showReferrers" url="{pageContext.mountPoint}/{site}/{row.id}/referrers.html" icon="{...}/refer.png"/&amp;gt;
    &amp;lt;/row-actions&amp;gt;
    &amp;lt;actions&amp;gt;
      &amp;lt;custom-action label="exportPdf" url=".../exportPdf?ids={comma_separated_ids}"/&amp;gt;  &amp;lt;!-- Probably needs to support POST-links to be practical, plus ways to control what is sent. --&amp;gt;
    &amp;lt;/actions&amp;gt;
  &amp;lt;/results&amp;gt;
&amp;lt;/docbrowser&amp;gt;&lt;/pre&gt;


&lt;h2&gt;Layout ideas&lt;/h2&gt;


&lt;p&gt;Like the current document browser, the document browser would have two
distinct halves: The "search" part and the "search-result" part.&lt;br&gt;
The "search" part would show different search aspects: fulltext, daisy-metadata,
facets and predefined filters.&lt;br&gt;
To save space, these would be rendered in tabs or an accordeon widget.&lt;/p&gt;


&lt;p&gt;The "search-result" part would become table-like (like the querySearch
results), but there should be a possibility of toggling between "table" mode and
"preview mode" (preview-mode being the style used in the current document
browser).&lt;/p&gt;


&lt;h2&gt;Mockups&lt;/h2&gt;


&lt;p&gt;These are the 'search' aspects as they would appear in an accordeon widget
(all aspects are shown in collapsed mode and in expanded mode)&lt;/p&gt;


&lt;p&gt;
&lt;img alt="docbrowser search aspects" title="docbrowser search aspects" src="/wiki/618-cd/version/default/part/ImageData/data/search-aspects.png"&gt;&lt;/p&gt;


&lt;p&gt;This is what the whole document browser would look like:&lt;/p&gt;


&lt;p&gt;
&lt;table class="plainTable"&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a style="border: 1px" href="/wiki/619-cd/version/default/part/ImageData/data/docbrowser-mockup.png"&gt;&lt;img alt="docbrowser-mockup" title="docbrowser-mockup" src="/wiki/619-cd/version/default/part/ImagePreview/data"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;a style="font-style: italic" href="/wiki/619-cd/version/default/part/ImageData/data/docbrowser-mockup.png"&gt;Click to enlarge&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;


&lt;h3&gt;Additional requirements (not visible in current mockups):&lt;/h3&gt;


&lt;ul&gt;

&lt;li&gt;A button to toggle between "preview" and "table" mode.&lt;/li&gt;

&lt;li&gt;Chunking links&lt;/li&gt;

&lt;li&gt;A button to toggle between "results" and "current selection" (the current
selection of documents must be available even if not all documents are in the
current resultset.&lt;/li&gt;

&lt;/ul&gt;


&lt;/body&gt;
&lt;/html&gt;
</description></item></channel></rss>