Setting Up External Authentication Triggers

WARNING: Make sure you spell the trigger name correctly when adding the trigger with p4 triggers because a misspelling can result in all users being locked out of Perforce. Also, be sure to fully test your trigger and trigger table invocation prior to deployment in a production environment. Please contact support@perforce.com if you need assistance with restoring access to your server.

TASK

How can I authenticate Perforce users against external data?


SOLUTION

This article is for administrators who want to authenticate Perforce users against an external data source such as LDAP. Support for trigger types enabling external authentication was first made available in the 2005.2 release of the Perforce Server. You need to update your Perforce Server version to 2005.2 or later to use any of the following triggers with Perforce.

To implement external authentication, you must understand:

To implement external authentication, you create an authentication trigger. The trigger connects to a remote password database and delivers the username and password for verification.

There are two types of authentication triggers that can be configured:

  • auth-check : verifies a password for the p4 login command.
  • auth-set : sets a password for the p4 passwd command.

The auth-check trigger is run by the Perforce Server after the user issues the p4 login command. If the trigger runs successfully, the user is issued a Perforce ticket. If the trigger encounters an error, the login is rejected. Note that the P4PASSWD environment variable that you might have set (allowed up to security level 2) will no longer work.

The auth-set trigger is unlikely to be required since the users already have a way of setting their password external to Perforce; however, to be thorough it is described here. The auth-set trigger is run by the Perforce Server after the user issues the p4 passwd command. Note the auth-check trigger is also required to check old passwords before new external passwords can be set.

One important difference between authentication triggers and other Perforce triggers is the way authentication triggers receive the passwords. Passwords are sent to the auth-check and auth-set triggers on the standard input (STDIN). The first thing the trigger must do is read the password from STDIN. As with all triggers, success is indicated by an execution exit status of 0.

The following is a small Perl script example of how the password is read from the standard input. This simple case just checks that the password is "secret".

test auth-check auth "/script/checkpass"

#!/usr/bin/perl
##
## Perforce requires messages on stdout
##
open(STDERR, ">&STDOUT") or die "Can't dup stdout";
##
## read the password from <stdin< and truncate the newline
##
chomp (my $password = <STDIN>);
$password =~ s/r$//;
##
## success
##
if($password eq "secret"){
   exit 0;
}
##
## failure
##
die "You got the password wrong!";

In the above example, when a p4 login request is issued with the correct password supplied (note: this is totally independent of username), the server displays the following output:

% p4 login
Password: secret
User joeb logged in.

By contrast, when the wrong password is entered, you see the following output:

% p4 login
Password: foobar
Password invalid.
'test' validation failed: You got the password wrong!

If you write an auth-set trigger, the only difference from an auth-check trigger is that the auth-set trigger gets the old password followed by the new password on STDIN.

Below is an example auth-check trigger definition that authenticates against an LDAP server. Note that the LDAP distinguished name (DN) is being passed to the trigger as a trigger argument.

ldap auth-check auth "/script/checkpass uid=%user%,cn=users,dc=myco,dc=com"

After adding or removing an auth-check or auth-set trigger you must restart the server for your change to take effect. Making changes to the parameters of these triggers once they have been added can be done without a server restart.

When an auth-check trigger is in place, the Perforce security counter is ignored; Perforce no longer tries to enforce strong passwords or other such security measures.

For examples of authentication triggers (Perl/C), see the following code in the Public Depot. A detailed description of each script's function is explained in the comment sections of that script:

Active Directory vs. LDAP server

Active Directory differs from most LDAP servers in that it supports secure authentication but not secure communication.

Please note that the provided AD scripts work by using the cn for authentication. It expects the cn to be equal to the sAMAccountID, the short name without spaces that users generally use to log into their machine. If cn fields on your AD server have been changed to include spaces, you need to modify the scripts below to do a lookup on the sAMAccountID and retrieve the cn before attempting the AD authentication component.

Below is a small program that authenticates against an Active Directory server and compiles readily on Windows. Also included is an already compiled copy that should work on all Windows platforms and a Linux 24x86 binary. Before adding the script to the p4 triggers table, first run the script from a command line replacing %user% with an Active Directory username to make sure there are no errors and the script returns a zero exit code.

An example of how p4auth_ad should be called from a Perforce trigger is:

ad auth-check auth "c:/p4auth_ad.exe localhost 389 CN=Users,DC=test,DC=perforce,DC=com %user%"

Sometimes a Windows domain name must be appended to the user such as:

ad auth-check auth "c:/p4auth_ad.exe localhost 389 CN=Users,DC=test,DC=perforce,DC=com foobar\%user%"
Other times forward slashes are not allowed and backslashes must be used:
ad auth-check auth "c:\p4auth_ad.exe localhost 389 CN=Users,DC=test,DC=perforce,DC=com foobar\%user%"

To find the proper parameters to use, download the Port Query tool from Microsoft at

http://support.microsoft.com/kb/31009.

Look at serverName:

currentdate: 03/23/2010 22:22:59 (unadjusted GMT)
subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,DC=foo,DC=com
dsServiceName: CN=NTDS Settings,CN=SVR-DC1,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=foo,DC=com
namingContexts: DC=foo,DC=com
defaultNamingContext: DC=foo,DC=com
schemaNamingContext: CN=Schema,CN=Configuration,DC=foo,DC=com
configurationNamingContext: CN=Configuration,DC=foo,DC=com
rootDomainNamingContext: DC=foo,DC=com
supportedControl: 1.2.840.113556.1.4.319
supportedLDAPVersion: 3
supportedLDAPPolicies: MaxPoolThreads
highestCommittedUSN: 1715777
supportedSASLMechanisms: GSSAPI
dnsHostName: SVR.foo.com
ldapServiceName: foo.com:svr$@FOO.COM
serverName: CN=SVR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=foo,DC=com
supportedCapabilities: 1.2.840.113556.1.4.800
isSynchronized: TRUE
isGlobalCatalogReady: TRUE
domainFunctionality: 4
forestFunctionality: 4
domainControllerFunctionality: 4

The trigger syntax would become

ad auth-check auth "C:\Program Files\Perforce\p4auth_ad.exe SVR.foo.com 389 CN=SVR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=foo,DC=com foo\%user%"

Users reported that in some environments the above trigger does not properly handle users with null passwords. Use the below trigger in cases where the above trigger does not work. It operates in a similar fashion to the above trigger, but it does not allow users to login if they have not set an Active Directory password.

The above auth trigger is called slightly differently. It does not require the domain. Here is an example of how it should be called from a Perforce trigger where %user% might need to be replaced with %user%@<domainname>

ad auth-check auth "c:\p4auth_ad-no_null.exe localhost 389 %user@server.domainname.com"

Please report any issues encountered with these scripts to support@perforce.com. See Authentication Troubleshooting for help in debugging external authentication triggers.