cancel
Showing results for 
Search instead for 
Did you mean: 

LDAP Individuals user home folders

fbertos
Champ in-the-making
Champ in-the-making
Hi,

Using LDAP authentication in Alfresco all new users are created with /app:company_home user home folder.

I've changed PersonServiceImpl class for using individual folders named like the user.

The code is:

package es.intecna.alfresco.repo.security.person;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.PermissionServiceSPI;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.NoSuchPersonException;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.alfresco.repo.security.person.*;

/**
   Updated by Fernando Bertos Matilla (Intecna Soluciones Software Engineer) 9/6/2006
*/

public class PersonServiceImpl implements PersonService
{
    public static final String SYSTEM_FOLDER = "/sys:system";
    public static final String PEOPLE_FOLDER = SYSTEM_FOLDER + "/sysSmiley Tongueeople";
    // IOC
    private StoreRef storeRef;
    private NodeService nodeService;
    private SearchService searchService;
    private AuthorityService authorityService;
    private PermissionServiceSPI permissionServiceSPI;
    private NamespacePrefixResolver namespacePrefixResolver;
    private boolean createMissingPeople;
    private boolean userNamesAreCaseSensitive;
    private String companyHomePath;
    private NodeRef companyHomeNodeRef;
    private String usersHomePath;
    private NodeRef usersHomeNodeRef;   
    private static Set<QName> mutableProperties;

    static
    {
        Set<QName> props = new HashSet<QName>();
        props.add(ContentModel.PROP_HOMEFOLDER);
        props.add(ContentModel.PROP_FIRSTNAME);
        // Middle Name
        props.add(ContentModel.PROP_LASTNAME);
        props.add(ContentModel.PROP_EMAIL);
        props.add(ContentModel.PROP_ORGID);
        mutableProperties = Collections.unmodifiableSet(props);
    }

    public PersonServiceImpl()
    {
        super();
    }

    public boolean getUserNamesAreCaseSensitive()
    {
        return userNamesAreCaseSensitive;
    }

    public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
    {
        this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
    }

    public NodeRef getPerson(String caseSensitiveUserName)
    {
        String userName = userNamesAreCaseSensitive ? caseSensitiveUserName : caseSensitiveUserName.toLowerCase();
        NodeRef personNode = getPersonOrNull(userName);

        if (personNode == null)
        {
            if (createMissingPeople())
            {
                return createMissingPerson(userName);
            }
            else
            {
                throw new NoSuchPersonException(userName);
            }
        }
        else
        {
            return personNode;
        }
    }

    public boolean personExists(String caseSensitiveUserName)
    {
        return getPersonOrNull(caseSensitiveUserName) != null;
    }

    public NodeRef getPersonOrNull(String caseSensitiveUserName)
    {
        String userName = userNamesAreCaseSensitive ? caseSensitiveUserName : caseSensitiveUserName.toLowerCase();
        SearchParameters sp = new SearchParameters();
        sp.setLanguage(SearchService.LANGUAGE_LUCENE);
        sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" + userName + "\"");
        sp.addStore(storeRef);
        sp.excludeDataInTheCurrentTransaction(false);
        ResultSet rs = null;

        try
        {
            rs = searchService.query(sp);

            for (ResultSetRow row : rs)
            {
                NodeRef nodeRef = row.getNodeRef();

                if (nodeService.exists(nodeRef))
                {
                    String realUserName = DefaultTypeConverter.INSTANCE.convert(
                            String.class,
                            nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME));
                    realUserName = userNamesAreCaseSensitive ? realUserName : realUserName.toLowerCase();

                    if (realUserName.equals(userName))
                    {
                        return nodeRef;
                    }
                }
            }
        }
        finally
        {
            if (rs != null)
            {
                rs.close();
            }
        }

        return null;
    }

    public boolean createMissingPeople()
    {
        return createMissingPeople;
    }

    public Set<QName> getMutableProperties()
    {
        return mutableProperties;
    }

    public void setPersonProperties(String caseSensitiveUserName, Map<QName, Serializable> properties)
    {
        String userName = userNamesAreCaseSensitive ? caseSensitiveUserName : caseSensitiveUserName.toLowerCase();
        NodeRef personNode = getPersonOrNull(userName);

        if (personNode == null)
        {
            if (createMissingPeople())
            {
                personNode = createMissingPerson(userName);
            }
            else
            {
                throw new PersonException("No person found for user name " + userName);
            }
        }

        properties.put(ContentModel.PROP_USERNAME, userName);
        nodeService.setProperties(personNode, properties);
    }

    public boolean isMutable()
    {
        return true;
    }

    private NodeRef createMissingPerson(String userName)
    {
        HashMap<QName, Serializable> properties = getDefaultProperties(userName);
        return createPerson(properties);
    }

    private NodeRef createHomeFolder(String userName)
    {
       NodeRef parentRef = this.getUsersHome();
        Map<QName, Serializable> nodeProperties = new HashMap<QName, Serializable>(7);
        nodeProperties.put(ContentModel.PROP_NAME, userName);
        ChildAssociationRef assocRef = nodeService.createNode(parentRef,
                ContentModel.ASSOC_CONTAINS,
                ContentModel.TYPE_FOLDER,
                ContentModel.TYPE_FOLDER,
                nodeProperties);
        return assocRef.getChildRef();
    }

    private HashMap<QName, Serializable> getDefaultProperties(String userName)
    {
       NodeRef homeFolder = createHomeFolder(userName);
        HashMap<QName, Serializable> properties = new HashMap<QName, Serializable>();
        properties.put(ContentModel.PROP_USERNAME, userName);
        properties.put(ContentModel.PROP_HOMEFOLDER, homeFolder);
        properties.put(ContentModel.PROP_FIRSTNAME, userName);
        properties.put(ContentModel.PROP_LASTNAME, "");
        properties.put(ContentModel.PROP_EMAIL, "");
        properties.put(ContentModel.PROP_ORGID, "");
        return properties;
    }

    public NodeRef createPerson(Map<QName, Serializable> properties)
    {
        String caseSensitiveUserName = DefaultTypeConverter.INSTANCE.convert(String.class, properties
                .get(ContentModel.PROP_USERNAME));
        String userName = userNamesAreCaseSensitive ? caseSensitiveUserName : caseSensitiveUserName.toLowerCase();
        properties.put(ContentModel.PROP_USERNAME, userName);
        return nodeService.createNode(
                getPeopleContainer(),
                ContentModel.ASSOC_CHILDREN,
                ContentModel.TYPE_PERSON,
                ContentModel.TYPE_PERSON,
                properties).getChildRef();
    }

    public NodeRef getPeopleContainer()
    {
        NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
        List<NodeRef> results = searchService.selectNodes(
                rootNodeRef,
                PEOPLE_FOLDER,
                null,
                namespacePrefixResolver,
                false);

        if (results.size() == 0)
        {
            throw new AlfrescoRuntimeException("Required people system path not found: " + PEOPLE_FOLDER);
        }
        else
        {
            return results.get(0);
        }
    }

    public void deletePerson(String userName)
    {
        NodeRef personNodeRef = getPersonOrNull(userName);

        // delete the person
        if (personNodeRef != null)
        {
            nodeService.deleteNode(personNodeRef);
        }

        // translate username based on user name case sensitivity
        String authorityName = userNamesAreCaseSensitive ? userName : userName.toLowerCase();

        // remove user from any containing authorities
        Set<String> containerAuthorities = authorityService.getContainingAuthorities(null, userName, true);

        for (String containerAuthority : containerAuthorities)
        {
            authorityService.removeAuthority(containerAuthority, authorityName);
        }

        // remove any user permissions
        permissionServiceSPI.deletePermissions(authorityName);
    }

    public Set<NodeRef> getAllPeople()
    {
        SearchParameters sp = new SearchParameters();
        sp.setLanguage(SearchService.LANGUAGE_LUCENE);
        sp.setQuery("TYPE:\"" + ContentModel.TYPE_PERSON + "\"");
        sp.addStore(storeRef);
        sp.excludeDataInTheCurrentTransaction(false);
        LinkedHashSet<NodeRef> nodes = new LinkedHashSet<NodeRef>();
        ResultSet rs = null;

        try
        {
            rs = searchService.query(sp);

            for (ResultSetRow row : rs)
            {
                NodeRef nodeRef = row.getNodeRef();

                if (nodeService.exists(nodeRef))
                {
                    nodes.add(nodeRef);
                }
            }
        }
        finally
        {
            if (rs != null)
            {
                rs.close();
            }
        }

        return nodes;
    }

    public void setCreateMissingPeople(boolean createMissingPeople)
    {
        this.createMissingPeople = createMissingPeople;
    }

    public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
    {
        this.namespacePrefixResolver = namespacePrefixResolver;
    }

    public void setAuthorityService(AuthorityService authorityService)
    {
        this.authorityService = authorityService;
    }

    public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI)
    {
        this.permissionServiceSPI = permissionServiceSPI;
    }

    public void setNodeService(NodeService nodeService)
    {
        this.nodeService = nodeService;
    }

    public void setSearchService(SearchService searchService)
    {
        this.searchService = searchService;
    }

    public void setStoreUrl(String storeUrl)
    {
        this.storeRef = new StoreRef(storeUrl);
    }

    public void setCompanyHomePath(String companyHomePath)
    {
        this.companyHomePath = companyHomePath;
    }

    public void setUsersHomePath(String usersHomePath)
    {
        this.usersHomePath = usersHomePath;
    }

    public synchronized NodeRef getCompanyHome()
    {
        if (companyHomeNodeRef == null)
        {
            List<NodeRef> refs = searchService.selectNodes(nodeService.getRootNode(storeRef), companyHomePath, null,
                    namespacePrefixResolver, false);

            if (refs.size() != 1)
            {
                throw new IllegalStateException("Invalid company home path: found : " + refs.size());
            }

            companyHomeNodeRef = refs.get(0);
        }

        return companyHomeNodeRef;
    }

    private synchronized NodeRef getUsersHome()
    {
        if (usersHomeNodeRef == null)
        {
            List<NodeRef> refs = searchService.selectNodes(nodeService.getRootNode(storeRef), usersHomePath, null,
                    namespacePrefixResolver, false);

            if (refs.size() != 1)
            {
                throw new IllegalStateException("Invalid users home path: found : " + refs.size());
            }

            usersHomeNodeRef = refs.get(0);
        }

        return usersHomeNodeRef;
    }
    // IOC Setters
}

We need modify the authentication-services-context.xml file for configuring the parent users home folder:

    <bean id="personService" class="es.intecna.alfresco.repo.security.person.PersonServiceImpl">
      <property name="nodeService">
          <ref bean="nodeService" />
      </property>
      <property name="searchService">
          <ref bean="searchService" />
      </property>
      <property name="permissionServiceSPI">
         <ref bean="permissionServiceImpl" />
      </property>
                <property name="authorityService">
                        <ref bean="authorityService" />
                </property>
      <property name="namespacePrefixResolver">
         <ref bean="namespaceService" />
      </property>
        <!– Configurable properties.                                 –>
        <!–                                                          –>
        <!– TODO:                                                    –>
        <!– Add support for creating real home spaces adn setting    –>
        <!– permissions on the hame space and people created.        –>
        <!–                                                          –>
        <!– The store in which people are persisted.                 –>
        <property name="storeUrl">
           <value>${spaces.store}</value>
        </property>
        <!– The path to the company home space, used to set the      –>
        <!– default home space for users that are created if         –>
        <!– missing.                                                 –>
        <property name="companyHomePath">
           <value>/${spaces.company_home.childname}</value>
        </property>
       
        <property name="usersHomePath">
           <value>/${spaces.company_home.childname}/cm:Usuarios</value>
        </property>
        <!– Some authentication mechanisms may need to create people –>
        <!– in the repository on demand. This enables that feature.  –>
        <!– If dsiabled an error will be generated for missing       –>
        <!– people. If enabled then a person will be created and     –>
        <!– persisted.                                               –>
        <!–                                                          –>
        <!– This value should be false or only true if the           –>
        <!– repository is mutable; set from the property             –>
        <!– ${server.transaction.allow-writes}                       –>
        <property name="createMissingPeople">
           <value>${server.transaction.allow-writes}</value>
        </property>
        <!– Set is user names are case sensitive - taken from the    –>
        <!– repository wide setting - you are advised not to change  –>
        <!– this setting.                                            –>
        <!– This value should be ${user.name.caseSensitive}          –>
        <property name="userNamesAreCaseSensitive">
           <value>${user.name.caseSensitive}</value>
        </property>
    </bean>

    <!– The ticket component.                                              –>
    <!– Used for reauthentication                                          –>
    <bean id="ticketComponent" class="org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl">
        <!– The period for which tickets are valid in XML duration format. –>
        <!– The default is P1H for one hour.                               –>
        <property name="validDuration">
            <value>P1H</value>
        </property>
        <!– Do tickets expire or live for ever?                            –>
        <property name="ticketsExpire">
            <value>false</value>
        </property>
        <!– Are tickets only valid for a single use?                       –>
        <property name="oneOff">
            <value>false</value>
        </property>
    </bean>
</beans>

Cheers!!

fbertos
3 REPLIES 3

csiege
Champ in-the-making
Champ in-the-making
I was unable to get this to work.  What version of Alfresco are you running?  As I have traced the process, it appears the when the LDAP sync runs, the xml import file is created.  That import file, creates the users without using the Person class.

I am using 1.3.  Please let me know if you were able to get this working on 1.3.

thanks!

Chris

csiege
Champ in-the-making
Champ in-the-making
ok, I see what you are doing now… not syncing the users, just authenticating with LDAP… when the user logs in the first time and their profile is created, you create the home directory…

I would prefer to sync and have the directory created at that time, will see if I can get that to work.

thanks.

Chris

andy
Champ on-the-rise
Champ on-the-rise
Hi

Creation of home folders is now pluggable during LDAP import and on demand creation of poeple.

See
http://wiki.alfresco.com/wiki/Security_and_Authentication#Creating_home_spaces_-_from_1.4_onwards

Regards

Andy