Setting Up External Authentication Triggers

WARNING: Make sure to spell the trigger name correctly when adding an 'auth-check' trigger with p4 triggers. A misspelling can result in all users being locked out of Perforce. Also, be sure to fully test the trigger and trigger table invocation prior to deployment in a production environment. If you should get locked out of your Perforce server due to a external authenication trigger problem, please contact support@perforce.com for assistance with restoring access to the Perforce server.

TASK

How can I authenticate Perforce users against an external authentication source such as LDAP or Active Directory?

SOLUTION

Use a Perforce type 'auth-check' trigger.

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. A Perforce Server version 2005.2 or later is required use any of the following authentication triggers with Perforce.

To implement external authentication, an understanding of the following concepts is required:

The canonical reference for triggers is Chapter 6 of the Perforce System Administrator's Guide. See also KB Article #28 for additional information on using triggers in Perforce.

To implement external authentication, 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: If the P4PASSWD environment variable is set (permitted on Perforce servers up to security level 2) it will no longer work to authenticate Perforce commands.

The auth-set trigger is unlikely to be required since the users already have a way of setting their password external to the Perforce server. 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. As such, you can not have an auth-set trigger without a working auth-check trigger.

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 the server displays the following output:

% p4 login
Password: secret
User joeb logged in.

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

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

The only difference between an auth-set trigger and 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"

Note: After adding or removing an auth-check or auth-set trigger the Perforce server must be restarted for the 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, as this is now handled by the external authorization (such as LDAP).

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:

Password Length

Prior to Perforce release 2011.1, Perforce truncated passwords to 16 bytes. Users of Perforce releases prior to 2011.1 should avoid passwords longer than 16 bytes as the truncated values passed to the authentication trigger will never match a longer value stored in an external authentication mechanism.  The new password length limit for 2011.1 and later Perforce servers is 1024 bytes.

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 the AD server have been changed to include spaces, the scripts below will need to be modified to perform 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 a 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 existing 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%"

On some systems 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%"
On other systems 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 this link:

Microsoft also offers information on using this utility to query an Active Directory server at this link:

Once the Port Query is obtained, use it to determine the serverName:

c:\PortQryV2>PortQry.exe -n localhost -p tcp -e 389

Querying target system called:

 localhost

Attempting to resolve name to IP address...


Name resolved to 127.0.0.1

querying...

TCP port 389 (ldap service): LISTENING

Using ephemeral source port
Sending LDAP query to TCP port 389...

LDAP query response:


currentdate: 10/06/2011 17:16:29 (unadjusted GMT)
subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,DC=ad,DC=foo,DC=com
dsServiceName: CN=NTDS Settings,CN=GABRIEL,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=foo,DC=com
namingContexts: DC=ad,DC=foo,DC=com
defaultNamingContext: DC=ad,DC=foo,DC=com
schemaNamingContext: CN=Schema,CN=Configuration,DC=ad,DC=foo,DC=com
configurationNamingContext: CN=Configuration,DC=ad,DC=foo,DC=com
rootDomainNamingContext: DC=ad,DC=foo,DC=com
supportedControl: 1.2.840.113556.1.4.319
supportedLDAPVersion: 3
supportedLDAPPolicies: MaxPoolThreads
highestCommittedUSN: 180235
supportedSASLMechanisms: GSSAPI
dnsHostName: gabriel.ad.foo.com
ldapServiceName: ad.foo.com:gabriel$@AD.PERFORCE.COM
serverName: CN=GABRIEL,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=foo,DC=com
supportedCapabilities: 1.2.840.113556.1.4.800
isSynchronized: TRUE
isGlobalCatalogReady: TRUE
domainFunctionality: 0
forestFunctionality: 0
domainControllerFunctionality: 2


======== End of LDAP query response ========

Run the authentication command from the command line adding including the Active Directory user name.  In this example, the user is bruno and the password is mypassw0rd:

c:\PortQryV2>p4auth_ad.exe localhost 389 CN=GABRIEL,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=foo,DC=com bruno
mypassw0rd
Success:  Password verified.exit

The trigger syntax would become

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

Users have reported that in some environments the above trigger does not properly handle users with null passwords. In such cases, the trigger below might allow the authentication to complete successfully. 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.

The above triggers do not perform two factor authentication. However, Perforce authentication triggers can be written to support two factor authentication. For more information, see the Perforce blog entry Two Factor Authentication with Perforce.

An alternative to the Port Query tool is the Microsoft NetDiag tool, available from:
Information on using NetDiag can be found here: