Perforce Public Knowledge Base - Setting Up External Authentication Triggers
Reset Search
 

 

Article

Setting Up External Authentication Triggers

« Go Back

Information

 
Problem

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

Solution

External Authentication with Perforce 2014.2 and later

SASL

The easiest way to set up external authentication is by using SASL.  The Active Diretory

  1. Create an LDAP template
p4 ldap saslconfig

and change the template

Name:   saslconfig
Host:   10.20.30.40
Port:   389
Encryption:     none
BindMethod:     sasl
SearchScope:    subtree
GroupSearchScope:       subtree


where 10.20.30.40 is replaced with the IP address of the Active Directory server.
  1. Test that authentication works first before affecting other users
p4 ldap -t username saslconfig
 
The username may or may not need to be the Active Directory full name in quotes.
  1. Set configurables

p4 configure set auth.default.method=ldap
p4 configure set auth.ldap.order.1=saslconfig

  1. Restart the Perforce server

Check the users

p4 users

  1. Verify that Active Directory is in use

Log into Perforce with a different Active Directory user and check if the new user now appears in p4 users.

p4 -u ADuser login
p4 users

Simple

The simple method requires knowledge of the distinguished name.

p4 ldap mysimple

and change the template

Name:   mysimple
Host:   10.20.30.40
Port:   389
Encryption:     none
BindMethod:     simple
SimplePattern:  CN=%user%,CN=Users,DC=ad,DC=foo,DC=com
SearchScope:    subtree
GroupSearchScope:       subtree

where 10.20.30.40 is replaced with the IP address of the Active Directory server.  Use a tool like Sysinternals Active Directory Explorer and select one user on the left pane.  This tool shows the distinguishedName in the right panel.  Substitute the variable %user% in place of the name.

ADExplorer screenshot 

Search

The search method logs into Active Directory as a particular user and uses a standard LDAP query to filter results down to one user to log in.  A look through Active Directory Explorer shows that there are multiple ways to filter for the user.  In this example, we are using the username bruno and bruno's password to gain access to Active Directory, and then we'll search the sAMAccountName fields seen in the right pane of Active Directory Explorer.

Name:   mysearch
Host:   10.20.30.40
Port:   389
Encryption:     none
BindMethod:     search
SearchBaseDN:   CN=Users,DC=ad,DC=foo,DC=com
SearchFilter:   (sAMAccountName=%user%)
SearchScope:    subtree
SearchBindDN:   bruno@ad.perforce.com
SearchPasswd:   stdpasswd
GroupSearchScope:       subtree


Or alternatively, you can use your LDAP query to filter using the CN field seen in the right pane of
Active Directory Explorer.

Name:   mysearch2
Host:   10.0.10.8
Port:   389
Encryption:     none
BindMethod:     search
SearchBaseDN:  CN=Users,DC=ad,DC=perforce,DC=com
SearchFilter:   (CN=%user%)
SearchScope:    subtree
SearchBindDN:   bruno@ad.foo.com
SearchPasswd:   stdpasswd
GroupSearchScope:       subtree


Troubleshooting LDAP queries

Use ldifde to check whether the LDAP query to place into SearchFilter is correct. 

For example, we use distinguishedName and (CN=*) to search for all the CN entries.

c:\program files\perforce\server>ldifde -d "CN=Users,DC=ad,DC=foo,DC=com" -
f output.txt -r "(CN=*)"
Connecting to "ts-vm.ad.foo.com"
Logging in as current user using SSPI
Exporting directory to file output.txt
Searching for entries...
Writing out entries...............................
31 entries exported

The command has completed successfully

Here we run the query with a particular user and password, useful for entering the username and password when choosing the search method.

c:\program files\perforce\server>ldifde -a perforce stdpasswd -d "CN=Users,DC=ad,DC=foo,DC=com" -f output.txt -r "(CN=*)"
Connecting to "ts-vm.ad.foo.com"
Logging in as "bruno" using simple bind
Exporting directory to file output.txt
Searching for entries...
Writing out entries...............................
31 entries exported

The command has completed successfully

The LDAP query will use a filter to narrow LDAP to find one particular user.  This user will become %user% in the proper LDAP query syntax.  In this example, our filter in LDAP query syntax is "(CN=smith)" to filter to this one name.
  
c:\program files\perforce\server>
c:\program files\perforce\server>ldifde -d "CN=Users,DC=ad,DC=foo,DC=com" -f output.txt -r "(CN=smith)"
Connecting to "ts--vm.ad.foo.com"
Logging in as current user using SSPI
Exporting directory to file output.txt
Searching for entries...
Writing out entries.
1 entries exported
The command has completed successfully
c:\program files\perforce\server>


If this works, we can replace "smith" with the variable "%user%" in the p4 ldap form.  If commands like ldifde do not work properly outside of Perforce, it is unlikely that Perforce ldap authentication will work either.

More information is documented in Authenticating against LDAP servers


External Authentication with Perforce 2014.1 and earlier

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

This article is for administrators who want to authenticate Perforce users against an external data source such as Active Directory or 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 Debugging Triggers for additional information on using triggers in Perforce.

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.

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.

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 authentication trigger problem, please use the p4d -xf 18362 flag or contact support@perforce.com for assistance with restoring access to the Perforce server.
 

Auth-check and Auth-set

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.

Important notes:

  • The auth-check trigger is also required to check old passwords before new external passwords can be set. As such, you cannot have an auth-set trigger without a working auth-check trigger.
  • 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.
  • 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).
  • 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.

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.

Installing an Active Directory Trigger

  1. Either:
    Download ad-auth-check.ps1 (a PowerShell script) from the public depot. This simply requires the Active Directory username, and may be the easiest trigger to install and get working - but if it doesn't work for you then try the alternatives below. For detailed requirements, please see the comments in the script itself.

    Or:
    Download the active directory executable. 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.

  2. To find the proper parameters to use, download the Port Query tool from Microsoft at this link:

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

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

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

    Once the Port Query is obtained, find the serverName line

    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.FOO.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 ========
    
    
    
  3. Run the authentication command from the command line adding including the serverName and a typical Active Directory user name. In this example, the user is bruno and the password is mypassw0rd. Note that there will not be a prompt; after pressing enter, type in the password, then press enter again.
     
    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.
    

    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%"
    

    If the above executables do not work, try the no_null executable alternative listed below. Sometimes a more simplified syntax works such as

    ./p4auth_ad 10.12.21.125 389 OU=LA,DC=p4test,DC=com
    
    
  4. Place the command into the triggers table.
    "p4 triggers" from the command line
     
    p4 triggers
                    
    and add a line similar to below:
    ad auth-check auth "c:/p4auth_ad.exe localhost 389 CN=Users,DC=test,DC=perforce,DC=com %user%"

    where the path to the p4auth executable is specified, the parameters from Port Query determine the arguments, and %user% is substituted for the user name.
  1. Restart the Perforce server.
If authentication does not work after a restart and you need to log in, run p4d with the 18362 flag as shown below.
cd <Perforce root> p4d -r . -xf 18362 "echo 0"
 

No-null Executable Alternative

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"


Two Factor Authentication

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.

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.

Perl Examples

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:


Custom Script

You can also write a custom script to perform authentication. 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.


LDAP example

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
Related Links

Feedback

 

Was this article helpful?


   

Feedback

Please tell us how we can make this article more useful.

Characters Remaining: 255