The official documentation is at: http://docs.alfresco.com
Table of Contents
- 1 Services
- 1.1 The Authentication Service
- 1.2 The Authority Service
- 1.3 The Ownable Service
- 1.4 The Permission Service
- 1.5 The Person Service
- 1.6 Handling duplicate person entries for the same uid - from 2.0 onwards
- 1.7 Creating home spaces - from 1.4 onwards
- 1.1 The Authentication Service
Security is supported by five key services:
- the Authentication Service;
- the Authority Service;
- the Ownable Service;
- the Permission Service; and
- the Person Service.
The Authentication Service
The authentication service provides an API to:
- authenticate using a user name and password;
- authenticate using a ticket;
- create, update and delete authentication information;
- clear the current authentication;
- invalidate a ticket;
- get the username for who is currently authenticated;
- get a ticket for subsequent re-authentication; and
- determine if the current user is 'the system user'.
Not all implementations will support creating, updating and deleting authentication information.
The authenticated username is used as they key to obtain other security information such as group membership,
the details about the person, to record a user as the owner of an object.
It is one of the identifiers against which permissions may be assigned.
The authentication service does not provide any details about a user other than authentication.
The authentication service stores authentication information on the calling thread.
Application developers should ensure that this information is cleared.
The implementation and configuration for this service can be found in authentication-services-context.xml.
The product ships with a default authentication implementation. This default implementation coordinates two service providers for the AuthenticationComponent and MutableAuthenticationDAO. It also uses the permission service provider interface to clear up permissions as users are deleted. Tickets are supported using the ticket component.
The only configuration option that should be changed is if user names are case sensitive. This is set in repository.properties.
Note that in the authentication service implementation, the MD4 hash algorithm is used to encode passwords.
This is to allow the open source authentication service to support authentication using NTLM while using the CIFS protocol.
See Configuring NTLM to configure NTLM authentication and single sign on using NTLM.
As well as requiring changes to the authentication service configuration, authentication filters in the client have to be changed to match.
Any of the Acegi authentication mechanisms may be used. Alfresco expects a vanilla Acegi Authentication object in the Acegi context. This allows third parties to use classes extending UserDetails without any issue, and implement the services described in this guide on top of an existing Acegi security implementation.
Alfresco ships with a DAO provider implementation to plug into the Acegi DAO provider, this supports authentication using information held in the repository. There is a provider to authenticate credentials that have programmatically been set as authenticated. The authentication service uses this provider to set the current user (without Acegi attempting to authenticate against the DAO). An NTLM authentication implementation is also available.
Alfresco does not add roles and groups etc to the objects held in the Acegi context. This information is encapsulated through the AuthorityService. If you use acegi already, you could implement an authority service that retrieves group and role information from the Acegi authentication object.
LDAP, JAAS, Kerberos
The ChainingAuthenticationServiceImpl can be used to link together any combination of other authentication services.
It takes a list of authenticationServices and an optional mutableAuthenticationService.
If the mutableAuthenticationService is set then users can be managed in this authentication service.
They can be created, deleted, password updated etc. No attempt is made to modify the other services.
All other operations are tried against each authentication service in the order they are defined.
If a mutableAuthenticationService is present it will be treated as first in the list.
Authentication will be tried against each service in turn. If all fail authentication will fail. If one authentication is allowed authentication will be granted. It does not matter if previous services contain the same user with different passwords. This will change when domains are fully supported. It is not advisable for users with the same id to exist in more than one authentication service that are linked together. If this is done - authentication can be done against any - the first definition will define the properties such as 'enabled'.
This implementation could be used for:
- External LDAP users and internal users held in alfresco
- Several LDAP repositories
- One LDAP repository with users to be found in different locations on the server.
See projects\repository\config\alfresco\extension\chaining-authentication-context.xml.sample for an example of JAAS and Alfresco authentication services combined.
In the configuration, take care to give unique bean names where required in the definitions of each authentication service stack.
The Authority Service
The authority service is responsible for:
- creating authority identifiers;
- querying for authority identifiers;
- deleting authority identifiers;
- structuring authority identifiers into hierarchies;
- supporting queries against authority identifiers hierarchies;
- finding all the authorties that apply to the current authenticated user; and
- determining if the current authenticated user has admin rights.
It does not support users, authentication and user management. This is for the AuthenticationService.
The authority service is defined and configured in authority-services-context.xml.
This file includes documentation on how to configure specific implementations of this service.
You can provide your own implementation of this service by implementing the
org.alfresco.service.cmr.security.AuthorityService interface. The implementation should be a spring bean identified by the id authorityService. This will then get wrapped with the appropriate transactional and security behaviour and exposed as a service bean called AuthorityService.
In both cases, the admin users can be changed by altering the admin users property, on the authorityService bean defined in authority-services-context.xml. In the standard Alfresco Tomcat installation, this file is located in the directory /usr/local/alfresco/tomcat/webapps/alfresco/WEB-INF/classes/alfresco.
<bean id='authorityService' .....>
To include andy as an admin user and remove the alfresco admin user you would change the config to
The Ownable Service
The idea of file ownership is present in both unix and windows. The repository has the concept of node ownership. This is optional and is implemented as an aspect. The owner of a node may have specific ACLs granted to them. Owner is a dynamic authority. If the Ownable aspect is not present, the creator is used as the default owner. The owner is simply defined using the user name. If the username of the current user matches the user name of the node owner then the current user will be granted all permissions assigned to the owner authority.
The ownable service is responsible for:
- determining the owner of a node;
- setting the owner of a node;
- determining if a node has an owner; and
- allowing the current user to take ownership of a node.
The Ownable Service is supported by an ownable aspect defined in contentMode.xml.
There are a set of well known permissions associated with the Ownable Service.
The beans and configuration for the ownership service are defined in ownable-services-context.xml. There are no configuration options for this service.
The Permission Service
The permission service is responsible for:
- providing well known permissions and authorities;
- providing an API to read, set and delete permissions for a node;
- providing an API to query, enable and disable permission inheritance for a node; and
- determine if the current, authenticated user has a permission for a node.
The PermissionService interface defines constants for well known permissions and authorities.
The default implementation coordinates implementations of two service provider interfaces; a ModelDAO and a PermissionsDAO. A permission is just a name scoped by the fully qualified name of the type or aspect to which it applies. The beans are defined and configured in public-services-security-context.xml. This file also contains the configuration for security enforcement.
The ModelDAO interface defines an API to access a permissions model. This model defines low level permissions, groups of permissions, and groups of permissions that extend existing groups of permissions. Each permission or grouping of permissions applies only in the context of a type or aspect, or to all types. Permission requirements may then be set in service beans to protect method invocations. For example, a method may only be called by authenticated users that have been granted particular permissions on one of the nodes identified by a parameter for the method. The model also supports static or global permissions. Global permissions apply to all objects in the repository and take precedence over permissions assigned to individual nodes. For example, the assignment of all permissions to the admin user for all nodes in the repository. The permission model is separate from the data dictionary; fully qualified type names provide the key to link the two together.
The PermissionsDAO interface defines an API to persist permissions set against specific nodes and to determine if the current user has a specified permission for a given node. This takes into account both global and node level permissions and all the authorities that apply to the current user.
In the default PermissionsDAO implementation, a permission or permission group is granted or denied to an authority for a particular node. There can be any number of these entries for a given node. Permissions will be inherited by any children unless the permission is denied by an ACL on a child or inheritance of ACLs is disabled on a child. An ACL can deny or allow. Allow takes precedence. If 'bob' is a member of the group 'rats' and 'bob' is allowed 'read' and 'rats' is denied 'read' then 'bob' will be allowed read. Any allow allows access, as opposed to Microsoft file systems, wherein a single deny denies all.
Permissions are assigned at the node level, not at the attribute level. Ths makes sense with the current implementation of search.
Search results need to reflect what the user performing the search can see. It makes sense that all properties have the same read access as the node, as nodes are indexed for searching. Applying read ACLs at the property level would require a change to the indexing implementation or a complex post analysis to work out how nodes were found by the search.
If not, The values of properties could be deduced by how a readable node was found from a search on restricted properties.
Fine grain attribute permissions could be implemented by using children nodes to partition meta-data if required.
If we need to support attribute level permissions in the future, the best compromise would be to index as we are now but only allow different read access for properties that are not indexed - so their content can not be determined via query. Alternatively, only index properties etc. that have the same access permissions as the node. In both cases the content can not be determined from the index. We could have additional indexing support to search against restricted properties.
What is a role? You could define groups and roles, against which you could assign permissions and permission groups, by convention, starting with 'ROLE_' for roles and 'GROUP_' for groups. The AuthorityService is responsible for providing the additional authorities, over and above user name, that apply to a particular user. This service can be extended or replaced if you want to add additional roles/groups to users. We do not use roles in this way, as there is not much distinction between a role and a group.
A role is more like a set of permissions that are granted to a particular authority for all nodes. Or if it is context sensitive, a set of permissions granted to a particular authority for a given node and maybe its children. Both of these are supported by the implementation
The available permissions are defined in the permissions model. This is defined in the permissionDefinitions.xml file in the repository/config/aflresco/model directory. This configuration is loaded in a bean definition in the public-services-security-context.xml file. This file also defines global permissions. The definition file is read once at application start up. If you make changes to this file you will have to restart the repository to apply the changes.
Here is the v1.0 permission model definition as an example PermissionModelDefintionExample
The Person Service
The person service is the API by which nodes of the person type, as defined in contentModel.xml, should be accessed.
The person service is responsible for:
- obtaining a reference to the Person node for a given user name;
- determining if a person entry exists for a user;
- potentially creating missing people entries, with default settings, on demand;
- supplying a list of mutable properties for each person;
- creating, deleting and altering personal information.
The beans to support the person service and its configuration can be found in authentication-services-context.xml. The principle configuration options are around how people are created on demand if users are managed via NTLM or some other external user repository.
If you are using an external user repository it is likely that you will have to implement your own person service using the org.alfresco.service.cmr.security.PersonService interface. If not, you will want people to be created in the repository on demand so they do not have to exist before a user logs in.
Handling duplicate person entries for the same uid - from 2.0 onwards
How do I end up with duplicate person objects?
- A configuration error in the LDAP import - each import creates a new person - the query to find the existing person does not match the person you expect. Thus usually means the uid attriute is not correct or consistent over configurations. There is a task to simplify the config and make this less likely.
- Before the first LDAP import completes a person is created automatically as the user logs in. The LDAP import will not see the auto created person - a duplicate will be present after the import completes. One way to avoid this is to turn off the auto creation of people.
- There are simultaneous logins for the same person which auto create the person details.
Duplicate person entries can now be handled in a number of ways.
- Find the best match, use it; leave all entries as they are
- Find the best match and fix the other uids to be unique by appending a guid
- Find the best match and delete all others
This can be configured on the person service in authentication-services-context.xml.
Person service properties to split users
- - true(default) - handles duplicates
- - false - throws an error
- - true(default) - prefer the most most recently created or updated person entry
- - false - the reverse
- used to detemine the best match
- - false(default) - do not include auto created entries when searching for the best match
- - true - they are included
- used to detemine the best match
- one of DELETE, SPLIT, LEAVE
- How to deal with duplicates
- - leave them as they are but just use the best one found - the duplication will remain
- - leave the best one and use it, split the rest by appending a GUID - the duplication will be removed but the person entries remain
- - leave the best one and use it, all others are deleted - the duplication will be removed and so will the duplicate person objects.
TODO: include the existance of preferences and personal configuration in selecting the best person against which to match for duplicate users.
Creating home spaces - from 1.4 onwards
Home space creation can be done when people are created from v1.4 onwards. See
When a person is created a call is made to a home space provider as specified by the property cm:homeFolderProvider. This names a home space provider to use on a per person basis. If the property is not specified then a default home space provider is used.
A home space provider may also use the cm:defaultHomeFolderPath property.
Prior to 1.4 any person created on demand or via LDAP import would be assigned the Company Home space as their home space. This meant it was awkward to set up home spaces. This behaviour was tied to the default PersonService implementation. Home space creation or assignment is now pluggable. The change removes the companyHomePath property from the default PersonServiceImpl, and it adds the defaultHomeFolderProvider property which is set for each person created on demand, if this is allowed.
To change the default home folder provider, you can override the homeFolderManager bean to change the defaultProvider property. See below for examples and also authentication-services-context.xml.
<bean name='homeFolderManager' class='org.alfresco.repo.security.person.HomeFolderManager'>
<ref bean='nodeService' />
<ref bean='policyComponent' />
<ref bean='myHomeFolderProvider' />
The person service knows nothing of home folder creation and providers.
(This behaviour is bound to a create policy for the cm:person type using a bean exposing the HomeFolderManager class.)
HomeFolderManager defines the default home folder provider.
The base class used to implement the providers below allows permissions to be set. There are two sets of permissions: those set when home spaces are created and those set when a home space is assigned (it already existed).
Common properties for all providers:
- The bean name is the name of the home space provider. Set cm:homeSpaceProvider on cm:person to this value to select the use of a particular provider.
- Inject the home folder manager.
- A store ref (used for search context etc - to look up path)
- Inject the service registry.
- A path to a folder. This is required in some form by all providers. They may use this path in different ways.
- The name of the owner to set on creation. If not specified then the person will own their home space. So you could set this to 'admin' if you do not want folk to own their home spaces.
- If a home space is created, set if permissions are inherited. The default is false.
- A set of permissions to set for the owner when a home space is created.
- A Map of Sets of permissions to for specified users when a home space is created
- The permissions to set for the user/person when a homespace is created or an existing one reused.
- Specifically to support clearing permissions when a home folder is created from a template. If true then permissions are cleared, if false they will be taken from the template.
Defining a home space that is an existing space (ExistingPathBasedHomeFolderProvider)
- The path to folder to assign as the home space.
The default in 1.3 and before was to use company home.
This can be implemented using the provider below.
<bean name='companyHomeFolderProvider' class='org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider'>
<ref bean='ServiceRegistry' />
<ref bean='homeFolderManager' />
<bean name='guestHomeFolderProvider' class='org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider'>
<ref bean='ServiceRegistry' />
<ref bean='homeFolderManager' />
Creating a home space based on uid
Below is an example configuration for creating a home folder based on the uid of a user.
As the uid is unique it can be used to name a home folder.
- An optional path to a template node used to create home spaces.
- The folder in which to create home spaces.
<bean name='exampleHomeFolderProvider' class='org.alfresco.repo.security.person.UIDBasedHomeFolderProvider'>
<ref bean='ServiceRegistry' />
<ref bean='homeFolderManager' />
Also refer to authentication-services-context.xml for examples of 'userHomesHomeFolderProvider' (the current default provider, which creates home folders under User Homes) and 'personalHomeFolderProvider' (which creates home folders under Company Home).
Defining a home space during bootstrap
The BootstrapHomeFolderProvider class is present to support specifying home folders.
You will probably not have to use this.
The LDAP import can specify a default home folder provider name, or it could be set per person imported by setting the cm:homeFolderProvider property from an attribute stored in LDAP.
To set the default provider for imported LDAP users that do not specify a specific home folder provider