ED-Auth exists to provide an easy means for applications to do simple PID/password authentication and role based authorization (student, faculty, staff, etc.). The ablility to support LDAPv3 over SSL/TLS (ldaps or ldap with startTLS) is the only thing required for connecting to ED-Auth. See the ED-Auth FAQ for common questions about ED-Auth.
ED-Auth offers simple PID/password authentication plus the ability to authorize on a user's affiliation with Virginia Tech.
The basic steps to authenticate against ED-Auth are:
The basic steps to authorize against ED-Auth are:
(eduPersonAffiliation=VT-ACTIVE-MEMBER)), or search for the person and cycle through the eduPersonAffiliations, looking for a match. (compare is recommended)Middleware provides two directories for authentication and authorization purposes. Before you begin the process of interfacing your system with ED-Auth or ED-ID (or both!), you must first consider which system better suits your needs. Both ED-Auth and ED-ID support authentication and provide authorization data, however, ED-ID provides much more authorization data. Below are some criteria to help you decide which system will work best for you. Please note you may have to ask the vendor of your product whether it has some of the functionality listed below.
Use ED-Auth if:
AND
OR
Use ED-ID if:
AND
OR
OR
Some applications may even be able to support the usage of both directories. If this is the case, it is strongly recommended that you use ED-Auth for authentication and use ED-ID for the lookup of data pertaining to a person. This guarantees fast response times on authentication requests and allows access to all the information about a person that has been collected for placement in the directory.
The following information is taken from the Person Affiliations Explained document. Please refer to this document for more information.
The eduPersonPrimaryAffiliation attribute is an attribute used to communicate, to other institutions, the most basic affiliation a person has with Virginia Tech. This attribute is used in conjunction with systems like Shibboleth* to allow other universities to make authorization decisions about this person. This attribute should NEVER be used by internal Virginia Tech systems for purposes of authorization, it is strictly meant as an external, to VT, facing attribute.
The eduPersonAffiliation attribute gives all the affiliations a person associated with Virginia Tech has with the university. This attribute is meant to be used by internal applications, and will often be used in authorization logic. It is vitally important to realize that this attribute can, and almost always will, have more than one value, which is a change from the current affiliation tracking systems.
The following steps are required for all Java applications that talk to ED-Auth. Only JDK versions 1.5 and greater are supported.
keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file $PATH_TO/cacert.pem
The following steps are optional, but may provide additional functionality or better performance in some cases.
The BC cryptographic provider has a number of additional ciphers compared to the default JSSE provider. For example the AES cipher is provided in 3 flavors (AESEngine, AESFastEngine, AESLightEngine) to allow optimization for performance versus resource consumption, so the use of these features of BC can improve application performance accordingly. Additionally, the implementation of the common ciphers is arguably better.
security.provider.1=sun.security.provider.Sun security.provider.2=com.sun.crypto.provider.SunJCE security.provider.3=sun.security.jgss.SunProvider security.provider.4=org.bouncycastle.jce.provider.BouncyCastleProvider security.provider.5=com.sun.net.ssl.internal.ssl.Provider security.provider.6=com.sun.rsajca.Provider
If problems persist after following these instructions it is useful to verify that your JVM is configured properly.
To do so, add the following switch when starting the JVM:
java -Djavax.net.debug=ssl ...
This will provide a trace of the SSL negoitation and verification of the keystores that the JVM is configured to use.
This switch is not recommmended for production use.
The following example uses JNDI to communicate with ED-Auth over an explicit TLS connection.
import java.io.IOException; import java.util.Hashtable; import java.util.ArrayList; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttributes; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; import javax.naming.ldap.StartTlsRequest; import javax.naming.ldap.StartTlsResponse; public class EdAuthTlsExample { public static void main(String[] args) { if (args.length < 2) { System.err.println("USAGE: EdAuthSslExample uupid pass"); return; } String hostName = "ldap://authn.directory.vt.edu"; String baseDn = "ou=People,dc=vt,dc=edu"; String pid = args[0]; String credential = args[1]; // Set up JNDI context for an anonymous search for uupid Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, hostName); env.put("java.naming.ldap.version", "3"); LdapContext ctx = null; StartTlsResponse tls = null; try { ctx = new InitialLdapContext(env, null); // Authentication must be performed over a secure channel tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest()); tls.negotiate(); // Perform anonymous lookup of user DN based on uupid attribute BasicAttributes attrs = new BasicAttributes("uupid", pid); String[] retAttrs = new String[] { "dn" }; NamingEnumeration ne1 = ctx.search(baseDn, attrs, retAttrs); SearchResult pidSearchResult = (SearchResult) ne1.next(); if (pidSearchResult == null) { System.out.println(pid+" not found in ED-Auth"); return; } String userDn = pidSearchResult.getNameInNamespace(); System.out.println("Found user DN "+userDn); // Authenticate the user and search for privileged attributes // belonging to authenticated user ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDn); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, credential); ctx.reconnect(null); NamingEnumeration ne2 = ctx.search(baseDn, attrs); while (ne2.hasMore()) { SearchResult sr = (SearchResult) ne2.next(); NamingEnumeration attributes = sr.getAttributes().getAll(); while (attributes.hasMore()) { Attribute attr = (Attribute) attributes.next(); System.out.println(attr.getID()); NamingEnumeration values = attr.getAll(); while (values.hasMore()) { System.out.println("\t" + values.next()); } } } } catch (IOException e) { System.err.println("TLS negotiation error:"); e.printStackTrace(); } catch (NamingException e) { System.err.println("JNDI error:"); e.printStackTrace(); } finally { if (tls != null) { try { // Tear down TLS connection tls.close(); } catch (IOException e) { System.err.println("Error tearing down TLS connection."); } } if (ctx != null) { try { // Close LDAP connection ctx.close(); } catch (NamingException e) { System.err.println("Error closing JNDI context."); } } } } }
As an alternative to explicitly managing TLS, for ED-Auth it is sufficient to specify “ssl” for the Context.SECURITY_PROTOCOL initial environment parameter to establish a TLS connection. Since ED-Auth is intended for the authentication/authorization use case where all operations need to be performed over a secure channel, an implicit TLS connection may be preferable.
Requires the Middleware EDLdap Library
Download the Middleware EDLdap example
Line 1 import the EdAuth library
Lines 13-15 initialize variables
Line 17 initialize ED-Auth object
Line 18 authenticate and authorize the user
Lines 19-25 get affiliations and print them out
1 import edu.vt.middleware.ldap.ed.EdAuth; 2 3 /** 4 * <p> 5 * EdAuthLibTest provides a test for the EdAuth class. 6 * </p> 7 */ 8 public final class EdAuthLibTest 9 { 10 public void doTest() 11 throws Exception 12 { 13 String uupid = "UUPID"; 14 String credential = "PASSWORD"; 15 String filter = "AUTHORIZATION FILTER"; 16 17 final EdAuth auth = new EdAuth(); 18 if (auth.authenticateAndAuthorize(uupid, credential, filter)) { 19 System.out.println("Primary affiliation: "+ 20 auth.getPrimaryAffiliation(uupid, credential)); 21 final String[] affil = auth.getAffiliations(uupid, credential); 22 System.out.println("Affiliations: "); 23 for (int i = 0; i < affil.length; i++) { 24 System.out.println(" "+affil[i]); 25 } 26 } else { 27 System.out.println("Authentication or Authorization failed"); 28 } 29 } 30 31 public static void main(final String[] args) 32 throws Exception 33 { 34 final EdAuthLibTest test = new EdAuthLibTest(); 35 test.doTest(); 36 } 37 }
A C/C++ LDAP library supporting LDAP with the startTLS extension is required in order to connect to ED-Auth. These instructions use the OpenLDAP C LDAP library. You must make sure this library is in your applications library path. Please see Appendix: OpenLDAP and Certificates for information on how to set up your environment for SSL/TLS.
Lines 1,2 include necessary headers
Lines 6-21 initialize variables used to connect and perform operations
Lines 23-28 initialize LDAP connection
Lines 30-37 make the LDAP connection use TLS
Lines 39-51 search for the DN for this user
Lines 53-65 get the DN from the search result
Lines 67-75 authenticate the user
Lines 77-86 get this person s record
Lines 88-115 retrieve and print the affiliation information for this user
Lines 117-122 determine if the user has a certain affiliation
Lines 124-127 close the LDAP connection and free used memory
Example compilation: gcc -I/usr/local/openldap/include -L/usr/local/openldap/lib -o ed-auth ed-auth.c -lldap
1 #include <stdio.h> 2 #include <ldap.h> 3 4 int main(int argc, char* argv[]) 5 { 6 LDAP* ldap; 7 LDAPMessage *result, *entry; 8 BerElement* ber; 9 char *HOST_NAME = "authn.directory.vt.edu"; 10 int PORT_NUMBER = 389; 11 char *PASSWORD = "PASSWORD"; 12 char *filter = "(uupid=UUPID)"; 13 char *attrs[] = {"eduPersonPrimaryAffiliation", 14 "eduPersonAffiliation", NULL}; 15 char *base = "ou=People,dc=vt,dc=edu"; 16 char *attribute = NULL; 17 char **values = NULL; 18 char *dn = NULL; 19 char *cmpAttr = "eduPersonAffiliation"; 20 char *cmpVal = "VT-ACTIVE-MEMBER"; 21 int i, resultCode, version; 22 23 /* Initialize an LDAP connection. */ 24 if( (ldap = ldap_init(HOST_NAME, PORT_NUMBER)) == NULL) 25 { 26 perror("ldap_init"); 27 return 1; 28 } 29 30 /* Set the version number so that we may use startTLS. */ 31 version = LDAP_VERSION3; 32 ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); 33 34 if(ldap_start_tls_s(ldap, NULL, NULL) != LDAP_SUCCESS) 35 { 36 ldap_perror(ldap, "ldap_start_tls"); 37 } 38 39 resultCode = ldap_search_ext_s(ldap, base, LDAP_SCOPE_SUBTREE, 40 filter, NULL, 0, NULL, NULL, 41 NULL, LDAP_NO_LIMIT, &result); 42 if(resultCode != LDAP_SUCCESS) 43 { 44 /* another way to print errors... 45 fprintf(stderr, "ldap_search_ext_s: %s\n", 46 ldap_err2string(resultCode)); 47 */ 48 ldap_perror(ldap, "ldap_search_ext_s"); 49 ldap_unbind_ext_s(ldap, NULL, NULL); 50 return 1; 51 } 52 53 entry = ldap_first_entry(ldap, result); 54 if(entry != NULL) 55 { 56 dn = ldap_get_dn(ldap, entry); 57 ldap_msgfree(result); 58 } 59 else 60 { 61 printf("search on filter: %s returned no entries\n", filter); 62 ldap_msgfree(result); 63 ldap_unbind_ext_s(ldap, NULL, NULL); 64 return 1; 65 } 66 67 /* Bind as a user. If PASSWORD is NULL, resultCode will be LDAP_UNWILLING_TO_PERFORM. 68 Always make sure password is not NULL. */ 69 resultCode = ldap_simple_bind_s(ldap, dn, PASSWORD); 70 if(resultCode != LDAP_SUCCESS) 71 { 72 ldap_perror(ldap, "ldap_simple_bind_s"); 73 ldap_memfree(dn); 74 return 1; 75 } 76 77 /* Search for the user. */ 78 resultCode = ldap_search_ext_s(ldap, dn, LDAP_SCOPE_BASE, 79 filter, attrs, 0, NULL, NULL, 80 NULL, LDAP_NO_LIMIT, &result); 81 if( resultCode != LDAP_SUCCESS) 82 { 83 ldap_perror(ldap, "ldap_search_ext_s"); 84 ldap_memfree(dn); 85 return 1; 86 } 87 88 /* Since we are doing a base search, there should be only one 89 matching entry */ 90 entry = ldap_first_entry(ldap, result); 91 if(entry != NULL) 92 { 93 printf("\ndn: %s\n", dn); 94 /* Iterate through each attribute in the entry. */ 95 for( attribute = ldap_first_attribute(ldap, entry, &ber); 96 attribute != NULL; 97 attribute = ldap_next_attribute(ldap, entry, ber)) 98 { 99 /*For each attribute, print the name and values.*/ 100 values = ldap_get_values(ldap, entry, attribute); 101 if( values != NULL) 102 { 103 for(i = 0; values[i] != NULL; i++) 104 { 105 printf("%s: %s\n", attribute, values[i]); 106 } 107 ldap_value_free(values); 108 } 109 ldap_memfree(attribute); 110 } 111 if(ber != NULL) 112 { 113 ber_free(ber, 0); 114 } 115 } 116 117 /* see if user has a specific affiliation */ 118 resultCode = ldap_compare_s(ldap, dn, cmpAttr, cmpVal); 119 if(resultCode == LDAP_COMPARE_TRUE) 120 printf("ldap_compare_s: %s has %s=%s\n", dn, cmpAttr, cmpVal); 121 else 122 printf("ldap_compare_s: %s does not have %s=%s\n", dn, cmpAttr, cmpVal); 123 124 ldap_msgfree(result); 125 ldap_memfree(dn); 126 ldap_unbind_ext_s(ldap, NULL, NULL); 127 return 0; 128 }
Note that in addition to setting up the OpenLDAP Library for certificates (Appendix: OpenLDAP and Certificates), you can do this in the code directly:
char *cacertfile = "/path/to/cachain.pem"; ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, (void *) cacertfile);
This example uses the native Windows LDAP API (WinLDAP) to connect to ED-Auth. Similar code could probably be compiled as a COM object or DLL for use with .Net or VB.
Lines 20-24 include necessary headers
Lines 33-47 initialize variables
Lines 51-57 initialize the LDAP connection
Lines 59-67 use LDAPv3 and SSL
Lines 69-78 connect to ED-Auth
Lines 80-87 search for the UUPID
Lines 89-92 get the DN
Lines 94-100 bind with the supplied credentials
Lines 102-107 determine if the person has the given affiliation
Lines 109-110 clean up
1 /** 2 * winldap-edauth.c 3 * This code is an example of how to connect to ED-Auth, 4 * search for an entry by a person's UUPID, bind as that 5 * UUPID, and then determine if that person is an active 6 * member at VT with the winldap library. 7 * This illustrates the basic authentication/ 8 * authorization ED-Auth is to be used for. 9 * 10 * Notes: * You must have imported the VTCA chain into the 11 * Windows keystore before this code will work properly. 12 * This is available at http://www.pki.vt.edu/developer/rootca.html, 13 * or click on "immediate installation" and run the .exe at 14 * http://www.pki.vt.edu/download/ie6.html. This will 15 * automatically install the CA for you. 16 * 17 * * You must link this against wldap32.lib 18 */ 19 20 #include <windows.h> 21 #include <ntldap.h> 23 #include <winldap.h> 24 #include <stdio.h> 25 26 /** 27 * Search for the DN with the supplied UUPID, bind as that DN with the 28 * given credentials, and then determine if the entry has the 29 * specified affiliation. 30 */ 31 int main(int argc, char* argv[]) 32 { 33 LDAP* ld = NULL; 34 INT retVal = 0; 35 PCHAR pHost = "authn.directory.vt.edu"; 36 int port = 636; 37 char* base = "ou=People,dc=vt,dc=edu"; 38 char* filter = "(uupid=UUPID)"; 39 LDAPMessage *result, *entry; 40 char *dn; 41 char *pass = "PASSWORD"; 42 char *cmpAttr = "eduPersonAffiliation"; 43 char *cmpVal = "VT-ACTIVE-MEMBER"; 44 45 ULONG version = LDAP_VERSION3; 46 SecPkgContext_ConnectionInfo sslInfo; 47 LONG lv = 0; 48 49 printf("\nConnecting to host \"%s\" ...\n",pHost); 50 51 // Create an LDAP session. 52 ld = ldap_sslinit(pHost, port, 1); 53 if (ld == NULL) 54 { 55 printf( "ldap_sslinit failed with 0x%x.\n",GetLastError()); 56 return -1; 57 } 58 59 // Specify version 3; the default is version 2. 60 printf("Setting Protocol version to 3.\n"); 61 retVal = ldap_set_option(ld, 62 LDAP_OPT_PROTOCOL_VERSION, 63 (void*)&version); 64 if (retVal != LDAP_SUCCESS) 65 return 1; 66 67 retVal = ldap_set_option(ld,LDAP_OPT_SSL,LDAP_OPT_ON); 68 69 // Connect to the server. 70 retVal = ldap_connect(ld, NULL); 71 72 if(retVal == LDAP_SUCCESS) 73 printf("ldap_connect succeeded \n"); 74 else 75 { 76 printf("ldap_connect failed with 0x%x.\n",retVal); 77 return 1; 78 } 79 80 // Search for the UUPID 81 retVal = ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, filter, NULL, NULL, &result); 82 83 if(retVal != LDAP_SUCCESS) 84 { 85 printf("ldap_search_s failed with 0x%x.\n",retVal); 86 return 1; 87 } 88 89 // Get the DN 90 entry = ldap_first_entry(ld, result); 91 dn = ldap_get_dn(ld, entry); 92 ldap_msgfree(result); 93 94 // Bind with current credentials. 95 printf("Binding with dn %s...\n", dn); 96 retVal = ldap_bind_s(ld,dn,pass,LDAP_AUTH_SIMPLE); 97 if (retVal != LDAP_SUCCESS) 98 printf("Bind failed with 0x%x.\n", retVal); 99 else 100 printf("Bind as %s succeeded.\n", dn); 101 102 // Determine if this person has the affiliation we want 103 retVal = ldap_compare_s(ld, dn, cmpAttr, cmpVal); 104 if(retVal != LDAP_COMPARE_TRUE) 105 printf("ldap_compare_s failed with 0x%x.\n",retVal); 106 else 107 printf("%s == %s", cmpAttr, cmpVal); 108 109 ldap_memfree(dn); 110 ldap_unbind_s(ld); 111 return 0; 112 }
This document uses the NET::LDAP LDAP module, which in turn requires the IO::Socket::SSL module. If you choose to use a different LDAP module it must be able to support either LDAP over SSL (LDAPS) or LDAP with the startTLS extension.
Lines 3 import the Net::LDAP module
Lines 6-12 declare and initialize variables for use
Lines 14 setup connection to LDAP server
Lines 16-19 make connection use TLS
Lines 21-22 search for the user s DN
Lines 24-28 get person s DN from search result
Lines 30-31 authenticate user
Lines 33-36 search for the person s affiliation information
Lines 38-44 get affiliation information out of search result
Lines 49 close LDAP connection
1 #!/usr/bin/perl 2 3 use Net::LDAP; 4 use strict; 5 6 my $server = "authn.directory.vt.edu"; 7 my $port = 389; 8 my $dn = ""; 9 my $pass = "PASSWORD"; 10 my $cafile = "/PATH/TO/ED_AUTH/CA_file.pem"; 11 my $base = "ou=People,dc=vt,dc=edu"; 12 my $filter = "(uupid=UUPID)"; 13 14 my $ldap = Net::LDAP->new($server, port => $port, version => 3) or die $@; 15 16 my $mesg = $ldap->start_tls(verify => 'require', 17 cafile => $cafile, 18 ciphers => 'RC4-SHA'); 19 $mesg->code && die $mesg->error; 20 21 $mesg = $ldap->search(base => $base, filter => $filter); 22 $mesg->code && die $mesg->error; 23 24 my $entry = $mesg->entry(0); 25 if($entry) 26 { 27 $dn = $entry->dn; 28 } 29 30 $mesg = $ldap->bind( dn => $dn, password => $pass); 31 $mesg->code && die $mesg->error; 32 33 $mesg = $ldap->search(base => $base, filter => $filter, 34 attrs => ['eduPersonPrimaryAffiliation', 35 'eduPersonAffiliation']); 36 $mesg->code && die $mesg->error; 37 38 $entry = $mesg->entry(0); 39 if($entry) 40 { 41 print $entry->get_value('edupersonprimaryaffiliation')."\n"; 42 my $ref = $entry->get_value('edupersonaffiliation', asref => 1); 43 foreach(@{$ref}){ print $_."\n"; } 44 } 45 46 # print all attributes for the entry 47 #foreach $entry ($mesg->all_entries) { $entry->dump; } 48 49 $ldap->unbind;
This example uses python-ldap to communicate with ED-Auth. Since python-ldap is a wrapper around the OpenLDAP libraries, OpenLDAP and OpenSSL are required for this example to work. Certificates can be set up according to Appendix: OpenLDAP and Certificates. See Appendix: Compiling OpenLDAP Libraries for help with compiling the OpenLDAP library. See the INSTALL document bundled with python-ldap for installation instructions (hint: modify setup.cfg to give OpenLDAP and OpenSSL include and library paths).
Line 3 import python-ldap
Lines 5-10 initialize variables
Line 14 initialize thy LDAP connection
Lines 15-16 startTLS on the connection
Line 17 search for the user
Line 18 get result of search
Lines 20-21 get the DN from the search and bind as that user
Lines 22-25 determine if user has the specified eduPersonAffiliation (authorization)
1 #!/usr/bin/python 2 3 import ldap 4 5 base = "ou=People,dc=vt,dc=edu" 6 scope = ldap.SCOPE_SUBTREE 7 searchFilter = "uupid=UUPID" 8 password = "PASSWORD" 9 attribute = "eduPersonAffiliation"; 10 affiliation = "VT-ACTIVE-MEMBER" 11 12 try: 13 # initialize the ldap connection 14 edauth = ldap.initialize("ldap://authn.directory.vt.edu:389") 15 edauth.protocol_version=ldap.VERSION3 16 edauth.start_tls_s() 17 results = edauth.search(base, scope, searchFilter, None) 18 resultType, result_data = edauth.result(results, 0) 19 if result_data: 20 dn = result_data[0][0] 21 edauth.simple_bind_s(dn, password) 22 if edauth.compare_s(dn, attribute, affiliation) == 0: 23 print dn, "does not have", attribute, "=", affiliation 24 else: 25 print dn, "has", attribute, "=", affiliation 26 else: 27 print "UUPID not found" 28 except ldap.LDAPError,e: 29 print str(e)
This example uses PHP to connect to ED-Auth. You must compile PHP with LDAP for this example to work. See Appendix: Compiling OpenLDAP Libraries for instructions on installing OpenLDAP libraries.
You also need to make sure that certificates are set up properly. See Appendix: OpenLDAP and Certificates for instructions.
Lines 3-11 create and initialize variables
Lines 14-24 determine user's DN
Lines 28-41 authenticate and authorize user
Lines 42-53 do a base search on the user's DN and print an attribute (eduPersonAffiliation)
1 <?php 2 3 $host = 'ldap://authn.directory.vt.edu'; 4 $baseDn = 'ou=People,dc=vt,dc=edu'; 5 $userfield = 'uupid'; 6 $pid = 'UUPID'; 7 $credential = 'PASSWORD'; 8 $attr = 'eduPersonAffiliation'; 9 $value = 'VT-ACTIVE-MEMBER'; 10 $groupAttr = 'groupMembership'; 11 $group = 'uugid=department.staff,ou=Groups,dc=vt,dc=edu'; 12 13 /*ldap will bind anonymously, make sure we have some credentials*/ 14 if (isset($pid) && $pid != '' && isset($credential)) { 15 $ldap = ldap_connect($host); 16 ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); 17 if (!@ldap_start_tls($ldap)) { 18 print('Could not start TLS'); 19 } else if (isset($ldap) && $ldap != '') { 20 /* search for pid dn */ 21 $result = @ldap_search($ldap, $baseDn, $userfield.'='.$pid, array('dn')); 22 if ($result != 0) { 23 $entries = ldap_get_entries($ldap, $result); 24 $principal = $entries[0]['dn']; 25 if (isset($principal)) { 26 27 /* bind as this user */ 28 if (@ldap_bind($ldap, $principal, $credential)) { 29 print("Authenticate success\n"); 30 /* determine if the user has the $attr */ 31 if(@ldap_compare($ldap, $principal, $attr, $value) === true) { 32 print("$principal has $attr = $value\n"); 33 } else { 34 print("$principal does not have $attr = $value\n"); 35 } 36 /* determine if the user is in the $group */ 37 if(@ldap_compare($ldap, $principal, $groupAttr, $group) === true) { 38 print("$principal is a member of $group\n"); 39 } else { 40 print("$principal is not a member of $group\n"); 41 } 42 /* Do a base search on the dn to view all 43 eduPersonAffilation(s). */ 44 $r = ldap_read($ldap, $principal, $userfield.'='.$pid); 45 $e = ldap_first_entry($ldap, $r); 46 $attrs = ldap_get_attributes($ldap, $e); 47 print("$attr: \n"); 48 for($i = 0; $i < $attrs[$attr]['count']; 49 $i++) 50 { 51 print("\t".$attrs[$attr][$i]."\n"); 52 } 53 ldap_free_result($r); 54 } else { 55 print('Authenticate failure'); 56 } 57 } else { 58 print('User not found in LDAP'); 59 } 60 ldap_free_result($result); 61 } else { 62 print('Error occured searching the LDAP'); 63 } 64 ldap_close($ldap); 65 } else { 66 print('Could not connect to LDAP at '.$host); 67 } 68 } 69 ?>
note: if you are testing ldaps you must specify a fully qualified URL:
ldap_connect("ldaps://$hostname:$port");
you cannot use:
ldap_connect($hostname, $port);
See the PHP Documentation for ldap_connect().
If your website runs on Hosting, you can only test authentication using the https://secure.hosting.vt.edu URL associated with your website.
If you have magic_quotes_gpc set to On in your php.ini, people with certain special characters (',”,\, for example) in their passwords will be unable to authenticate, as the characters will be escaped. Either set magic_quotes_gpc to Off or use stripslashes() to ensure that these people can authenticate. Note that Hosting currently has this option On.
Here is a simplistic example that shows how to bind with PEAR Net_LDAP:
<?php require_once 'Net/LDAP.php'; $host = 'directory.vt.edu'; $port = 389; $base = 'ou=people,dc=vt,dc=edu'; $uupid = 'UUPID'; $pass = 'PASS'; $config = array ( 'basedn' => $base, 'host' => $host, 'port' => $port, 'starttls' => true); $ldap = Net_LDAP::connect($config); if(Net_LDAP::isError($ldap)) { die('Could not connect to LDAP server: '.$ldap->getMessage()); } $filter = "uupid=$uupid"; $search = $ldap->search($base, $filter); if(Net_LDAP::isError($search)) { die('Could not fetch entry: '.$search->getMessage()); } $entry = $search->entries(); if($entry) { $dn = $entry[0]->dn(); $result = $ldap->bind($dn, $pass); if(Net_LDAP::isError($result)) { die($result->getMessage()."\n"); } else { echo "Authenticate success\n"; } } else { echo "No entries found for uupid = $uupid\n"; } $ldap->done(); ?>
To use this class to connect to ED-Auth you must have the ruby-ldap module compiled against the OpenLDAP and OpenSSL libraries. See Appendix: Compiling OpenLDAP Libraries.
1 # Simple ED-Auth library; requires ruby-ldap built 2 # against OpenLDAP and OpenSSL. 3 # Sam Stephenson <sams@vt.edu> 2004-06-17 4 # Modified a bit by Brad Tilley < rtilley@vt.edu> 2006-12-13 5 6 require 'ldap' 7 8 class NotAuthenticatedError < Exception 9 end 10 11 class EdAuth 12 HOST, PORT = 'authn.directory.vt.edu', 389 13 DN, FILTER = 'ou=People,dc=vt,dc=edu', '(uupid=%s)' 14 15 def initialize(pid, pass) 16 @ldap = LDAP::SSLConn.new(HOST, PORT, true) 17 @authenticated = false 18 @pid, @pass = pid, pass 19 @dn, @filter = DN, format(FILTER, pid) 20 21 @authenticity = false 22 @pri_affil, @affil = nil, nil 23 end 24 25 def authenticate 26 return @authenticity if @authenticated 27 begin 28 @ldap.search(@dn, LDAP::LDAP_SCOPE_ONELEVEL, 29 @filter) {|c| @dn = c.get_dn} 30 @ldap.bind(@dn, @pass) 31 @authenticity = true 32 rescue LDAP::ResultError 33 @authenticity = false 34 ensure 35 @authenticated = true 36 end 37 @authenticity 38 end 39 40 def get_primary_affiliation 41 query if @pri_affil.nil? 42 puts @pri_affil 43 @pri_affil 44 end 45 46 def get_affiliations 47 query if @affil.nil? 48 puts @affil 49 @affil 50 end 51 52 def close 53 begin 54 @ldap.unbind 55 rescue LDAP::InvalidDataError 56 end 57 end 58 59 private 60 def query 61 raise NotAuthenticatedError unless @authenticated and 62 @authenticity 63 @ldap.search(@dn, LDAP::LDAP_SCOPE_SUBTREE, @filter, 64 ['eduPersonPrimaryAffiliation', 65 'eduPersonAffiliation']) do |entry| 66 @pri_affil = 67 entry.get_values('edupersonprimaryaffiliation').shift 68 @affil = entry.get_values('edupersonaffiliation') 69 end 70 end 71 end 72 73 x = EdAuth.new('your_pid', 'your_password') 74 x.authenticate 75 x.get_primary_affiliation 76 x.get_affiliations 77 x.close
Please note you must accept PID/password credentials securely. Since these credentials are given to the Apache server using HTTP Basic Auth, this means that all your restricted resources must be served over an SSL (HTTPS) encrypted connection. Failure to do so is a violation of the ED Usage Requirements.
These instructions require the OpenSSL, mod_ssl, OpenLDAP, and auth_ldap libraries. Links to these are provided in the resource appendix. You must have these libraries available to Apache for this to work (See Appendix: Compiling OpenLDAP Libraries for help). These instructions do not describe how to compile Apache, OpenSSL, or mod_ssl. Please refer to the documentation included with those individual programs for compilation instructions.
1. Compile Apache with SSL support. Be sure to enable loadable module support.
2. Compile OpenLDAP with SSL/TLS support (Appendix: Compiling OpenLDAP Libraries)
3. Compile auth_ldap. Here is the configuration we use, obviously some of the paths may be different on your machine:
./configure --with-apxs=../apache/bin/apxs \\
--with-ldap-sdk=openldap \\
--with-sdk-headers=/usr/local/openldap/include \\
--with-sdk-libs=/usr/local/openldap/lib \\
4. Compile and install via make and make install
5. Add the following directive into your httpd.conf file so that Apache loads the auth_ldap module:
LoadModule auth_ldap_module libexec/auth_ldap.so
6. Add the following directives, within a <Directory> directive, into your httpd.conf file for Apache:
AuthLDAPURL ldap://authn.directory.vt.edu:389/ou=People,dc=vt,dc=edu?uupid AuthLDAPStartTLS on AuthType Basic AuthName "Virginia Tech ED-Auth (PID/pass)" require valid-user
7. Download the VT CA Chain, also available from VT Middleware CA.
8. Add the following line to your ldap.conf file, usually found at $OPENLDAP_HOME/etc/openldap/ldap.conf
(see Appendix: OpenLDAP and Certificates for more ways to set up your trusted certificates):
TLS_CACERT /path/to/cert/download/above/cert.pem
1. Compile OpenLDAP with SSL/TLS support (Appendix: Compiling OpenLDAP Libraries)
2. Configure Apache with support for LDAP authentication, here is the configuration we use:
CPPFLAGS=-I/path/to/openldap/include \
LDFLAGS=-L/path/to/openldap/lib \
./configure --enable-ssl \
--with-ldap \
--enable-ldap=shared \
--enable-auth-ldap=shared \
--prefix=/location/to/install/apache
3. Compile and install Apache with make and make install.
4. Add the following configuration to your httpd.conf file:
LDAPTrustedCA /path/to/CA.pem LDAPTrustedCAType BASE64_FILE <Directory /some/directory > AuthType Basic AuthName "Virginia Tech ED-Auth (PID/pass)" AuthLDAPURL ldaps://authn.directory.vt.edu:636/ou=People,dc=vt,dc=edu?uupid require valid-user </Directory>
1. Compile OpenLDAP with SSL/TLS support (Appendix: Compiling OpenLDAP Libraries)
2. Configure Apache with support for LDAP authentication, here is the configuration we use:
CPPFLAGS=-I/path/to/openldap/include \
LDFLAGS=-L/path/to/openldap/lib \
./configure --enable-ssl \
--with-ldap \
--enable-ldap=shared \
--enable-authnz-ldap=shared \
--prefix=/location/to/install/apache
3. Compile and install Apache with make and make install.
4. Add the following configuration to your httpd.conf file:
LDAPTrustedGlobalCert CA_BASE64 /path/to/CA.pem <Directory /some/directory > AuthType Basic AuthBasicProvider ldap AuthzLDAPAuthoritative Off AuthName "Virginia Tech ED-Auth (PID/pass)" AuthLDAPURL ldaps://authn.directory.vt.edu:636/ou=People,dc=vt,dc=edu?uupid require valid-user </Directory>
Sometimes it is desirable to use both ED-Auth and some form of local authentication together. The following is an example of how to use Apache's password files.
LDAPTrustedGlobalCert CA_BASE64 /path/to/CA.pem <Directory /some/directory > AuthType Basic AuthBasicProvider ldap file AuthUserFile /path/to/apache.passwd AuthzLDAPAuthoritative Off AuthName "Virginia Tech ED-Auth (PID/pass)" AuthLDAPURL ldaps://authn.directory.vt.edu:636/ou=People,dc=vt,dc=edu?uupid require valid-user </Directory>
The AuthBasicProvider directive sets the order of auth modules to attempt to use. In this case it uses file-based auth with apache.passwd if the user is not found in the LDAP.
Note: If you reverse the order of the modules in AuthBasicProvider, you will be able to override users that exist in the LDAP in the password file. This is probably not desirable, and you should ensure that the Apache password file is properly protected.
The Tomcat Servlet container can be configured to use the EdAuthRealm provided by the Middleware EDLdap Library to provide container-based authentication and authorization.
Integration steps:
Template server.xml file for configuring an ED-Auth container authentication realm.
<Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" /> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" descriptors="/edu/vt/middleware/ldap/catalina/mbeans/mbeans-descriptors.xml"/> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/> <!-- Global JNDI resources --> <GlobalNamingResources> <!-- Add EdAuth Database as global resource --> <Resource name="EdAuthDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="EdAuth role database" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/edauth-users.xml" /> </GlobalNamingResources> <!-- Define the Tomcat Stand-Alone Service --> <Service name="Catalina"> <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" /> <!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /> <!-- Define the top level container in our container hierarchy --> <Engine name="Catalina" defaultHost="localhost"> <!-- Because this Realm is here, an instance will be shared globally --> <!-- Add EdAuth Realm to this Engine --> <Realm className="edu.vt.middleware.ldap.catalina.realm.EdAuthRealm"/> <!-- Define the default virtual host Note: XML Schema validation will not work with Xerces 2.2. --> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host> </Engine> </Service> </Server>
EdAuthRealm also supports container-based authorization. Simply specify an <auth-constraint> in the <security-constraint> section of the application web.xml to authorize users based on their membership in a given ED group. The following example requires the authenticated user to be a member of the middleware.staff ED group to access protected resources.
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> ... <security-role> <description>ED group describing the administrative role.</description> <role-name>middleware.staff</role-name> </security-role> ... <security-constraint> <web-resource-collection> <web-resource-name>Protected Resources</web-resource-name> <url-pattern>/protected/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>middleware.staff</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> ... </web-app>
PAM LDAP gives Unix and Linux machines the ability to authenticate against an LDAP server such as ED-Auth. PAM is highly tunable and powerful, and allows administrators to determine how services (login, xdm, ssh, etc.) authenticate users. These instructions assume you are compiling from source, but you are free to use your favorite distribution's package at your own risk.
1. Download PAM LDAP.
2. Configure pam_ldap: (see Appendix: Compiling OpenLDAP Libraries for OpenLDAP dependency)
./configure --prefix=/path/to/pam_ldap \
--with-ldap=/path/to/openldap \
--with-ldap-lib=openldap
3. In your /etc/ldap.conf1), add the following:
base ou=People,dc=vt,dc=edu uri ldap://authn.directory.vt.edu ldap_version 3 pam_login_attribute uupid ssl start_tls tls_checkpeer yes tls_cacertfile /path/to/cachain.pem
3. Download vt-cachain.pem and put the file in the location you specified in step 3.
4. man pam and read up about the pam.conf configuration file, pam.d, and services.
5. Modify your service rules in /etc/pam.d accordingly, making sure the rules do what you think they do (!!!). (hint: the pam.d directory that comes with the pam_ldap distribution is a good place to look at rules. The login rules file works well.)
pGina is a replacement for the authentication portion of Windows 2000/XP, and allows Windows users to authenticate against ED-Auth. This is especially useful in a lab or similar enviromment where PID/pass authentication is desired.
Plugin tab, and put the path to the LDAPAuth Plugin for the Plugin Path.Configure and fill in the following: If the application you are using to connect to ED-ID or ED-Auth uses the OpenLDAP libraries, it may be necessary to set up the certificates for your client. This is done with the following directives: TLS_CACERT, TLS_CERT, and TLS_KEY. TLS_CACERT refers to the certificate chain used to verify the server. TLS_CERT and TLS_KEY refer to the client certificate and private key, respectively, that are used for TLS client authentication (only used for ED-ID). These directives can be set up in the following ways:
Download the VT Middeware CA chain file
1. Add the following to the OpenLDAP library's ldap.conf. This must be the
ldap.conf that corresponds to the OpenLDAP library you are using for your
application (note that there may be multiple ldap.conf files on your system,
but only one will actually be used by a particular OpenLDAP library).
############# # ldap.conf TLS_CACERT /path/to/cachain.pem ### only needed for ED-ID ### ### NOTE: TLS_CERT and TLS_KEY are user-only attributes, meaning they ### cannot be in ldap.conf, but must be in .ldaprc or ldaprc or environment variables #TLS_CERT /path/to/cert.pem #TLS_KEY /path/to/key.pem #############
This sets up certificates system-wide for the OpenLDAP library.
2. Put the above directives in a file called ldaprc in the user's $HOME
directory that is using the application. This will override the system-wide
settings for the user.
3. Put the above directives in a file called .ldaprc in the user's $HOME
directory that is using the application. This will override the system-wide
settings for the user.
4. Put the above directives in a file called ldaprc in the user's current
working directory ($PWD) that is using the application. This will override
the system-wide settings for the user.
5. Set the following environment variables:
export LDAPCONF=/path/to/ldap.conf OR export LDAPRC=/path/to/ldaprc OR export LDAPTLS_CACERT=/path/to/cachain.pem export LDAPTLS_CERT=/path/to/cert.pem export LDAPTLS_KEY=/path/to/key.pem
These directives are searched for in this order. The last directives set
override any previous directives. For more information on this, see the
ldap.conf manpage for OpenLDAP.
The ldapsearch program distributed with OpenLDAP is a useful tool for testing and debugging your custom application, particularly if it uses the OpenLDAP libraries at some level. Below are examples for how to connect to ED-Auth. Please refer to Appendix: OpenLDAP and Certificates for information on how to set up certificates.
NOTE: Your OpenLDAP libraries must be compiled with SSL support to do this.
To search for a person:
ldapsearch -H ldap://authn.directory.vt.edu -x -Z \
-b ou=People,dc=vt,dc=edu '(uupid=<uupid to search for>)'
To bind as a person:
ldapsearch -H ldap://authn.directory.vt.edu -x -Z \
-b ou=People,dc=vt,dc=edu \
-D uid=<uid to bind as>,ou=People,dc=vt,dc=edu \
-W '(uupid=<uupid to search for>)'
Options Key:
To use LDAPS functionality in PHP on Windows you must create the following file:
c:\OpenLDAP\sysconf\ldap.conf
and place the following line in it:
TLS_CACERT c:\OpenLDAP\sysconf\certs\cachain.pem
Next, place the VT CA Chain in the
c:\OpenLDAP\sysconf\certs\
directory.
Many of the examples contained in this document depend on the OpenLDAP LDAP Libraries for their functionality. This includes the C, Net::LDAP, Python, PHP, Ruby, and Apache examples as well as the standard LDAP utilities such as ldapsearch. This appendix exists to help you compile the libraries needed for your application to interface with ED-Auth.
1. Download the OpenLDAP Software Distribution. The OpenLDAP stable Release is always the best choice to install.
2. Configure OpenLDAP with the following line:
./configure --prefix=/path/to/openldap \
--enable-slapd=no \
--enable-slurpd=no \
--with-tls
If your OpenSSL libraries are not in the standard include and lib paths, you may need to run the following:
CPPFLAGS=-I/path/to/ssl/include LDFLAGS=-L/path/to/ssl/lib \
./configure --prefix=/path/to/openldap \
--enable-slapd=no \
--enable-slurpd=no \
--with-tls
3. make depend && make && make install