Friday, July 20, 2012

Integrating FreeIPA and Alfresco...

After describing how to install CentOS, DNS and reverse DNS, FreeIPA and Alfresco, in this post I'm going to describe how to integrate Alfresco with FreeIPA. I want to achieve the following goals with the integration:
  • Users and groups are kept within FreeIPA and authentication is done by FreeIPA.
  • Alfresco Web interface honors Kerberos tickets. Upon opening Web interface users are immediately presented with their pages withoug necessity for authentication (if, of course, they have valid Kerberos tickets).
  • Authentication when mounting DAV share is also done via Kerberos tickets.
In short, I want to achieve SSO (Single Sign-On) as much as possible. Users sign in when they start to use their workstations once, that's the only time they have to enter password.

Preparation step

In case you don't have any users in FreeIPA it is a good idea to create at least one so that you can test integration process.

Also, alfresco host has to join Kerberos domain. This is done using ipa-client-install tool from ipa-client package. So, install ipa-client using yum and run the tool. This is the transcript for my case:
# ipa-client-install
DNS domain '' is not configured for automatic KDC address lookup.
KDC address will be set to fixed value.

Discovery was successful!
Hostname: alfresco.example-domain.local
DNS Domain: example-domain.local
IPA Server: ipa.example-domain.local
BaseDN: dc=example-domain,dc=com

Continue to configure the system with these values? [no]: yes
User authorized to enroll computers: admin
Synchronizing time with KDC...
Password for admin@EXAMPLE-DOMAIN.COM:

Enrolled in IPA realm EXAMPLE-DOMAIN.COM
Created /etc/ipa/default.conf
Configured /etc/sssd/sssd.conf
Configured /etc/krb5.conf for IPA realm EXAMPLE-DOMAIN.COM
SSSD enabled
NTP enabled
Client configuration complete.
As you can see, the tool automatically figured out all the parameters using DNS. In case you DNS isn't configured you'll have to provide all this information manually.

Integrating with LDAP

First, we are going to connect Alfresco to LDAP. Basically, LDAP will be used for storing user data.

Go to the directory $WEBAPPS/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/ldap. Open file in text editor and change the following lines:
  • should be set to false, i.e. we are not using LDAP for authentication!
  • Set ldap.authentication.userNameFormat to uid=%s,cn=users,cn=accounts,dc=example-domain,dc=com
  • should be set to point to your FreeIPA instance. In our case that should be ldap://ipa.example-domain.local:389
  • Set default principal for user and group synchronization to Directory Manager, i.e. set should be set to cn\=Directory\ Manager (note backslashes!).
  • Define password of the user for synchronization, i.e. set value of to whatever password you defined for the user.
  • Change base DN of users, i.e. set ldap.synchronization.userSearchBase to cn\=users,cn\=accounts,dc\=example-domain,dc\=com. Again, note backslashes.
  • Change base DN of groups, i.e. set ldap.synchronization.groupSearchBase to cn\=groups,cn\=accounts,dc\=example-domain,dc\=com
Two things to note. The first one is security related! Namely you should not (ab)use Directory Manager to connect to directory server in production environment, i.e. you should create a separate user for that role. Next thing to note is that base DN in LDAP mirrors Kerberos domain, i.e. EXAMPLE-DOMAIN.COM and not DNS domain (example-domain.local).

Now, open file $WEBAPPS/ alfresco/WEB-INF/classes/ and find the following line:
it is commented out, and shown is default value (i.e. the value that will be assumed if variable isn't defined). So, remove comment mark (hash) and modify line to read like this:
What you are basically saying is that first local authentication should be tried and then LDAP. Later we will add kerberos for authentication.

Now, start Alfresco and look into log file. There should be no errors related to user synchronization. For additional check, go to the Alfresco Web console (as user admin) and get user list. In the user list should appear users pulled from FreeIPA. Also, in the log file you should see the lines about successful LDAP synchronization.

Ok, now stop tomcat again and let's proceed to Kerberos integration.

Integrating with Kerberos

First, we need to add HTTP service principal and retrieve its keytab. To do that first you need to create principal, so go to IPA administration console and then select Services tab. You'll see there predefined services for the ipa host itself. Click on Add button and fill in the fields so that service's type and name is HTTP and for host name select host on which alfresco is running (i.e. alfresco.example-domain.local).

Now, go to Alfresco host and first obtain admin ticket:
# kinit admin
Password for admin@EXAMPLE-DOMAIN.COM: <type your admin password>
Then, obtain ticket for Alfresco HTTP service using the following command:
# ipa-getkeytab -k /etc/alfrescohttp.keytab -p HTTP/alfresco.example-domain.local@EXAMPLE-DOMAIN.COM -s -P
New Principal Password: <type password>
Verify Principal Password:
<retype password>
ipa.example-domain.localKeytab successfully retrieved and stored in: /etc/alfrescohttp.keytab
Again, open the file $WEBAPPS/alfresco/WEB-INF/classes/ and modify the variable authentication.chain to have the following value:
we are basically adding Kerberos into authentication chain. Now, go to directory $WEBAPPS/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/kerberos and open file in text editor. In the file, only one line is important and that is authenticateCIFS which should be set to false:
Note that there is also variable kerberos.authentication.http.password and in case you protected alfresco's http ticket with pasword you'll have to use that variable to tell alfresco which password to use to unlock ticket.

Now, open the file that is in the same directory as the file. In this file set the value of property kerberos.authentication.http.password to the password you entered when you've run ipa-getkeytab command.

Now, go to the directory /usr/lib/jvm/java-1.6.0-openjdk- Note that if you are using other version of Java you should change directory name to reflect the Java version. In that directory create file named java.login.config with the following content:
Alfresco { sufficient;
AlfrescoCIFS { required
AlfrescoHTTP { required
}; { sufficient;
other { sufficient;
In the same directory in which you created java.login.config you'll find file Open it and find the following line:
Uncomment it and change it, or add another one, that reads like this:
Save and close the file.

Now to test if everything is working as expected...

Testing kerberos authentication

To test if kerberos authentication is working you need properly configured Firefox browser and a computer on which you can request tickets (via kinit command).

To be able to request Kerberos tickets use ipa-client-install command on some workstation. This will configure DNS resolution and /etc/krb5.conf file. Alternatively, if you don't want or can not run ipa-client-install, you can copy /etc/krb5.conf from Alfresco to some computer and change /etc/resolv.conf to point to IPA server. Then issue ticket for, e.g. admin@EXAMPLE-DOMAIN.COM principal. To have Firefox browser properly configured go to IPA Web UI (see my previous post about IPA installation for details). This will configure Firefox to handle Kerberos tickets.

Finally, in the Firefox browser enter Alfresco's URL, i.e. https://alfresco.example-domain.local/alfresco/. What should happen is that you should be automatically logged in as admin user (or whichever user's ticket you obtained).

As an additional test you can do the following. First, select Logout in Alfresco's Web console. You are now presented with the option to Re-login. If you click that link you'll be logged in again. But, in the command line run kdestroy which will remove your ticket. Click on Re-login now! What should happen is that you are presented with a Alfresco's Login screen.

Error messages

Here are error messages I had to resolve why trying to configure Alfresco and FreeIPA, in case you stumble on them to know what's wrong.

07:53:32,266 ERROR [org.alfresco.fileserver] CIFS server configuration error, Error creating bean with name 'authenticationComponent' defined in file [/var/lib/tomcat6/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/ldap/../common-ldap-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'boolean' for property 'active'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [${}]

This is CIFS server complaining that no authentication is defined. But, since I don't want CIFS, I simply disabled it by editing file in directory $WEBAPPS/alfresco/WEB-INF/classes/alfresco/subsystems/fileServers/default.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationComponent' defined in file [/var/lib/tomcat6/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/ldap/../common-ldap-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'boolean' for property 'active'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [${}]

This one was real pain to discover what's wrong. Namely, the value was set to false, which is (you guessed it) boolean!? But Alfresco claims it's not. What happened actually is that I moved properties file in another directory and Alfresco couldn't find it. So, variables were not initialized and obviously they were left as is instead of being replaced with values, in this case false.

20:16:23,243 ERROR [] HTTP Kerberos web filter error Integrity check on decrypted field failed (31) - PREAUTH_FAILED
For this message question on Stackoverflow was the first info I managed to find. Then, I stumbled on this post, but it didn't help either. The latest info about this is this post. After I published initial version of this post I realized that I was actually configuring CIFS instead of HTTP. In other words, I had to disable CIFS and properly configure HTTP. The text is updated now.

In case you see the previous entry in the log file than one of the reasons could be that keytab is encrypted but you (that is application) is trying to decrypt it using a wrong key/passpharse.


Adam Valenzuela said...

quick question... where you indicate the creation of the "java.login.config" do you need to change "principal="HTTP/alfresco.example-domain.local@EXAMPLE-DOMAIN.LOCAL";" with what our actual entry is that we created when we generated the keytab or is this line referencing something else?

Stjepan Groš (sgros) said...

Yes, that entry is specific to Alfresco, and thus it has to be changed.

Adam Valenzuela said...

thank you so much for you quick turn around. I have one last hurdle (i hope) after following your kerberos config and making changes in the and the java.login.config i get the following error when i http connect to /alfresco or when i tail the logs when trying to auth with an existing IPA user from /share

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'globalAuthenticationFilter' defined in file [/opt/alfresco-4.0.d/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/kerberos/kerberos-filter-context.xml]: Invocation of init method failed; nested exception is java.lang.SecurityException: Unable to locate a login configuration
caused by:
java.lang.SecurityException: Unable to locate a login configuration
caused by: Unable to locate a login configuration

what did I do wrong?

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive