Alfresco – 2010 Roadmap
As some of you might have seen Alfresco team have published a roadmap for the year 2010. I must say I’m very pleased with the latest community version 3.2r2 (actually, couple more SVN releases than the official 17458 but lets not be picky). In my opinion, it is finally what was 3.0 “Stable” supposed to be and I’m not counting the DoD module here but the overall stability of the product.
My wishes for community edition in 2010:
- content store selector available in enterprise edition only
- better support for Windows 7
- fine-tuning of UI controls in Share as some are really not available where they should be, hint: Edit Online on document details page
- content modeling in GUI not just in XMLs
- ability to chain SSO authentication with something non-SSO e.g. NTLM SSO + ldap if it is even technically possible
- faster merging of bug-fixes from enterprise branch
- better support from Alfresco team in forums though I must say they’ve been very helpful in last 6-9 months
- publishing critical patches for last stable community release and not just telling people to “it’s in HEAD”
- abandon policy to have certain functionality in enterprise edition only as legally possible
+ of course, everything they have in their published roadmap
Alfresco, Sharepoint protocol, Office 2007, and Vista
To get the Alfresco’s implementation of Sharepoint protocol to work properly on Vista/Office 2007 with NTLM authentication you need to mess a bit with your registry. I consider you did your job and are using fully updated versions of both Vista and Office.
Open up the Alfresco Share, navigate to the document library and locate some Office document and click Edit online. Likely, the file will open read-only. So, implement this fix from Microsoft’s article KB 870853.
If you try again, file will open up fine but when you save it you’ll get an error message stating “Word did not save the document”. To fix this stop or disable the Web Client Windows service using Services MMC snap-in.
Sharepoint protocol should work completely now.
Deny delete permission to space owner in Alfresco
If you are the guy/girl responsible for implementing permissions model for your business case you might find yourself in trouble. Let us imagine a scenario where business case states that certain users should be able to create new content but not be able to delete anything. That’s the easy one, you’ll likely say, and assign Contributor role to those users.
Lets check Contributor role definition from the Alfresco wiki:
Contributor
Includes the Consumer permission group and adds AddChildren and CheckOut.
They will, by default own anything they create and have the ROLE_OWNER authority.
Hm, ROLE_OWNER looks suspicious:
“FullControl” granted to “ROLE_OWNER”
The owner (as defined by the ownable aspect, or, if the aspect is not present the node creator) is allowed all rights. This interacts with contributor for cm:content. They only need the right to create content in the default set up; all other rights come from the fact that they own the nodes they create.
To sum up the above, users that are just contributors can delete everything they create and you likely don’t want that.
So what can we do to fix this. There are two options and both have certain drawbacks.
Method 1: Edit permissionDefinitions.xml
Add somewhere near the top of the model/permissionDefinitions.xml file new permissionGroup definition and assign permissions by your needs:
<permissionGroup name=”FullWithoutDelete” allowFullControl=”false” expose=”false”>
<includePermissionGroup type=”sys:base” permissionGroup=”Read”/>
<includePermissionGroup type=”sys:base” permissionGroup=”Write”/>
<includePermissionGroup type=”sys:base” permissionGroup=”AddChildren”/>
<includePermissionGroup type=”sys:base” permissionGroup=”Execute”/>
</permissionGroup>
then find:
<globalPermission permission=”FullControl” authority=”ROLE_OWNER”/>
and change it to:
<globalPermission permission=”FullWithoutDelete” authority=”ROLE_OWNER”/>
Notice that this will take away delete permissions from owners on ALL content in repository unless he is assigned proper permissions on space. Drawback: you mess with the core Alfresco configuration which may have unexpected consequences although I haven’t seen any with the above in a production setup at one of the clients.
Method 2: Ownable aspect
There is one other option the I think is better than messing with core alfresco configs. You can create a rule on top space that adds cm:ownable aspect to whatever you want. By default if ownable aspect i.e. cm:owner property is not present (which is the case when adding new content on clean config) then cm:creator property is used as owner.
So when you add content and rule gets triggered document receives ownable aspect with cm:owner property empty. This in effect removes delete permissions from cm:creator as he is no longer the owner and cm:owner is empty!
Note that adding aspects is exposed in rules wizard though you might need to modify web-client-config-custom.xml to expose cm:ownable aspect in it.
Drawback: it is inconvenient if you already have a huge repository – you likely won’t be able to apply this action to entire repository. However, I recommend it if you start with clean repository and you did proper planning.
Alfresco – Tomcat as a Windows service
Question that is often asked and that usually leaves new users puzzled is how to run Alfresco on Apache Tomcat 6 as a Windows service. Unlike most examples found on the Internet I’ll show you how to mostly use graphical interface instead of command line. This article assumes you have Alfresco Tomcat bundle extracted at C:\Alfresco and Java 6 installed at default location.
So, to begin, fire-up command prompt and enter these two commands:
cd C:\Alfresco\tomcat\bin
tomcat6 //IS//alfresco –DisplayName=”Alfresco Server” –Install=”C:\Alfresco\tomcat\bin\tomcat6.exe”
We’re done with command line.
What you want to do next is create a shortcut in a convenient location, say desktop and put the following as the shortcut target:
C:\Alfresco\tomcat\bin\tomcat6w.exe //ES//alfresco
If you open it you’ll find a nice tool to edit service settings.

Tomcat server service control general settings
In general setting panel you can modify the service startup type. Next panel is the Log On account for the service. For the simplicity of this article we’ll leave it on Local System account but in production you should use an account with lower privileges.

Tomcat server service control log on properties
Next one is the logging panel. You can set the paths as shown in image. Make a mental note that stdout.log is now the main output log instead of alfresco.log. Make another mental note that stdout.log is not rotated daily when you run Tomcat as a service so it can grow huge.

Tomcat server service control logging properties
Next tab is the most important one – tab where you set all the Java options for the JVM. Make sure you have the paths to jvm.dll and bootstrap.jar correct. Initial memory pool, maximum memory pool, thread stack size are Xms, Xmx, and Xss parameters respectively that you set in alfresco.bat if you use default console startup of Tomcat. I’ll speak more about these parameters in another post.

Tomcat server service control java properties
Final two tabs are pretty much the same and they manage startup and shutdown parameters of the service. Make sure they look as in images.

Tomcat server service startup properties

Tomcat server service shutdown properties
64-bit Windows considerations
If you are using 64-bit Windows you’ll likely have trouble installing service using the default tomcat6.exe. Instead, download the 64-bit version from SVN repository. Also, make sure you are using the 64-bit Java.
Alfresco integration with Active Directory
Introduction
One of the main features of the Alfresco ECM System is the ability to integrate user authentication and synchronization with Microsoft Active Directory.
Unfortunately, integration is not trivial and it is error prone.
In this guide I’ll show you how to achieve full integration with Active Directory which includes Alfresco Explorer and Alfresco Share SSO, CIFS SSO, and Active Directory (LDAP) users and groups synchronization.
Prerequisites for this article are: working Active Directory environment, functional basic installation of Alfresco i.e. you can login into working Alfresco using the default admin/admin user. I tend to use bundled Alfresco/Tomcat zip installation since installer can be buggy from version to version and you don’t have full control. I recommend using Alfresco CE 3.2 build 2242 or later since it includes many fixes for NTLM, CIFS and LDAP merged from enterprise version. In my case Alfresco is installed on Windows 2003 EE with SP2 32bit.
Alfresco subsystems
Introduced in version 3.2 are the number of Alfresco subsystems:
- Authentication
- Synchronization
- File Servers
- IMAP
- sysAdmin
- WCM Deployment Receiver
- Third party (OpenOffice, Image Magick, etc.)
Subsystems in their nature are separate configurable modules responsible for a sub-part of the Alfresco functionality. Subsystems that we are interested in this article are the first three: authentication, synchronization and file servers. Note that configuration for subsystems is located in their respective folders as shown in the picture:
Note that LDAP synchronization is linked to LDAP authentication.
Lets get our hands dirty now.
Authentication
First thing to do to integrate user authentication with Active Directory is to configure the main authentication chain in Alfresco configuration. We do this by adding the following line in \Alfresco\tomcat\shared\classes\alfresco-global.properties:
authentication.chain=passthru1:passthru,ldap-ad1:ldap-ad
Note: ldap-ad is here in chain to support later explained user synchronization.
Now, create the file \subsystems\Authentication\passthru\passthru1\changes.properties and put the following inside:
passthru.authentication.useLocalServer=false
passthru.authentication.servers=DOMAIN\\192.168.0.1,192.168.0.1
ntlm.authentication.sso.enabled=true
alfresco.authentication.allowGuestLogin=false
ntlm.authentication.mapUnknownUserToGuest=false
passthru.authentication.authenticateCIFS=true
passthru.authentication.authenticateFTP=false
passthru.authentication.guestAccess=false
passthru.authentication.defaultAdministratorUserNames=AD_usernames
What we tell Alfresco with the above config is to use the external server for authentication, enable NTLM SSO, and put the list of usernames that should have the administrator role.
Now, edit the \Alfresco\tomcat\shared\classes\alfresco\web-extension\webscript-framework-config-custom.xml file and make sure the following is present and uncommented:
<config evaluator=”string-compare” condition=”Remote”>
<remote>
<!– SSL client certificate + trusted CAs. Optionally used to authenticate share to an external SSO system such as CAS –>
<keystore>
<path>alfresco/web-extension/alfresco-system.p12</path>
<type>pkcs12</type>
<password>alfresco-system</password>
</keystore>
<connector>
<id>alfrescoCookie</id>
<name>Alfresco Connector</name>
<description>Connects to an Alfresco instance using cookie-based authentication</description>
<class>org.alfresco.connector.AlfrescoConnector</class>
</connector><endpoint>
<id>alfresco</id>
<name>Alfresco – user access</name>
<description>Access to Alfresco Repository WebScripts that require user authentication</description>
<connector-id>alfrescoCookie</connector-id>
<endpoint-url>http://localhost:8080/alfresco/wcs</endpoint-url>
<identity>user</identity>
<external-auth>true</external-auth>
</endpoint>
</remote>
</config>
Next, edit the WEB-INF\web.xml file found in share.war (hint: share.war is just a zip file with .war extension) and uncomment the following:
<filter>
<filter-name>Authentication Filter</filter-name>
<filter-class>org.alfresco.web.site.servlet.NTLMAuthenticationFilter</filter-class>
<init-param>
<param-name>endpoint</param-name>
<param-value>alfresco</param-value>
</init-param>
</filter><filter-mapping>
<filter-name>Authentication Filter</filter-name>
<url-pattern>/page/*</url-pattern>
</filter-mapping><filter-mapping>
<filter-name>Authentication Filter</filter-name>
<url-pattern>/p/*</url-pattern>
</filter-mapping><filter-mapping>
<filter-name>Authentication Filter</filter-name>
<url-pattern>/s/*</url-pattern>
</filter-mapping>
SSO should now be fully functional for Alfresco Explorer and Alfresco Share. Lets synchronize the users and groups now.
Synchronization
For user synchronization to work we must configure Alfresco to hit the Active Directory domain controller with the appropriate LDAP queries. Queries are highly dependant of ones AD structure so the following configuration covers the scenario where:
- All groups that I want in Alfresco are members of a single group called Alfresco Groups,
- Users that I want synchronized to Alfresco are members of the above mentioned member groups.
This structure is nice if you have users in different OUs but don’t want them all to be also present in Alfresco.
So, edit the \subsystems\Authentication\ldap-ad\ldap-ad1\changes.properties file and add the following inside:
#
# LDAP Sync
#
# This flag enables use of this LDAP subsystem for authentication. It may be
# that this subsytem should only be used for synchronization, in which case
# this flag should be set to false.
ldap.authentication.active=false
ldap.authentication.java.naming.security.authentication=simple# This flag enables use of this LDAP subsystem for user and group
# synchronization. It may be that this subsytem should only be used for
# authentication, in which case this flag should be set to false.
ldap.synchronization.active=true
ldap.authentication.userNameFormat=%s
ldap.authentication.allowGuestLogin=true
ldap.authentication.java.naming.provider.url=ldap://domain.local:389# The default principal to bind with (only used for LDAP sync). This should be a UPN or DN
ldap.synchronization.java.naming.security.principal=user@domain.local# The password for the default principal (only used for LDAP sync)
ldap.synchronization.java.naming.security.credentials=YourPass# If positive, this property indicates that RFC 2696 paged results should be
# used to split query results into batches of the specified size. This
# overcomes any size limits imposed by the LDAP server.
ldap.synchronization.queryBatchSize=1000# The query to select all objects that represent the groups to import.
ldap.synchronization.groupQuery=(&(objectclass\=group)(memberOf\=cn\=Alfresco Groups,ou\=user,dc\=domain,dc\=local))# The query to select objects that represent the groups to import that have changed since a certain time.
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(memberOf\=cn\=Alfresco Groups,ou\=user,dc\=domain,dc\=local)(!(modifyTimestamp<\={0})))# The query to select all objects that represent the users to import.
ldap.synchronization.personQuery=(&(objectclass\=user)(|(memberOf\=CN\=Developers,OU\=user,DC\=domain,DC\=local)(memberOf\=CN\=Sales,OU\=user,DC\=domain,DC\=local))(userAccountControl\:1.2.840.113556.1.4.803\:\=512))# The query to select objects that represent the users to import that have changed since a certain time.
ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(|(memberOf\=CN\=Developers,OU\=user,DC\=domain,DC\=local)(memberOf\=CN\=Sales,OU\=user,DC\=domain,DC\=local))(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(!(modifyTimestamp<\={0})))# The group search base restricts the LDAP group query to a sub section of tree on the LDAP server.
ldap.synchronization.groupSearchBase=dc\=domain,dc\=local# The user search base restricts the LDAP user query to a sub section of tree on the LDAP server.
ldap.synchronization.userSearchBase=dc\=domain,dc\=local# The name of the operational attribute recording the last update time for a group or user.
ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp# The timestamp format. Unfortunately, this varies between directory servers.
ldap.synchronization.timestampFormat=yyyyMMddHHmmss’.0Z’# The attribute name on people objects found in LDAP to use as the uid in Alfresco
ldap.synchronization.userIdAttributeName=sAMAccountName# The attribute on person objects in LDAP to map to the first name property in Alfresco
ldap.synchronization.userFirstNameAttributeName=givenName# The attribute on person objects in LDAP to map to the last name property in Alfresco
ldap.synchronization.userLastNameAttributeName=sn# The attribute on person objects in LDAP to map to the email property in Alfresco
ldap.synchronization.userEmailAttributeName=mail# The attribute on person objects in LDAP to map to the organizational id property in Alfresco
ldap.synchronization.userOrganizationalIdAttributeName=company# The default home folder provider to use for people created via LDAP import
ldap.synchronization.defaultHomeFolderProvider=userHomesHomeFolderProvider# The attribute on LDAP group objects to map to the gid property in Alfrecso
ldap.synchronization.groupIdAttributeName=cn# The group type in LDAP
ldap.synchronization.groupType=group# The person type in LDAP
ldap.synchronization.personType=user# The attribute in LDAP on group objects that defines the DN for its members
ldap.synchronization.groupMemberAttributeName=membersynchronization.synchronizeChangesOnly=true
What we do above is: disable LDAP authentication and enable just LDAP synchronization, set the LDAP URL to query, credentials with read rights on LDAP, groups query, users query, and LDAP attributes to map Alfresco user’s attributes to. Note that LDAP synchronization is not instant, duration depends on number of objects to synchronize and is scheduled to run every hour (configurable in scheduled-jobs-context.xml).
CIFS
Now, the problematic part. CIFS is usually the hardest one to get it to work properly. So lets start with basic config that should work and then try to fix the eventual problems if there are any.
Edit the \subsystems\fileServers\default\default\changes.properties file and add the following inside:
filesystem.name=Alfresco
filesystem.domainMappings=DOMAIN
filesystem.domainMappings.value.DOMAIN.rangeFrom=192.168.0.0
filesystem.domainMappings.value.DOMAIN.rangeTo=192.168.0.255cifs.enabled=true
cifs.localname=HOSTNAME
cifs.domain=DOMAIN
cifs.hostannounce=true
cifs.urlfile.prefix=http://hostname:8080/alfresco/cifs.broadcast=192.168.0.255
cifs.bindto=192.168.0.123
cifs.ipv6=disabledftp.enabled=false
ftp.ipv6=disabled
nfs.enabled=false
If it doesn’t work you can try to enable only the Java socket based NetBIOS over TCP/IP. You do this by copying file-servers-context.xml to \subsystems\fileServers\default\default\custom-file-servers-context.xml and commenting out the following sections in it:
<!–
<property name=”netBIOSSMB”>
<bean class=”org.alfresco.filesys.config.NetBIOSSMBConfigBean”>
<property name=”bindTo”>
<value>${cifs.bindto}</value>
</property>
<property name=”sessionPort”>
<value>${cifs.netBIOSSMB.sessionPort}</value>
</property>
<property name=”namePort”>
<value>${cifs.netBIOSSMB.namePort}</value>
</property>
<property name=”datagramPort”>
<value>${cifs.netBIOSSMB.datagramPort}</value>
</property>
<property name=”platforms”>
<value>linux,solaris,macosx</value>
</property>
</bean>
</property>
–>
<!– Use Win32 NetBIOS interface on Windows –>
<!–
<property name=”win32NetBIOS”>
<bean class=”org.alfresco.filesys.config.Win32NetBIOSConfigBean” />
</property>
<property name=”win32HostAnnouncerEnabled”>
<value>${cifs.hostannounce}</value>
</property>
<property name=”win32HostAnnounceInterval”>
<value>5</value>
</property>
–>
Make sure the following property is setup like this:
<!– Use Java socket based NetBIOS over TCP/IP and native SMB on linux –>
<property name=”tcpipSMB”>
<bean class=”org.alfresco.filesys.config.TcpipSMBConfigBean”>
<!–
Can be mapped to non-privileged ports, then use firewall rules to forward requests from the standard
ports
–>
<property name=”port”>
<value>${cifs.tcpipSMB.port}</value>
</property>
<property name=”ipv6Enabled”>
<value>${cifs.ipv6.enabled}</value>
</property>
</bean>
</property>
You must also disable the native SMB over TCP/IP by editing th following registry key:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBT\Parameters]
“SMBDeviceEnabled”=dword:00000000
You can also try to disable File and Printer sharing in the network interface’s properties dialog.
Conclusion
As you can see Alfresco integration with Active Directory can be tricky but benefits you get are definitely worth the trouble. If you have any questions feel free to ask them in comments. Feedback is highly appreciated.
