|
||
|
|
Chapter 8 Defining Functions for Authentication
This chapter explains how to write a plug-in function to bypass or replace the standard function for authentication with your own function.
Information on authentication with the Netscape Directory Server (Directory Server) is organized in the following sections:
- Understanding Authentication Methods
![]()
- How the Directory Server Identifies Clients
![]()
- How the Authentication Process Works
![]()
- Writing Your Own Authentication Plug-in
![]()
- Writing a Pre-Operation Bind Plug-in
![]()
- Using SASL with an LDAP Client
![]()
Understanding Authentication Methods
Two methods that you can use to authenticate clients are simple authentication and SASL authentication:
- Simple authentication is described in RFC 2251, which you can find at this location:
http://ds.internic.net/rfc/rfc2251.txt![]()
- Simple authentication provides minimal facilities for authentication. In the simple authentication method, clients send a DN and password to the server for authentication. The server compares the password sent by the client against the password stored in the client's directory entry.
- Simple Authentication and Security Layer (SASL) is described in RFC 2222, which you can find at this location:
http://ds.internic.net/rfc/rfc2222.txt![]()
- SASL provides the means to use mechanisms other than simple authentication and SSL to authenticate to the Directory Server.
How the Directory Server Identifies Clients
The server keeps track of the identity of the LDAP client through the
SLAPI_CONN_DNandSLAPI_CONN_AUTHTYPEparameters.During an LDAP bind operation, the server authenticates the user and puts the DN and authenticated method in the
SLAPI_CONN_DNandSLAPI_CONN_AUTHTYPEparameters.When an authenticated client requests the server to perform an LDAP operation, the server checks the DN in the
SLAPI_CONN_DNparameter to determine if the client has the appropriate access rights.How the Authentication Process Works
When the Directory Server receives an LDAP bind request from a client, it processes the request in the following steps:
- The server parses the LDAP bind request and retrieves the following information:
![]()
- The DN that the client is attempting to authenticate as
![]()
- The method of authentication used
![]()
- Any credentials (such as a password) included in the request
![]()
- If the method of authentication is
LDAP_AUTH_SASL(SASL authentication), the server also retrieves the name of the SASL mechanism used from the LDAP bind request.
- The server normalizes the DN retrieved from the request. (See the
slapi_dn_normalize()function for more information on normalized DNs.)![]()
- The server retrieves any LDAP v3 controls included with the LDAP bind request.
![]()
- If the method of authentication is
LDAP_AUTH_SASL(SASL authentication), the server determines whether or not the SASL mechanism (specified in the request) is supported.![]()
- If the SASL mechanism is not supported by the server, the server sends an
LDAP_AUTH_METHOD_NOT_SUPPORTEDresult code back to the client and ends the processing of the bind request.
- If the method of authentication is
LDAP_AUTH_SIMPLE(simple authentication), the server checks if the DN is an empty string or if there are no credentials.![]()
- If the DN is an empty string, if the DN is not specified, or if no credentials are specified, the server assumes that the client is binding anonymously and sends an
LDAP_SUCCESSresult code back to the client.
- The DN and authentication method for the connection (which are used to determine access rights for all operations performed through the connection) are left as NULL and
SLAPD_AUTH_NONE, respectively.
- If the DN specified in the request is not served by this Directory Server (for example, if the DN is
"uid=moxcross, o=netscape.com"and the directory root of the server is"o=example.com"), the server sends one of the following two results back to the client and ends the processing of the bind request:![]()
- If the server is configured with a default referral (an LDAP URL identifying an LDAP server that handles referrals), the server sends an
LDAP_REFERRALresult code back to the client (LDAP_PARTIAL_RESULTSif the client only supports the LDAP v2 protocol).![]()
- If the server is not configured with a default referral, the server sends an
LDAP_NO_SUCH_OBJECTresult code back to the client.![]()
- The server puts the information from the bind request into the parameter block:
![]()
SLAPI_BIND_TARGETis set to the DN that the client is authenticating as.![]()
SLAPI_BIND_METHODis set to the authentication method (for example,LDAP_AUTH_SIMPLEorLDAP_AUTH_SASL).![]()
SLAPI_BIND_CREDENTIALSis set to the credentials (for example, the password) included in the request.![]()
SLAPI_BIND_SASLMECHANISM(if the authentication method isLDAP_AUTH_SASL) is set to the name of the SASL mechanism that the client is using for authentication.![]()
- If the DN is the root DN or the update DN (the DN of the master entity responsible for replicating the directory), the server authenticates the client.
![]()
- If the credentials are correct, the server sets the
SLAPI_CONN_DNparameter to the DN and the SLAPI_CONN_AUTHTYPE parameter toLDAP_AUTH_SIMPLE. The server sends anLDAP_SUCCESSresult code back to the client and ends the processing of the bind request.![]()
- If the credentials are incorrect, the server sends an
LDAP_INVALID_CREDENTIALSresult code back to the client and ends the processing of the bind request.![]()
- The server calls any pre-operation bind plug-in functions. If the function returns a non-zero value, the server ends the processing of the bind request.
![]()
- If you are writing your own plug-in function to handle authentication, you should return a non-zero value so that the server does not attempt to continue processing the bind request.
- The server calls the backend bind function. The bind function returns one of the following values:
![]()
- If the function returns a non-zero value (
SLAPI_BIND_FAIL_OR_ANONYMOUSin Netscape Directory Server 4.x), the server ends the processing of the bind request. The bind function is responsible for sending the appropriate result code back to the client before returning a non-zero value.![]()
- If the function returns 0 (
SLAPI_BIND_SUCCESSin Netscape Directory Server 4.x), the server continues processing the bind request. The server sends theLDAP_SUCCESSresult code back to the client. (The bind function does not do this.)![]()
- If the backend bind function succeeds, the server sets the
SLAPI_CONN_DNparameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to the authentication method.![]()
- The server sends an
LDAP_SUCCESSresult code back to the client and ends the processing of the bind request.![]()
- If the client's password is going to expire, the server includes a "password expiring" control (with the OID 2.16.840.1.113730.3.4.5) with the result sent to the client. If the client is logging in for the first time and needs to change the password, the server includes a "password expired" control (with the OID 2.16.840.1.113730.3.4.4) with the result sent to the client.
Writing Your Own Authentication Plug-in
A situation may arise in which you may want to write and implement your own function for authentication; that is, replace the standard means of authentication with your own function. You can write a pre-operation bind plug-in function (a function that the server calls before processing an LDAP bind request) that performs the authentication and bypasses the default bind functionality. For details, see the next section, Writing a Pre-Operation Bind Plug-in.
Writing a Pre-Operation Bind Plug-in
You can define your own pre-operation bind plug-in function to authenticate LDAP clients. The server will call your function during the authentication process (in Step 9). Your function should return a non-zero value to bypass the default backend bind function and the post-operation bind functions.
Note that this means that Step 10 through Step 12 are skipped. Your pre-operation plug-in function is responsible for sending the result code to the client and for setting the DN and authentication method for the connection.
Figure 8-1 summarizes the process of using a pre-operation bind plug-in function to authenticate LDAP clients to the Directory Server.
Figure 8-1 Using a Pre-Operation Bind Plug-In Function to Handle Authentication
![]()
Figure 8-2 illustrates the steps that your pre-operation bind plug-in function must take to authenticate LDAP clients to the Directory Server.
Figure 8-2 How Your Pre-Operation Bind Plug-In Function Can Authenticate LDAP Clients
![]()
Defining Your Authentication Function
The following sections cover guidelines that you can follow when defining your authentication function:
- Getting and Checking the Bind Parameters
![]()
- Getting the Entry and Checking the Credentials
![]()
- What to Do If Authentication Fails
![]()
- What to Do If Authentication Succeeds
![]()
Be sure to check this source file for an example of a pre-operation plug-in function that handles authentication:
<server_root>/plugins/slapd/slapi/examples/testbind.c
Getting and Checking the Bind Parameters
Call the
slapi_pblock_get()function to get the values of the following parameters:
SLAPI_BIND_TARGET(a string value specifying the DN that the client is attempting to authenticate as)![]()
SLAPI_BIND_METHOD(an integer value specifying the authentication method, such asLDAP_AUTH_SIMPLEorLDAP_AUTH_SASL)![]()
SLAPI_BIND_CREDENTIALS(abervalstructure containing the credentials sent by the client)![]()
If you plan to support authentication through SASL mechanisms, you should also get the value of the
SLAPI_BIND_SASLMECHANISMparameter (a string value specifying the name of the SASL mechanism to use for authentication).Make sure to check the following:
- Determine if the client is requesting to bind as an anonymous user.
![]()
- If the
SLAPI_BIND_METHODparameter isLDAP_AUTH_SIMPLEand theSLAPI_BIND_CREDENTIALSparameter is empty or NULL, the client is attempting to bind anonymously.
- Call
slapi_send_ldap_result()to send the LDAP result codeLDAP_SUCCESSback to the client.
- If the
SLAPI_BIND_METHODparameter specifies a method that you do not recognize or support, callslapi_send_ldap_result()to send anLDAP_STRONG_AUTH_NOT_SUPPORTEDresult code back to the client.![]()
In both cases, return a non-zero value to prevent the server from calling the default backend function for authentication.
Getting the Entry and Checking the Credentials
Get the entry for the DN specified by the
SLAPI_BIND_TARGETparameter and compare the credentials in theSLAPI_BIND_CREDENTIALSparameter against the known credentials for that entry.By default, Directory Server 4.x uses the
userpasswordattribute to store the credentials for an entry. The server encodes the password using the scheme specified in thepasswdhashdirective of theslapd.confconfiguration file. The scheme can becryptorshaor" " (for cleartext).By default, Directory Server 6.x uses the
userpasswordattribute to store the credentials for an entry. The server encodes the password using the scheme specified in thensslapd-rootpwstorageschemeorpasswordStorageSchemeattributes of thecn=configentry contained in thedse.ldiffile. The scheme can be any of the following:
CLEAR(means no encryption and can be defined using theclear-password-storage-schemeplug-in)![]()
CRYPT(means Unix crypt algorithm and can be defined using thecrypt-password-storage-schemeplug-in)![]()
SHA(means Secure Hashing Algorithm and can be defined using thesha-password-storage-schemeplug-in)![]()
SSHA(means Salted Secure Hashing Algorithm and can be defined using thessha-password-storage-schemeplug-in)![]()
If you need to compare the client's credentials against the value of the
userpasswordattribute, you can call theslapi_pw_find_sv()function. This function determines which password scheme was used to store the password and uses the appropriate comparison function to compare a given value against the encrypted value of theuserpasswordattribute.What to Do If Authentication Fails
If authentication fails, send one of the following result codes back to the client:
- If no entry matches the DN specified by the client, send an
LDAP_NO_SUCH_OBJECTresult code back to the client.![]()
- When calling the
slapi_send_ldap_result()function to send the result code back to the client, specify the closest matching DN as thematchedargument.
- If the client fails to provide the necessary credentials or if credentials cannot be found in the entry, send an
LDAP_INAPPROPRIATE_AUTHresult code back to the client.![]()
- If the credentials specified by the client do not match the credentials found in the entry, send an
LDAP_INVALID_CREDENTIALSresult code back to the client.![]()
- If a general error occurs, send an
LDAP_OPERATIONS_ERRORresult code back to the client.![]()
Your function should also return a non-zero value (
SLAPI_BIND_FAIL_OR_ANONYMOUSin Netscape Directory Server 4.x).You do not need to set any values for the
SLAPI_CONN_DNparameter and theSLAPI_CONN_AUTHTYPEparameter. By default, these parameters are set to NULL andLDAP_AUTH_NONE, which indicate that the client has bound anonymously.What to Do If Authentication Succeeds
If the authentication is successful, your authentication function should do the following:
- Call
slapi_pblock_set()to set the values of theSLAPI_CONN_DNparameter and theSLAPI_CONN_AUTHTYPEparameter to the DN and authentication method.![]()
- This sets the DN and authentication method for the connection to the client. (The server uses this DN and method in subsequent operations when checking access rights.)
- You can set
SLAPI_CONN_AUTHTYPEto one of the following values:
SLAPD_AUTH_NONErepresents no authentication. (The client is binding anonymously.)![]()
SLAPD_AUTH_SIMPLErepresents the simple authentication method.![]()
SLAPD_AUTH_SSLrepresents authentication through SSL.![]()
SLAPD_AUTH_SASLrepresents SASL authentication.![]()
- Note that these values differ from the values in the
SLAPI_BIND_METHODparameter. The values listed above are string values defined in theslapi-plugin.hheader file, whereas the values of theSLAPI_BIND_METHODparameter (such asLDAP_AUTH_SIMPLEandLDAP_AUTH_SASL) are integer values defined in theldap.hheader file.
- If you want to, specify the credentials that you want sent back to the client.
![]()
- If the value of the
SLAPI_BIND_METHODparameter isLDAP_AUTH_SASLand you want to return a set of credentials to the client, callslapi_pblock_set()to set theSLAPI_BIND_RET_SASLCREDSparameter to the credentials.
- Send the result of the authentication process back to the client.
![]()
- Call
slapi_send_ldap_result()to send anLDAP_SUCCESSreturn code to the client.
Make sure that your function returns a non-zero value to bypass the default backend bind function and any post-operation plug-in functions.
Registering the SASL Mechanism
If you are using SASL as the authentication method, you need to register the SASL mechanisms that you plan to use.
In your initialization function (see Writing Plug-in Initialization Functions), call the
Functions for Syntax Plug-Infunction and specify the name of the SASL mechanism. For example:slapi_register_supported_saslmechanism( "babsmechanism" );
Note that if you do not register your SASL mechanism, the Directory Server will send an
LDAP_AUTH_METHOD_NOT_SUPPORTEDresult code back to the client and will not call your pre-operation bind function.
Be sure to check this source file for an example of a pre-operation plug-in function for SASL authentication with LDAP bind operations:
<server_root>/plugins/slapd/slapi/examples/testsaslbind.c
Example of a Pre-Operation Bind Plug-In
The following sections document an example of a pre-operation bind plug-in that handles authentication:
- Example of a Pre-Operation Bind Function
![]()
- Example of an Initialization Function
![]()
- Registering the Plug-In
![]()
Be sure to check this source file for an updated example of a pre-operation plug-in function that handles authentication:
<server_root>/plugins/slapd/slapi/examples/testbind.c
Example of a Pre-Operation Bind Function
The following is an example of a pre-operation bind function that authenticates clients and bypasses the default backend bind function. In this example, the function just compares the client's credentials against the value of the
userpasswordattribute for the entry.
Example of an Initialization Function
To initialize your plug-in, write an initialization function to do the following:
- Call
slapi_pblock_set()to set theSLAPI_PLUGIN_PRE_BIND_FNparameter to the name of your pre-operation bind function. (For details, see Registering Your Plug-In Functions.)![]()
- If you are using SASL as the authentication method, call the
Functions for Syntax Plug-Infunction to register your SASL mechanism with the Directory Server.![]()
The following is an example of an initialization function that registers the pre-operation bind function.
To register the plug-in, follow the instructions appropriate for the Directory Server you're using:
- In Directory Server 4.x, add the
plugin preoperationdirective to the end of theslapd.ldbm.conffile, which is located in the<server_root>/slapd-<instance_id>/configdirectory:![]()
plugin preoperation on "my preop plugin" /<server_root>/plugins/slapd/slapi/examples/libtest-plugin.so testauth_init
- Note that each pre-operation and post-operation plug-in is associated with a backend. Make sure that the
plugindirective that registers the plug-in is within the database section for that back-end in the server configuration file. (Theplugindirective should be added somewhere after thedatabasedirective.)
- In Directory Server 6.x, add this to the end of the
dse.ldiffile, which is located in the<server_root>/slapd-<instance_id>/configdirectory:![]()
dn: cn=Test Bind,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test Bind
nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
nsslapd-pluginInitfunc: testbind_init
nsslapd-pluginType: preoperation
nsslapd-pluginEnabled: on
nsslapd-plugin-depends-on-type: database
nsslapd-pluginId: test-bind
- Check this source file for an example of a pre-operation plug-in function that handles authentication:
<server_root>/plugins/slapd/slapi/examples/testbind.c
Using SASL with an LDAP Client
If you intend to use SASL as the method for authenticating clients, you need to enable your LDAP clients to use SASL.
In your client, call the
ldap_sasl_bind()orldap_sasl_bind_s()function to request authentication using SASL. To parse credentials from an asynchronous SASL bind operation, callldap_parse_sasl_bind_result(). These functions are part of the Netscape LDAP C SDK 3.0.The syntax for these functions are listed below:
LDAP_API(int) LDAP_CALL ldap_sasl_bind( LDAP *ld, const char *dn,
const char *mechanism, struct berval *cred,
LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );LDAP_API(int) LDAP_CALL ldap_sasl_bind_s( LDAP *ld, const char *dn,
const char *mechanism, struct berval *cred,
LDAPControl **serverctrls, LDAPControl **clientctrls,
struct berval **servercredp );The parameters are described below:
ldis the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.![]()
dnis the distinguished name (DN) that your client is attempting to authenticate as.![]()
mechanismis the name of the SASL mechanism that you want to use for authentication (the mechanism that you register in the initialization function for your server plug-in).![]()
credis a pointer to thebervalstructure containing the credentials that you want to use for authentication.![]()
serverctrlsis a pointer to an array ofLDAPControlstructures representing the LDAP v3 server controls that you want passed to the server for the bind operation.![]()
clientctrlsis a pointer to an array ofLDAPControlstructures representing the LDAP v3 client controls applicable to the bind operation.![]()
msgidpis a pointer to the message ID for this bind operation. To check the result of this operation, call theldap_result()function and theldap_parse_sasl_bind_result()function.![]()
servercredpis a pointer to a pointer to thebervalstructure containing any credentials returned by the server. These are the credentials that you set as the value of the SLAPI_BIND_RET_SASLCREDS parameter in your pre-operation bind plug-in function.![]()
If you are call the
ldap_sasl_bind()function, you need to call theldap_result()function to get the result of the authentication attempt:LDAP_API(int) LDAP_CALL ldap_result( LDAP *ld, int msgid, \
int all, struct timeval *timeout, LDAPMessage **result );The parameters are described below:
ldis the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.![]()
msgidis the message ID returned as the last argument of theldap_sasl_bind()function.![]()
allapplies to LDAP search operations. Since this is not an LDAP search operation, you can pass NULL for this argument.![]()
timeoutis the maximum interval to wait for the selection to complete. Iftimeoutis a NULL pointer, the select blocks indefinitely. To effect a poll, thetimeoutparameter should be a non-NULL pointer, pointing to a zero-valuedtimevalstructure.![]()
resultis a pointer to anLDAPMessagestructure containing the results of the bind operation. You need to pass this to theldap_parse_sasl_bind_result()function.![]()
After calling
ldap_result(), you need to call theldap_parse_sasl_bind_result()function to parse the results and retrieve the LDAP result code and any credentials returned by the server:LDAP_API(int) LDAP_CALL ldap_parse_sasl_bind_result( LDAP *ld, \
LDAPMessage *res, struct berval **servercredp, int freeit);The parameters are described below:
ldis the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.![]()
resis a pointer to theLDAPMessagestructure containing the results that you want to parse.![]()
servercredpis a pointer to a pointer to thebervalstructure containing any credentials returned by the server. These are the credentials that you set as the value of the SLAPI_BIND_RET_SASLCREDS parameter in your pre-operation bind plug-in function.![]()
freeitspecifies whether or not the result (theLDAPMessagestructure) should be freed after the error code is extracted. If 0, the result is not freed. If non-zero, the result is freed.![]()
The following example is an LDAP client that authenticates using the SASL method named
babsmechanism.
© 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002 Netscape Communications Corporation. All rights reserved.
Last Updated August 23, 2002