Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
Core Repository ServicesSecurityAuthentication
Security is supported by five key services:
The authentication service provides an API to:
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.
See Enterprise Security and Authentication Configuration.
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:
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 is responsible for:
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' .....>
....
....
<property name='adminUsers'>
<set>
<value>admin</value>
<value>administrator</value>
</set>
</property>
</bean>
To include andy as an admin user and remove the alfresco admin user you would change the config to
....
<property name='adminUsers'>
<set>
<value>administrator</value>
<value>andy</value>
</set>
</property>
....
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:
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 is responsible for:
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 is the API by which nodes of the person type, as defined in contentModel.xml, should be accessed.
The person service is responsible for:
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.
How do I end up with duplicate person objects?
Duplicate person entries can now be handled in a number of ways.
This can be configured on the person service in authentication-services-context.xml.
TODO: include the existance of preferences and personal configuration in selecting the best person against which to match for duplicate users.
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'>
<property name='nodeService'>
<ref bean='nodeService' />
</property>
<property name='policyComponent'>
<ref bean='policyComponent' />
</property>
<property name='defaultProvider'>
<ref bean='myHomeFolderProvider' />
</property>
</bean>
The person service knows nothing of home folder creation and providers.
(This behaviour is bound to a create policy for the cmerson 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 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'>
<property name='serviceRegistry'>
<ref bean='ServiceRegistry' />
</property>
<property name='path'>
<value>/${spaces.company_home.childname}</value>
</property>
<property name='storeUrl'>
<value>${spaces.store}</value>
</property>
<property name='homeFolderManager'>
<ref bean='homeFolderManager' />
</property>
</bean>
<bean name='guestHomeFolderProvider' class='org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider'>
<property name='serviceRegistry'>
<ref bean='ServiceRegistry' />
</property>
<property name='path'>
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
</property>
<property name='storeUrl'>
<value>${spaces.store}</value>
</property>
<property name='homeFolderManager'>
<ref bean='homeFolderManager' />
</property>
<property name='userPemissions'>
<set>
<value>Consumer</value>
</set>
</property>
</bean>
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.
Properties:
<bean name='exampleHomeFolderProvider' class='org.alfresco.repo.security.person.UIDBasedHomeFolderProvider'>
<property name='serviceRegistry'>
<ref bean='ServiceRegistry' />
</property>
<property name='path'>
<value>/${spaces.company_home.childname}</value>
</property>
<property name='storeUrl'>
<value>${spaces.store}</value>
</property>
<property name='homeFolderManager'>
<ref bean='homeFolderManager' />
</property>
<property name='ownerOnCreate'>
<value>admin</value>
</property>
<property name='inheritsPermissionsOnCreate'>
<value>false</value>
</property>
<property name='ownerPemissionsToSetOnCreate'>
<set>
<value>Coordinator</value>
<value>All</value>
</set>
</property>
<property name='permissionsToSetOnCreate'>
<map>
<entry key='GROUP_A'>
<set>
<value>Consumer</value>
</set>
</entry>
<entry key='GROUP_B'>
<set>
<value>Editor</value>
<value>Collaborator</value>
</set>
</entry>
</map>
</property>
<property name='userPemissions'>
<set>
<value>All</value>
</set>
</property>
<property name='templatePath'>
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
</property>
<property name='clearExistingPermissionsOnCreate'>
<value>true</value>
</property>
</bean>
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).
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
...
<property name='attributeDefaults'>
<map>
<entry key='cm:homeFolderProvider'>
<value>companyHomeFolderProvider</value>
</entry>
</map>
</property>
...