Chapter 6. Authentication and Security

WHAT'S IN THIS CHAPTER?

  • Configuring authentication

  • Working with users, groups, and zones

  • Configuring security

  • Implementing permissions

  • Implementing the ACEGI Spring security framework and services

This chapter discusses the authentication and security functionality built into Alfresco for user and group management, user authentication, permissions, and access control. In addition, this chapter provides instructions on how you can customize Alfresco for your own user base and needs using configurable modules for LDAP, NTLM, Kerberos, and other commonly used authentication protocols.

ALFRESCO AUTHENTICATION

The first time you access a vanilla Alfresco installation through the Alfresco Explorer Web client, Alfresco identifies you as a guest user. You can identify yourself as another user by clicking the Login link and entering a new user name and password in the Login window. If you log in with the credentials of a user with administrator privileges (Alfresco uses admin as the default user name and password), you can use the Administration Console to create additional users and assign them passwords.

In this out-of-the-box setup, you can manage the user base and their passwords manually from within Alfresco, and unauthenticated users still have limited access as the guest user.

From here, there are a number of common customizations you might want to make to scale up to the needs of a larger enterprise. For example, you might want to:

  • Disable unauthenticated guest access

  • Enable automatic sign-on using operating system credentials or a single sign-on (SSO) server to remove the need for a Login page

  • Delegate authentication responsibility to a central directory server to remove the need to set up users manually in the Administration Console

You will learn how to achieve these different levels of customization in various examples presented later in this chapter. To more fully understand the examples, you will first look at an overview of the Alfresco authentication subsystems.

Authentication Subsystems

The Alfresco authentication and identity management functionality is provided by a set of configurable software modules called subsystems. An authentication subsystem provides the following functions to Alfresco:

  • Password-based authentication for Web browsing, Microsoft SharePoint protocol, FTP, and WebDAV

  • CIFS and NFS file system authentication

  • Web browser, Microsoft SharePoint protocol, and WebDAV single sign-on (SSO)

  • User registry export (the automatic population of the Alfresco user and authority database)

Authentication Subsystem Types

A number of alternative authentication subsystem types exist for the most commonly used authentication protocols. These are each identified by a unique type name and summarized in Table 6-1.

Table 6.1. Authentication Subsystem Types

TYPE

DESCRIPTION

SINGLE SIGN-ON (SSO)

CIFS AUTHENTICATION

USER REGISTRY EXPORT?

alfrescoNtlm

Native Alfresco authentication

Yes, NTLM

Yes

No

ldap

Authentication and user registry export through the LDAP protocol (for example, OpenLDAP)

No

No

Yes

ldap-ad

Authentication and user registry export from Active Directory through the LDAP protocol

No

No

Yes

passthru

Authentication through a Windows domain server

Yes, NTLM

Yes

No

kerberos

Authentication through a Kerberos realm

Yes, SPNEGO

Yes

No

external

Authentication through an external SSO mechanism

Yes

No

No

The following sections show how these subsystem types enable you to tie Alfresco to some of the most widely used authentication infrastructures.

The Authentication Chain

It is very likely that at least one of the authentication subsystem types previously discussed will allow you to integrate Alfresco with one of the authentication servers in use in your enterprise. However, integrating Alfresco with just one of these systems may not be enough. For various reasons, you might want to mix and match multiple authentication protocols against a collection of servers.

That is why Alfresco has a built-in authentication chain. In simple terms, this is a priority-ordered list of authentication subsystem instances. A subsystem instance is a configuration of one of the subsystem types. Each subsystem instance has:

  • A type

  • A unique name that makes it distinguishable from other instances of the same type

  • A set of property values provided by user configuration

The following sections demonstrate the authentication chain in use.

Authentication Configuration Examples

The examples in this section demonstrate how to express various authentication configuration requirements in subsystem instances in the authentication chain. They also explain how the authentication chain integrates the functions of multiple subsystem instances into a more powerful conglomerate, letting you cater for even the most complex authentication scenarios. All the examples adopt the following structured approach:

  1. Decide the authentication chain composition (required subsystem types, instance names, order of precedence) and express this in alfresco-global.properties.

  2. For each subsystem instance:

    1. Locate the properties files for its subsystem type. These define the configurable properties for that subsystem type and their default values.

    2. Create a folder named after the subsystem instance under the alfresco extension folders.

    3. Copy the properties files into your new folder.

    4. Edit the properties files to record the desired configuration of the subsystem instance.

Example 1: Customizing alfrescoNtlm

An authentication chain containing a single subsystem instance of type alfrescoNtlm provides the Alfresco default authentication behavior. This means that Alfresco performs all user account management and password validation. As implied by the type name, alfrescoNtlm subsystem instances support automatic sign-on to internal Alfresco accounts through the NTLM protocol. But you do not have to use NTLM at all; in fact, it is turned off by default.

This example shows how to achieve two of the basic customizations using an instance of alfrescoNtlm:

  • Disabling unauthenticated guest access

  • Enabling automatic sign-on

Authentication Chain Composition

The first task is to declare your customized authentication chain to Alfresco. To do so, you must edit the configuration file alfresco-global.properties. In a default Alfresco installation, this is located in the following path:

<installLocation>sharedclassesalfresco-global.properties

You are still only relying on the internal capabilities of Alfresco, so you only need one alfrescoNtlm subsystem instance in your authentication chain. In this case, the subsystem instance name is alfinst. The name you choose does not really matter, as long as it is meaningful to you and unique within the authentication chain.

In alfresco-global.properties, add the following line:

authentication.chain=alfinst:alfrescoNtlm

Here you can see that the authentication.chain property declares the authentication chain to Alfresco. Its value is a comma-separated list of authentication chain instances. Each instance is declared by an instance name, followed by a colon, and then followed by the subsystem type.

Configuring the Instance

Now you will create the property files to configure your subsystem instance. First, you must create an appropriately named directory in the Alfresco extension location.

mkdir <installLocation>sharedclassesalfrescoextensionsubsystems
AuthenticationalfrescoNtlmalfinst

cd /d <installLocation>sharedclassesalfrescoextensionsubsystems
AuthenticationalfrescoNtlmalfinst

Note

Like other Alfresco configurations, the subsystem instance configuration lives in a directory below alfresco/extension in the application server's classpath. Below this path, subsystem configuration is further organized by category, type, and instance name. A subsystem category is a broad categorization given to a set of subsystem types. All authentication subsystem types have the category Authentication. To be precise, the configuration for a particular subsystem instance of category sc, type st, and name sn should be under a path alfresco/extension/subsystems/sc/st/sn.

Now you will source the properties files that define the configurable properties of your instance.

copy <installLocation>webappsalfrescoWEB-INFclassesalfrescosubsystems
AuthenticationalfrescoNtlm*.properties

As you can see, the default properties for a subsystem of category sc, type st, and name sn are under alfresco/subsystems/sc/st/*.properties in the Alfresco WAR file.

Warning

Never edit the properties files in the WAR file or under the Tomcat webapps directory. Always create your own copies in the extension classpath as shown in this example. Otherwise, any customizations you make would be lost whenever you upgraded Alfresco.

Two separate properties files appear in your alfinst directory after running one of the previous commands. These are:

  • alfresco-authentication.properties

  • ntlm-filter.properties

This demonstrates how the properties of a subsystem may be spread across multiple properties files. The number of files and their names do not matter, as long as they end with the suffix .properties. For the alfrescoNtlm subsystem type, alfresco-authentication.properties contains properties relating to core authentication capabilities, whereas ntlm-filter.properties groups together those relating to automatic sign-on.

Now you are set to configure your alfinst authentication subsystem instance.

To disable unauthenticated guest access, open the alfresco-authentication.properties file from the alfinst directory in a text editor and locate the following line:

alfresco.authentication.allowGuestLogin=true

Edit this line to disable guest access; for example:

alfresco.authentication.allowGuestLogin=false

To activate NTLM-based single sign-on (SSO), open the ntlm-filter.properties file from the alfinst directory in a text editor, and locate the following line:

ntlm.authentication.sso.enabled=false

Edit this line to enable SSO; for example:

ntlm.authentication.sso.enabled=true

Putting It in Action

Start or restart the Alfresco server. If you enter the Alfresco Explorer URL http://localhost:8080/alfresco/ in your browser, you should find that the guest home page does not appear, as this has been disabled. Instead, a browser authentication window appears. Although you enabled NTLM-based sign-on, this happens because your browser cannot log you in automatically as there is not yet an account in Alfresco whose credentials match your operating system credentials.

To remedy this, log in as the admin user (using admin as the user name and password). Use the Administration Console link at the top of the home page, and create a user with a user name and password that matches those of your operating system account. Close and restart your browser and try accessing Alfresco again. If your browser supports NTLM and its security settings allow, it will automatically log you in using your operating system account name.

This rather simplistic demonstration of SSO still involved the manual creation of users in Alfresco and the duplication of password information in two systems. To achieve truly enterprise-grade authentication, you will have to use some of the different subsystem types, as demonstrated in Example 2.

Example 2: The ldap-ad Subsystem

This example addresses the more advanced goal of delegating authentication responsibility to a centralized directory server. Most organizations maintain their user database in a directory server supporting the LDAP protocol, such as Active Directory or OpenLDAP. When integrated with an LDAP server, Alfresco can delegate both the password checking and account setup to the LDAP server, thus opening up Alfresco to your entire enterprise. This avoids the need for an administrator to manually set up user accounts or to store passwords outside of the directory server.

To integrate Alfresco with a directory server, you simply need to include an instance of the ldap or ldap-ad subsystem types in the authentication chain. Both subsystem types offer exactly the same capabilities and should work with virtually any directory server supporting the LDAP protocol. Their only differences are the default values configured for their attributes. The ldap type is preconfigured with defaults appropriate for OpenLDAP, whereas ldap-ad is preconfigured with defaults appropriate for Active Directory.

This example uses an Active Directory server and therefore will configure in an instance of the ldap-ad subsystem.

Authentication Chain Composition

You have two choices in this scenario. You can replace or add to the authentication chain.

  • Replace the authentication chain.

    You could remove alfinst from the previous example and instead add an instance of ldap-ad. This would hand over all authentication responsibility to Active Directory and would mean that the built-in accounts, such as admin and guest, could not be used.

    In this scenario, it would be important to configure at least one user who exists in Active Directory as an administrator and enable the guest account in Active Directory if guest access were required. Furthermore, because ldap-ad cannot support CIFS authentication (as it requires an MD5 password hash exchange), it would rule out use of the CIFS server for all users and the CIFS server would be disabled.

  • Add to the authentication chain.

    You could instead supplement the existing capabilities of alfinst by inserting an ldap-ad instance before or after alfinst in the chain. This means that you could use the built-in accounts alongside those accounts in the directory server. Furthermore, the built-in accounts could access Alfresco through the CIFS server, since alfrescoNtlm is able to drive CIFS authentication.

    In this scenario, where you chose to position your ldap-ad instance in the chain determines how overlaps or collisions between user accounts are resolved. If an admin account existed in both Alfresco and Active Directory, then admin would be Alfresco if alfinst came first, or Active Directory if the ldap-ad instance came first.

This example uses the second option to append an instance of ldap-ad to the authentication chain. This instance name is ldap1 and is declared by changing the authentication.chain property in alfresco-global.properties as follows:

authentication.chain=alfinst:alfrescoNtlm,ldap1:ldap-ad

Configuring the Instances

First, you will undo a previous modification to alfinst and disable NTLM-based SSO. This is done because the ldap-ad and ldap subsystem types cannot participate in the NTLM handshake; therefore, leaving SSO enabled would prevent any of the Active Directory users from logging in. You will see how to get around this in the next example.

For now, disable SSO by opening the ntlm-filter.properties file in the alfinst directory in a text editor, and editing the property ntlm.authentication.sso.enabled as follows:

ntlm.authentication.sso.enabled=false

Next, create the properties files to configure ldap1:

mkdir <installLocation>sharedclassesalfrescoextensionsubsystems
Authenticationldap-adldap1

cd /d <installLocation>sharedclassesalfrescoextensionsubsystems
Authenticationldap-adldap1

copy <installLocation>webappsalfrescoWEB-INFclassesalfrescosubsystems
Authenticationldap-ad*.properties

A single file called ldap-ad-authentication.properties now appears in your ldap1 directory. You can now edit this file to define your LDAP setup.

When you open ldap-ad-authentication.properties, the large number of configurable properties may alarm you. This demonstrates the flexibility of the Alfresco LDAP infrastructure. Luckily, because ldap-ad already has sensible defaults configured for a typical Active Directory setup, there are only a few edits you must make to tailor the subsystem instance to your needs.

The following lines show the set of properties you will typically need to edit and how you might set them for a domain controller for a fictitious domain called domain.com.

ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=%[email protected]
ldap.authentication.java.naming.provider.url=ldap://domaincontroller.domain.com:389

ldap.authentication.defaultAdministratorUserNames=Administrator,alfresco
ldap.synchronization.java.naming.security.principal=alfresco@domain.com
ldap.synchronization.java.naming.security.credentials=secret
ldap.synchronization.groupSearchBase=ou=Security Groups,ou=Alfresco
,dc=domain,dc=com

ldap.synchronization.userSearchBase=ou=User Accounts,ou=Alfresco,dc=domain,dc=com

Here is a brief description of the settings that have been changed:

  • ldap.authentication.allowGuestLogin — Enables/disables unauthenticated access to Alfresco.

  • ldap.authentication.userNameFormat — A template that defines how Alfresco user IDs are expanded into Active Directory User Principal Names (UPNs) containing a placeholder %s, which stands for the unexpanded user ID. A UPN generally consists of the user's account ID followed by an @ sign and then the domain's UPN suffix. You can check the appropriate UPN suffix for your domain by connecting to the directory with an LDAP browser, browsing to a user account, and looking at the value of the userPrincipalName attribute.

  • ldap.authentication.java.naming.provider.url — An LDAP URL containing the host name and LDAP port number (usually 389) of your Active Directory server.

  • ldap.authentication.defaultAdministratorUserNames — A list of user IDs who should be given Alfresco administrator privileges by default. Another administrator can include more users as administrators by adding those users to the ALFRESCO_ADMINISTRATORS group.

  • ldap.synchronization.java.naming.security.principal — The UPN for an account with privileges to see all users and groups. This account is used by Alfresco to retrieve the details of all users and groups in the directory so that it can synchronize its internal user and authority database. Passwords are never compromised and remain in the directory server.

  • ldap.synchronization.java.naming.security.credentials — The password for the previous account.

  • ldap.synchronization.groupSearchBase — The Distinguished Name (DN) of the Organizational Unit (OU) below which security groups can be found. You can determine the appropriate DN by browsing to security groups in an LDAP browser.

  • ldap.synchronization.userSearchBase — The Distinguished name (DN) of the Organizational Unit (OU) below which user accounts can be found. You can determine the appropriate DN by browsing to user accounts in an LDAP browser.

Putting It in Action

Restart the Alfresco server. If you watch the output from Tomcat in alfresco.log in the installation directory, you will eventually see lines similar to the following:

13:01:31,225 INFO
[org.alfresco.repo.management.subsystems.ChildApplicationContextFactory]
Starting 'Synchronization' subsystem, ID: [Synchronization, default]


...

13:01:49,084 INFO
[org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer]
Finished synchronizing users and groups with user registry 'ldap1'
13:01:49,084 INFO
[org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer]
177 user(s) and 19 group(s) processed

13:01:49,131 INFO
[org.alfresco.repo.management.subsystems.ChildApplicationContextFactory]
Startup of 'Synchronization' subsystem, ID: [Synchronization, default] complete

What you are seeing is output is from the Synchronization subsystem. This is another Alfresco subsystem responsible for synchronizing the Alfresco internal user and authority database with all user registries in the authentication chain. Since the authentication chain now provides a user registry, the Synchronization subsystem has some work to do when Alfresco starts up.

From the previous logs, notice that the Synchronization subsystem automatically created 177 users and 19 groups using attributes, such as email address and group memberships, retrieved from Active Directory through an LDAP query. This has eliminated a lot of work for the admin user!

Note

The Synchronization subsystem uses an incremental timestamp-based synchronization strategy, meaning that it only queries for changes since the last synchronization run. So after the first startup, further synchronization runs can be almost instantaneous. Because synchronization runs are also triggered by a scheduled nightly job, whenever an unknown user successfully authenticates you should find that Alfresco stays synchronized with hardly any effort.

Now, if you enter the Alfresco Explorer URL http://localhost:8080/alfresco/into your browser, you can log in using the ID and password of any of the Active Directory users.

Note

Passwords are validated through an LDAP bind operation on Active Directory in real time. Passwords for Active Directory users are not stored locally.

If you navigate to a user profile, notice that attributes such as email address were populated automatically from Active Directory.

You are somewhat closer now to the ideal of delegating authentication responsibility to Active Directory, but you still do not have the automatic sign-on and CIFS browsing capabilities that internal Alfresco users enjoyed in the first example. Is there anything more you can do? The next example demonstrates this.

Example 3: The passthru Subsystem

In Example 2, you saw that the authentication capabilities offered by the ldap-ad subsystem type were not capable of supporting CIFS and NTLM authentication. Instead, you had to settle for form-based login for all users, and only Alfresco internal users could access CIFS. This is the compromise you would have to make if the directory server did not support any other authentication protocol. But for Active Directory, which also supports NTLM and Kerberos authentication, you can overcome this limitation by using either the passthru or the kerberos subsystem types.

As passthru is simpler to set up, this is the one used for this example. The passthru subsystem supports SSO, CIFS, and password authentication against a Windows domain server using the NTLM v1 protocol. Many prefer Kerberos for its enhanced security and you should certainly consider it as an alternative.

Authentication Chain Composition

Append an instance of passthru to the authentication chain for this example. Call the instance passthru1 and declare it by changing the authentication.chain property in alfresco-global.properties as follows:

authentication.chain=alfinst:alfrescoNtlm,ldap1:ldap-ad,passthru1:passthru

Configuring the Instances

First, ensure that CIFS authentication is no longer targeted at your internal alfrescoNtlm subsystem instance, alfinst.

Open the alfresco-authentication.properties file in the alfinst directory in a text editor, and edit the alfresco.authentication.authenticateCIFS property as follows:

alfresco.authentication.authenticateCIFS=false

Note

Functions such as NTLM SSO and CIFS authentication can only be targeted at a single subsystem instance in the authentication chain. This is a restriction imposed by the authentication protocols themselves. For this reason, Alfresco targets these "direct" authentication functions at the first member of the authentication chain that has them enabled. By disabling CIFS in alfinst earlier, passthru1 has a chance to handle CIFS authentication for its larger user base. SSO is also left disabled in alfinst, which means that you can enable it in passthru1.

Next, stop ldap1 from performing authentication. You can leave that to passthru1, which will be authenticating against the same server using more secure protocols. This leaves the ldap1 user registry export capabilities active, which you still rely on for account synchronization.

Edit the ldap.authentication.active property in the ldap-ad-authentication.properties file located in your ldap1 directory as follows:

ldap.authentication.active=false

Finally, create the properties files to configure passthru1.

mkdir <installLocation>sharedclassesalfrescoextensionsubsystems
Authenticationpassthrupassthru1
cd /d <installLocation>sharedclassesalfrescoextensionsubsystems
Authenticationpassthrupassthru1

copy <installLocation>webappsalfrescoWEB-INFclassesalfrescosubsystems
Authenticationpassthru*.properties

After running the previous commands, two separate properties files should appear in your passthru1 directory. These are:

  • passthru-authentication-context.properties

  • ntlm-filter.properties

Using a similar distinction to the alfrescoNtlm subsystem type, passthru-authentication-context.properties contains properties relating to core authentication capabilities, whereas ntlm-filter.properties groups those properties relating to automatic sign-on. Unlike the alfrescoNtlm subsystem type, SSO is enabled by default in passthru subsystems so there is no need to edit ntlm-filter.properties.

The following lines show the set of properties you typically need to edit and how they might be set for a domain controller for the fictitious domain domain.com.

passthru.authentication.servers=DOMAIN\domaincontroller.domain.com
,domaincontroller.com
passthru.authentication.domain=# Leave blank
passthru.authentication.guestAccess=false
passthru.authentication.defaultAdministratorUserNames=Administrator,alfresco

Here is a brief description of the settings that have changed:

  • passthru.authentication.servers — A comma-separated list of domain controller host names, each prefixed by the name of the domain they correspond to and a double backslash. The last member of the list is a host name without a domain prefix, and this host will be used when a client does not include a domain name in an authentication request.

  • passthru.authentication.domain — This property is a less-reliable alternative to passthru.authentication.servers and should be left empty.

  • passthru.authentication.defaultAdministratorUserNames — A list of user IDs who should be given Alfresco administrator privileges by default. Additional users can be made administrators by another administrator if they add those users to the ALFRESCO_ADMINISTRATORS group.

Putting It in Action

Restart the Alfresco server. The main differences to notice from last time are:

  • All Active Directory users can point their browser to the Alfresco server and be signed on automatically. In Internet Explorer, this requires adding the Alfresco server to the Local Intranet security zone.

  • All Active Directory users can access Alfresco as a CIFS file system using their Active Directory credentials.

These examples have demonstrated the flexibility and power of an Alfresco authentication chain. You can combine the strengths of a variety of different authentication protocols and keep the Alfresco user database synchronized almost transparently.

ALFRESCO SECURITY

Authentication is concerned with validating that a user or principal is who or what they claim to be. Alfresco normally refers to users. A user's credentials can take many forms and can be validated in a number ways (for example, a password validated against an LDAP directory, or a Kerberos ticket validated against a Microsoft Active Directory Server).

Alfresco includes an internal, password-based, authentication implementation; the support to integrate with many external authentication environments; the option to write your own authentication integration; and the ability to use several of these options simultaneously. Alfresco can integrate with LDAP, Microsoft Active Directory Server, the Java Authentication and Authorization Service (JAAS), Kerberos, and NTLM. A user ID can also be presented as an HTML attribute over HTTPS to integrate with Web-based single sign-on solutions.

Authorization determines what operations an authenticated user is allowed to perform. There are many authorization models. Popular ones include Role Based Access Control (RBAC), UNIX-style Access Control Lists (ACLs) and extended ACLs, Windows-style ACLs, and many more. Authorization requirements for the management of records are more detailed and include additional requirements (for example, enforcing access based on security clearance or record state).

Alfresco authorization is based on UNIX-extended ACLs. Each node in the repository has an ACL that is used to assign permissions to users and groups. Operations, such as creating a new node, describe what permissions are required to carry out the operation. ACLs are then used to determine if a given user may execute the operation based on the permissions that have been assigned directly to the user or indirectly through a group. An operation in Alfresco is invoking a method on a public service bean. For example, creating a user's home folder requires invoking methods on several public services; to create the folder, set permissions, disable permission inheritance, and so on. Each public service method invocation will check that the user is allowed to execute the method.

By convention, public service beans are the beans whose names start with capital letters, such as the NodeService. You configure the security requirements for public service beans in XML. A given method on a particular service may be available to all users, all users in a specified group, all users with a specified role, or users who have particular permissions on specified arguments to the method or its return value. In addition, for methods that return collections or arrays, their content may be filtered based on user permissions. If the authorization requirements for a method call are not met, the method call will fail and it will throw an AccessDeniedException. Non-public beans, such as nodeService, do not enforce security; use these only when the enforcement of authorization is not required.

Permission assignments are made in Access Control Lists (ACLs), which are lists of Access Control Entries (ACEs). An ACE associates an authority (group or user) with a permission or set of permissions, and defines whether the permission is denied or allowed for the authority. Every node has a related ACL. When you create a node, it automatically inherits an ACL from its parent. You can alter this behavior after node creation by breaking inheritance or modifying the ACL.

The XML configuration for permissions also defines a context-free ACL for ACEs that apply to all nodes. For example, you could use this to assign everyone Read access to all nodes regardless of what individual ACLs any node has set. (See the "Permissions" section in this chapter for more details on how to modify the permission model.)

<!-- Extension to alfrescomodelpermissionDefinitions.xml -->
<globalPermission permission="Read" authority="GROUP_EVERYONE" />

Code snippet GlobalRead.xml

A check that a user has Read permission for a node is done in two stages. First, the context-free ACL is checked to see if it allows access. If not, the ACL assigned or inherited by the node is checked. A user may be allowed to perform an operation because of permissions assigned to the context-free ACL, assigned to the node's ACL, inherited by the node from its parent, or a combination of all three.

AUTHORITIES

Authorities are people (or persons) or groups. A group may contain people or other groups as members. The authorities assigned to a user at any time are the userName from their associated Person node, all of the groups of which the user is a direct or indirect member, and any appropriate dynamic authorities. Dynamic authorities are used for internal roles.

People and Users

When logging in, Alfresco validates the user's identifier and password. Alfresco employs the user's identifier to look up the appropriate person details for the user, using the userName property on the Person type. You can configure this look-up to be case-sensitive or case-insensitive. The userName property on the matching Person node is used as the actual user authority; it may differ in case from the user identifier presented to the authentication system. After the Person node look-up, Alfresco is case-sensitive when matching authorities to permissions, group membership, roles, and for all other authorization tests.

Any user who authenticates by any mechanism must have an associated person node in Alfresco. Person nodes may be:

  • Explicitly created

  • Created on demand with some default entries

  • Created from LDAP synchronization

Person nodes are explicitly created when using the administration pages of the Alfresco Explorer and Alfresco Share Web clients to manage users.

By default, person nodes will be auto-created if not present. If an external authentication system is configured, such as NTLM, when any user authenticates, an appropriate person node may not exist. If a person node does not exist and auto-creation is enabled, a person node will then be created using the identifier exactly as presented by the user and validated by the authentication system. The auto-created Person node's userName will have the same case as typed by the user. LDAP synchronization will create person nodes with the userName as provided from the LDAP server.

It is possible that LDAP synchronization can change the userName associated with a Person node. For example, this can happen with a system that uses NTLM authentication and LDAP synchronization, creates person nodes on demand, and uses case-insensitive authentication. For example, Andy could log in as "Andy" and the associated Person node would be created with the userName "Andy." Later, the LDAP synchronization runs and changes the userName to "andy." From version 3.2, changes to Person node userNames will cause updates to other related data in Alfresco, such as ACL assignment.

Groups

Groups are collections of authorities with a name and display name. As such, groups may include other groups or people. You may include a group in one or more other groups, as long as this inclusion does not create any cyclic relationships.

Zones

All person and group nodes are in one or more zones. You can use zones for any partitioning of authorities. For example, Alfresco synchronization uses zones to record from which LDAP server users and groups have been synchronized. Zones have been used to hide some groups that provide Role Based Access Control (RBAC) role-like functionality from the administration pages of the Alfresco Explorer and Alfresco Share Web clients. Examples of hidden groups are the roles used in Alfresco Share and Records Management (RM). Only users and groups in the default zone are shown for normal group and user selection on the group administration pages. Zones cannot be managed from the administration pages of the Alfresco Explorer and Alfresco Share Web clients.

Zones are intended to have a tree structure defined by naming convention. Zones are grouped into two areas: Application-related zones and authentication-related zones.

Within a zone, a group is considered to be a root group if it is not contained by another group in the same zone.

Figure 6-1 shows the model used for persisting people, groups, and zones in Alfresco. Each person is represented by a Person node and groups are represented by an AuthorityContainer, which can be used for other authority groupings, such as roles. AuthorityContainer and Person are sub-classes of Authority and as such can be in any number of Zones.

Application-Related Zones

Application-related zones, other than the default, are used to hide groups that implement RBAC like roles. Application zones, by convention, start with APP. and include the following:

  • APP.DEFAULT is for person and group nodes to be found by a normal search. If no zone is specified for a person or group node they will be a member of this default zone.

  • APP.SHARE is for hidden authorities related to Alfresco Share.

  • APP.RM will be added for authorities related to RM.

FIGURE 6-1

Figure 6.1. FIGURE 6-1

Authentication-Related Zones

Zones are also used to record the primary source of person and group information. They may be held within Alfresco or some external source. While authorities can be in many zones, it makes sense for an authority to be in only one authentication-related zone.

  • AUTH.ALF is for authorities defined within Alfresco and not synchronized from an external source. This is the default zone for authentication.

  • AUTH.EXT.<ID> is for authorities defined externally, such as in LDAP.

Dynamic Authorities and Roles

Alfresco uses some custom roles. To implement a custom role, you create a dynamic authority for that role and assign global permissions to it. The Alfresco internal roles have not been assigned any object-specific rights. The internal roles are as follows:

  • ROLE_ADMINISTRATOR is assigned to the default administrators for the configured authentication mechanisms or members of the administration groups defined on the AuthorityServiceImpl bean. This role has all rights.

  • ROLE_OWNER is assigned to the owner of a node. If there is no explicit owner, this role is assigned to the creator. This role has all rights on the owned node.

  • ROLE_LOCK_OWNER is assigned to the owner of the lock on a locked node. This supports a lock owner's right to check in, cancel a checkout, or unlock the node.

The Alfresco Web clients support the assignment of permissions only to the owner role. You can use such things as the Java API and scripting to make other assignments.

Note

Hierarchical and zoned roles may be added to Alfresco in the future to avoid the hidden group implementation for true roles.

PERMISSIONS

Permissions and their groupings are defined in an XML configuration file. The default file is found in the distribution configuration directory as <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescomodelpermissionDefinitions.xml. This configuration can be replaced or extended and has a structure as described in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescomodelpermissionSchema.dtd.

The following example uses the permission definitions related to the Ownable aspect.

<!-- ============================================== -->
  <!-- Permissions associated with the Ownable aspect -->
  <!-- ============================================== -->

  <permissionSet type="cm:ownable" expose="selected">

    <!-- Permission control to allow ownership of node to be taken from others -->
    <permissionGroup name="TakeOwnership" requiresType="false" expose="false">
      <includePermissionGroup permissionGroup="SetOwner" type="cm:ownable" />
    </permissionGroup>

    <permissionGroup name="SetOwner" requiresType="false" expose="false"/>

    <!-- The low level permission to control setting the owner of a node -->
    <permission name="_SetOwner" expose="false" requiresType="false">
      <grantedToGroup permissionGroup="SetOwner" />
      <requiredPermission on="node" type="sys:base" name="_WriteProperties" />
    </permission>

  </permissionSet>

Code snippet OwnablePermissions.xml

As you can see in the preceding code, permissions and permission groups are defined in a permission set, which is a sub-element of the permissions root element. A permission set is associated with a type or aspect and applies only to that type and sub-types, or aspect and sub-aspects.

A permission has a name. By convention, the names of permissions start with an underscore character. They may be exposed in the administration pages of the Alfresco Explorer and Alfresco Share Web clients but, by convention, are not. A permission, in its definition, may be granted to any number of permission groups. This means that those permission groups will include the permission. The permission may require that the type or aspect specified on the permission set be present on the node. If a permission is associated with an aspect and the requiresType property is set to true, then if that aspect is not applied to a node, the permission does not apply to that node either. If an aspect-related permission definition has the requiresType property set to false, the permission applies to any node, even if the aspect has not been applied to the node.

An aspect can be applied at any time and there are no restrictions as to which aspects can be applied to a type. A permission may also require other permissions be tested on the same node, its children, or its parent. In the preceding example, _SetOwner requires _WriteProperties. This means you cannot set ownership on a node if you are not allowed to write to its properties. You can also use this to check that all children can be deleted before deleting a folder, or to enforce that you can read only the nodes for which you can read all the parents; neither are normally required in Alfresco. The configuration to do this is present in the standard configuration file but is commented out. The _DeleteNode permission definition (as shown in the following DeleteNode.xml code snippet) is an example. If permission A requires permission B and this requirement is implied (by setting the implies attribute of the requiredPermission element to true), assigning an authority permission A will also give them permission B (as opposed to checking they have permission B).

<permission name="_DeleteNode" expose="false" >
  <grantedToGroup permissionGroup="DeleteNode" />
  <!-- Commented out parent permission check ...
  <requiredPermission on="parent" name="_ReadChildren" implies="false"/>
  <requiredPermission on="parent" name="_DeleteChildren" implies="false"/>
  <requiredPermission on="node" name="_DeleteChildren" implies="false"/>
   -->
  <!-- Recursive delete check on children -->
  <!--  <requiredPermission on="children" name="_DeleteNode" implies="false"/>  -->
</permission>

Code snippet _DeleteNode.xml

Permissions are normally hidden inside permission groups. Permission groups are made up of permissions and other permission groups. By convention, each permission has a related permission group. Permission groups can then be combined to make other permission groups. As for permissions, a permission group may be exposed by the administration pages of the Alfresco Explorer and Alfresco Share Web clients and may require the presence of a type or aspect to apply to a particular node. In addition, a permission group may allow full control, which grants all permissions and permission groups. As a type or aspect may extend another, a permission group defined for a type or aspect can extend one defined for one of its parent types and be assigned more permissions, include more permission groups, or change what is exposed in the administration pages of the Alfresco Explorer and Alfresco Share Web clients.

It is unusual to extend or change the default permission model unless you are adding your own types, aspects, and related public services or you wish to make minor modifications to the existing behavior. The following code snippets show how to extend and replace the default permission model.

<bean id='permissionsModelDAO'
class="org.alfresco.repo.security.permissions.impl.model.PermissionModel">
        <property name="model">
<-- <value>alfresco/model/permissionDefinitions.xml</value> -->
<value>alfresco/extension/permissionDefinitions.xml</value>
        </property>
        <property name="nodeService">
            <ref bean="nodeService" />
        </property>
<property name="dictionaryService">
            <ref bean="dictionaryService" />
        </property>
</bean>

Code Snippet ReplacePermissionModel.xml

The preceding code example shows how to replace the default permission model with one located in the alfresco/extension directory. The following code snippet shows how to extend the existing model.

<bean id="extendPermissionModel" parent="permissionModelBootstrap">
  <property name="model" value="alfresco/extension/permissionModelExtension.xml" />
</bean>

Code Snippet ExtendPermissionModel.xml

ACCESS CONTROL LISTS

An Access Control List (ACL) is an ordered list of Access Control Entries (ACEs). An ACE associates a single authority to a single permission group or permission, and states whether the permission is to be allowed or denied. All nodes have an associated ACL. There is one special, context-free, ACL defined in the XML configuration to support global permissions. An ACL specifies if it should inherit ACEs from a parent ACL. The parent ACL is associated with the primary parent node. When a new node is created it automatically inherits all ACEs defined on the parent within which it is created. Linking a node to a secondary parent has no effect on ACE inheritance; the node will continue to inherit permission changes from its primary parent (defined when it was first created).

By default, ACL inheritance is always from the primary parent. The underlying design and implementation does not mandate this. ACL inheritance does not have to follow the parent-child relationship. It is possible to change this through the Java API but not via the administration pages of the Alfresco Explorer and Alfresco Share Web clients.

There are several types of ACL defined in ACLType. The main types are:

  • DEFINING

  • SHARED

  • FIXED

  • GLOBAL

A node will be associated with an ACL. It will have a DEFINING ACL if any ACE has been set on the node. DEFINING ACLs include any ACEs inherited from the node's primary parent and above, if inheritance is enabled. All DEFINING ACLs are associated with one SHARED ACL. This SHARED ACL includes all the ACEs that are inherited from the DEFINING ACL. If the primary children of a node with a DEFINING ACL do not themselves have any specific ACEs defined, then they can be assigned the related SHARED ACL. For the primary children of a node with a SHARED ACL that also have no specific ACEs set, they can use the same SHARED ACL. A single SHARED ACL can be associated with many nodes. When a DEFINING ACL is updated, it will cascade-update any related ACLs via the ACL relationships rather than walk the node structure. If a DEFINING ACL inherits ACEs, then these will come from the SHARED ACL related to another DEFINING ACL.

ACLs and nodes have two linked tree structures. See the example in Figure 6-2, the ACL descriptions in Table 6-2, and the discussion in the section titled "An ACL Example."

FIXED ACLs are not associated with a node but found by name. A node ACL could be defined to inherit from a fixed ACL. A GLOBAL ACL is a special case of a FIXED ACL with a well-known name. It will be used to hold the global ACE currently defined in XML.

ACEs comprise an authority, a permission, and a deny/allow flag. They are ordered in an ACL.

ACL Ordering and Evaluation

The ACEs within an ACL are ordered and contain positional information reflecting how an ACE was inherited. DEFINING ACLs have entries at even positions; SHARED ACLs have entries at odd positions. For a DEFINING ACL, any ACEs defined for that ACL have position 0, any inherited from the parent ACL have position 2, and so on. For a SHARED ACL, ACEs defined on the ACL from which it inherits will have position 1.

When Alfresco makes permission checks, ACEs are considered in order, with the lowest position first. Deny entries take precedence over allow entries at the same position. The default configuration is that "any allow allows." Once a deny entry is found for a specific authority and permission combination, any matching ACE, at a higher position from further up the inheritance chain, is denied. A deny for one authority does not deny an assignment for a different authority. If a group is denied Read permission, a person who is a member of that group can still be assigned Read permission via another group or directly via their person userName. However, if an authority is granted Read (made up of ReadContent and ReadProperties) and the same authority denied ReadContent, they will just be granted ReadProperties permission. The administration pages of the Alfresco Explorer and Alfresco Share Web clients do not expose deny.

You can alter the configuration to support "any deny denies."

An ACL Example

This example relates a tree of nodes to two corresponding trees of ACLs, all shown in Figure 6-2. The nodes in the node tree are identified by number and are shown filled in black if they have any ACEs set, or white/clear if not. Primary child relationships are drawn as black lines and secondary child relationships as dashed lines. ACLs in the ACL trees are identified by letter, DEFINING ACLs are shown filled in black, and SHARED ALCs are shown as clear. Under each node on the node tree, the related ACL is referenced.

Table 6-2 describes the ACEs in each ACL and their position.

ACL A, and any ACL that inherits from it, allows Read for everyone (All) unless permissions are subsequently denied for everyone (All). If ACL A is changed, all the ACLs that inherit from ACL A in the ACL tree will reflect this change. In the example, nodes 1–12 would be affected by such a change. Nodes 13 and 14 would not inherit the change due to the definition of ACL G.

FIGURE 6-2

Figure 6.2. FIGURE 6-2

ACL C adds Contributor and Editor permissions for any authority in GROUP_A.

Note

The GROUP_ prefix is normally hidden by the administration pages of the Alfresco Explorer and Alfresco Share Web clients.

Anyone in GROUP_A can edit existing content or create new content. The owner ACE means that anyone who creates content then has full rights to it. The ACE assignment for owner is not normally required, as all rights are given to node owners in the context-free ACL defined in the default permission configuration.

ACL E adds some specific user ACEs in addition to those defined in ACL A. As an example, it allows Bob Write but also denies WriteContent. Write is made up of WriteContent and WriteProperties. Bob will only be allowed WriteProperties.

Table 6.2. ACL Formats

ACL FORMAT

AUTHORITY

PERMISSION

ALLOW/DENY

POSITION

ACL A (DEFINING, no inheritance)

All

Read

Allow

0

ACL B (SHARED, inherits from ACL A)

All

Read

Allow

1

ACL C (DEFINING, inherits from ACL B)

All

Read

Allow

2

 

ROLE_OWNER

All

Allow

0

 

GROUP_A

Write

Allow

0

 

GROUP_A

CreateChildren

Allow

0

ACL D (SHARED, inherits from ACL C)

All

Read

Allow

3

 

ROLE_OWNER

All

Allow

1

 

GROUP_A

Write

Allow

1

 

GROUP_A

CreateChildren

Allow

1

ACL E (DEFINING, inherits from ACL B)

All

Read

Allow

2

 

Andy

All

Allow

0

 

Bob

Write

Allow

0

 

Bob

WriteContent

Deny

0

ACL F (SHARED, inherits from ACL E)

All

Read

Allow

3

 

Andy

All

Allow

1

 

Bob

Write

Allow

1

 

Bob

WriteContent

Deny

1

ACL G (DEFINING, no inheritance)

Bob

All

Allow

0

ACL H (SHARED, inherits from ACL G)

Bob

All

Allow

1

ACL G does not inherit and starts a new ACL tree unaffected by any other ACL tree unless an inheritance link is subsequently made.

If a new node were created beneath node 13 or 14, it would inherit ACL H. If a new node were created beneath nodes 1, 6, 7, or 8, it would inherit ACL B.

If a node that has a shared ACL has an ACE set, a new defining ACL and a related shared ACL are inserted in the ACL tree. If a defining ACL has all its position-0 ACEs removed, it still remains a defining ACL: There is no automatic cleanup of no-op defining ACLs.

PUBLIC SERVICES

Security is enforced around public services. Web services, Web scripts, Alfresco Explorer and Alfresco Share Web clients, CIFS, WebDAV, FTP, CMIS, and more all use public services, so include security enforcement. Public services are defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-context.xml.

Access control allows or prevents users or processes acting on behalf of a user from executing service methods on a particular object by checking if the current user, or any of the authorities granted to the current user, has a particular permission or permission group, or that the user has a particular authority.

For example, on the NodeService bean, the readProperties method checks that the current user has Read permission for the node before invoking the method and returning the node's properties. On the SearchService query method, the results are restricted to return only the nodes for which a user has Read permission.

Configuration

Security is enforced in the Spring configuration by defining proxies for each internal service implementation and adding a method interceptor to enforce security for each public service proxy. These interceptors also have other roles discussed elsewhere. When a method is called on a public service, the security interceptor is called before the method it wraps. At this stage, the interceptor can examine the function arguments to the method and check that the user has the appropriate rights for each argument in order to invoke the method. For example, a method delete(NodeRef nodeRef) exists on the node service. The security interceptor can see the nodeRef argument before the underlying delete(...) method is called. If configured correctly, the interceptor could check that the current user has Delete permission for the node. If they do not have the permission, a security exception is raised. If all the entry criteria are met, the method goes ahead.

In a similar manner, after a method has executed, the interceptor can examine the returned object and decide if it should return it to the caller. For example, a search method could return a list of nodes. The security interceptor could filter this list for only those nodes for which the current user has Read permission.

It is also possible to configure a method so that it can be called by all users, only by users with the admin role, or only by specific users or groups. This can also be enforced by the security method interceptor.

Access control interceptor definitions for public services are included in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-security-context.xml along with any other supporting beans. This configuration file also defines the location from which the permission model is loaded. The interceptors are wired up to the public services in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-context.xml. The public services are the only Spring beans to have access control.

Defining Method-Level Security

The beans required to support Spring ACEGI-based security around method invocation are defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-security-context.xml. This configures two Alfresco-specific beans: A voter that can authorize method execution based on the permissions granted to the current user for specific arguments to the method, and an after-invocation provider to apply security to objects returned by methods. Method access is defined in the normal ACEGI manner with some additions.

For the following information detailing pre-conditions and post-conditions, these factors are all relevant:

  • <authority> — Represents an authority (user name or group)

  • <#> — Represents a method argument index

  • <permission> — Represents the string representation of a permission

Pre-conditions take one of the following forms:

  • ACL_METHOD.<authority> — Restricts access to the method to those with the given authority in Alfresco. This could be a user name or group. Dynamic authorities are not supported.

  • ACL_NODE.<#>.<permission> — Restricts access control to users who have the specified permission for the node at the identified argument. If the argument is a NodeRef, it will be used; if it is a StoreRef, the root node for the store will be used; if it is a ChildAssociationRef, the child node will be used.

  • ACL_PARENT.<#>.<permission> — Restricts access control to users who have the specified permission for the parent of the node on the identified argument. If the argument is a NodeRef, the parent of the node will be used; if it is a ChildAssociationRef, the parent node will be used.

  • ROLE_... — Checks for an authority starting with ROLE_

  • GROUP_... — Checks for an authority starting with GROUP_

If more than one ACL_NODE.<#>.<permission>, ACL_PARENT.<#>.<permission>, or ACL_METHOD.<permission> entry is present, then all of the ACL_NODE and ACL_PARENT permissions must be present as well as any one of the ACL_METHOD restrictions, if present, for the method to execute.

Post-conditions take the forms:

  • AFTER_ACL_NODE.<permission> — Similar to ACL_NODE.<#>.<permission> but the restriction applies to the return argument

  • AFTER_ACL_PARENT.<permission> — Similar to ACL_PARENT.<#>.<permission> but the restriction applies to the return argument

The support return types are:

  • StoreRef

  • ChildAssociationRef

  • Collections of StoreRef, NodeRef, ChildAssociationRef, and FileInfo

  • FileInfo

  • NodeRef

  • Arrays of StoreRef, NodeRef, ChildAssociationRef, and FileInfo

  • PagingLuceneResultSet

  • QueryEngineResults

  • ResultSet

The post-conditions will create access denied exceptions for return types such as NodeRef, StoreRef, ChildAssociationRef, and FileInfo. For collections, arrays, and result sets, their members will be filtered based on the access conditions applied to each member.

Continuing the example from the permissions defined for the Ownable aspect, the definition for the security interceptor for the related OwnableService is shown in the following code snippet.

<bean id="OwnableService_security"
  class="org.alfresco.repo.security.permissions.impl.acegi.
  MethodSecurityInterceptor">
    <property name="authenticationManager"><ref bean="authenticationManager"/>
    </property>
    <property name="accessDecisionManager"><ref local="accessDecisionManager"/>
    </property>
    <property name="afterInvocationManager"><ref local="afterInvocationManager"/>
    </property>
    <property name="objectDefinitionSource">
      <value>
      org.alfresco.service.cmr.security.OwnableService.getOwner=
      ACL_NODE.0.sys:base.ReadProperties
    org.alfresco.service.cmr.security.OwnableService.setOwner=
    ACL_NODE.0.cm:ownable.SetOwner
     org.alfresco.service.cmr.security.OwnableService.takeOwnership=
     ACL_NODE.0.cm:ownable.TakeOwnership
      org.alfresco.service.cmr.security.OwnableService.hasOwner=
      ACL_NODE.0.sys:base.ReadProperties
      org.alfresco.service.cmr.security.OwnableService.*=ACL_DENY
      </value>
    </property>
</bean>

Code Snippet OwnableServiceSecurity.xml

Here, security for the four methods on the OwnableService is defined. To invoke the OwnableService getOwner() method on a node, the invoker must have permission to read the properties of the target node. To set the owner of a node, a user must have been explicitly assigned the SetOwner permission or have all rights to the node. A user may have all rights to a node via the context-free ACL or be assigned a permission which grants all permission or includes SetOwner. With the default configuration, a user will own any node they create and therefore be able to give ownership to anyone else and possibly not have the right to take ownership back.

The last entry catches and denies access for any other method calls other than those listed. If any additional methods were added to this service and no security configuration explicitly defined for the new methods, these methods would always deny access.

MODIFYING ACCESS CONTROL

Modifying access control may involve:

  • Changing the definition of existing security interceptors to check for different conditions

  • Adding new public services and related security interceptors

  • Defining new types and aspects and their related permissions

  • Adding new definitions to the security interceptor by implementing an ACEGI AccessDecisionVoter and/or AfterInvocationProvider (in extreme cases)

A few constraints and design patterns should be observed when modifying access control. Permissions apply to the node as whole. In particular, the same Read rights apply to all properties and content. You should check that methods can be executed and not that a user has a particular permission. The access control restrictions for a public service method may change. Follow the design pattern to implement RBAC roles.

When modifying access control, do not try to split ReadProperties and ReadContent. This does not make sense for search. A node and all of its properties, including content, are indexed as one entity. Splitting the evaluation of access for content and properties is not possible. Search would have to apply both criteria so as to not leak information. Other services, such as copy, may not behave as expected or may produce nodes in an odd state.

Permissions are assigned at the node level, not at the attribute level. Again, this makes sense with the search capabilities. 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 and individual properties are not 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 child nodes to partition metadata. Queries would have to be done in parts and joined by hand, as there is no native support for SQL-like join.

Check that method execution is allowed; do not check that the user has a fixed permission. Rather than checking for Read permission in code, check that the appropriate method can be called using the PublicServiceAccessService bean. This avoids hard-coding to a specific permission implementation and is essential if you intend to mix records management and the content repository. In any case, the access restrictions for public service methods may change. The PublicServiceAccessService bean allows you to test if any public service method can be invoked successfully with a given set of arguments. It checks all the entry criteria for the method and, assuming these have not changed, the method can be called successfully. The method call may still fail if the conditions for the returned object are not met or some security configuration has changed, such as an ACE has been removed, a user has been removed from a group, or the method has failed for a non-authorization reason.

If you are coming from an RBAC background, Alfresco has roles in the RBAC sense only for limited internal use. To implement RBAC in Alfresco, use zoned groups. These groups will not appear in the administration pages of the Alfresco Explorer and Alfresco Share Web clients as normal groups (unless you also add them to the APP.DEFAULT zone) but can be used to assign users and groups to roles. This approach has been taken in Alfresco to support roles in Alfresco Share and records management. Here is how RBAC terminology maps to Alfresco: Operations map to method calls on public service beans; objects map to method arguments, including nodes (folders, documents, and so on). Users and permissions/privileges map directly. Alfresco allows the assignment of permissions to users or groups.

By default, the owner of an object can manage any aspect of its ACL. Users with ChangePermissions rights for a node can also change its ACL. If users have the ability to alter the ACL associated with an object, they can allow other users to do the same. There is no restriction on the permissions they may assign. The Alfresco model supports liberal discretionary access control with multi-level grant. A user who can grant access can pass on this right without any restriction. In addition, anyone who can change permissions can carry out the revocation of rights: it is not restricted to the original granter. Normally, when someone can perform an operation you would not expect it is because they own the node and therefore have all permissions for that node.

ACCESS CONTROL EXTENSION

The access control model described so far is used for all nodes in the content repository except those related to the Records Management extension. Records Management is used as an example here to outline how to extend access control.

The Records Management authorization is based on a fixed set of capabilities that are part of the DOD 5015.2 specification. These capabilities describe records management operations for which there is not a direct mapping to an Alfresco public service method call. There are separate Records Management implementations of the ACEGI AccessDecisionVoter and AfterInvocationProvider interfaces to support this mapping. The AccessDecisionVoter allows or denies access on method entry. The AfterInvocationProvider allows or denies access based on the method return value; it can also alter the return value. All Records Management nodes carry a marker aspect (an aspect that defines no properties or associations). If this marker is present, the default voter will abstain; if this marker is absent, the Records Management voter will abstain.

Public services are protected for Records Management in the same manner as already described but with two sets of configuration: one for each of the two different implementations. It is more complex to map the Records Management capabilities and caveats (for example, security clearance) to public service method calls and to enforce the restrictions. For example, the node service updateProperties method has to incorporate the idea of updating declared and undeclared records, allow updates to selected properties, and restrict access to some properties that should be updated only as part of state management. The Records Management voter has additional Records Management hard-coded policies to protect the public services in order to encapsulate the logic for this and related use cases.

In Records Management, normal users cannot pass on their rights to other users.

IMPLEMENTATION AND SERVICES

There are four key services involved in access control: the PersonService, the AuthorityService; the PermissionService, and the OwnableService. The PersonService and the AuthorityService are responsible for managing authorities. The PermissionService is responsible for managing ACLs and ACEs and for checking if a user has been assigned a permission for a particular node. The OwnableService manages object ownership and is used in evaluation the dynamic ROLE_OWNER authority.

The protection of public services methods is implemented using Spring method interceptors defined as part of the related ACEGI 0.8.2 security package. The Alfresco implementation adds new implementations of the ACEGI interfaces AccessDecisionVoter and AfterInvocationProvider, which support the configuration elements that have already been described (for example, ACL_NODE.<#>.<permission>). These extension classes make use of the four key services.

The Person Service

The PersonService interface is the API by which nodes of the person type, as defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescomodelcontentModel.xml, should be accessed.

The PersonService is responsible for all of the following:

  • 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 PersonService and its configuration can be found in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescoauthentication-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.

The Authority Service

The AuthorityService is responsible for:

  • Creating and deleting authorities

  • Querying for authorities

  • Structuring authorities into hierarchies

  • Supporting queries for membership

  • Finding all the authorities that apply to the current authenticated user

  • Determining if the current authenticated user has admin rights

  • Managing zones and the assignment of authorities to zones

The authority service does not support user authentication or user management. This is done by the AuthenticationService. Person nodes are managed via the PersonService.

The default implementation allows a list of group names to define both administration groups and guest groups. Each authentication component defines its own default administrative user(s), which can also be set explicitly. The default service is defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescoauthority-services-context.xml.

The Permission Service

The PermissionService is responsible for all of the following:

  • 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

  • Determining 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 simply a name scoped by the fully qualified name of the type or aspect to which it applies. The beans are defined and configured in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-security-context.xml. This file also contains the configuration for security enforcement.

The ModelDAO interface defines an API to access a permissions model. The default permission model is in XML and defines permission sets, and their related permission groups and permissions. Global permissions are part of the permission model. There may be more than one permission model defined in XML; they are in practice merged into one permission model. A module can extend the permission model.

The available permissions are defined in the permission model. This is defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescomodelpermissionDefinitions.xml. This configuration is loaded in a bean definition in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescopublic-services-security-context.xml. 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 in order to apply the changes.

The Ownable Service

The idea of file ownership is present in both UNIX and Windows. In Alfresco, the repository has the concept of node ownership. This ownership is optional and is implemented as an aspect.

The owner of a node may have specific ACLs granted to them. Ownership is implemented as the dynamic authority, ROLE_OWNER, and is evaluated in the context of each node for which an authorization request is made. The Ownable aspect, if present, defines a node's owner by storing a userName; if the Ownable aspect is not present, the creator is used as the default owner. If the userName of the current user matches, including case, the userName stored as the owner of the node, the current user will be granted all permissions assigned to the authority ROLE_OWNER.

The OwnableService is responsible for all of the following:

  • Determining the owner of a node

  • Setting the owner of a node

  • Determining if a node has an owner

  • Allowing the current user to take ownership of a node

The OwnableService is supported by an Ownable aspect defined in <installLocation> omcatwebappsalfrescoWEB-INFclassesalfrescomodelcontentModel.xml.

There are permissions and permission groups associated with the Ownable aspect in the permission model and related access controls applied to the methods on the public OwnableService.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.195.236