Plug-in Programmer’s Guide Red Hat Directory Server |
Previous |
Contents |
Index |
Next |
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 Red Hat Directory Server (Directory Server) is organized in the following sections:
- Understanding Authentication Methods (page 99)
- How the Directory Server Identifies Clients (page 100)
- How the Authentication Process Works (page 100)
- Writing Your Own Authentication Plug-in (page 103)
- Writing a Pre-Operation Bind Plug-in (page 103)
- Using SASL with an LDAP Client (page 113)
Understanding Authentication Methods
Authentication methods for LDAP is described in RFC 2829, which you can find at http://www.ietf.org/rfc/rfc2829.txt
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 http://www.ietf.org/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 http://www.ietf.org/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_DN and SLAPI_CONN_AUTHTYPE parameters.
During an LDAP bind operation, the server authenticates the user and puts the DN and authenticated method in the SLAPI_CONN_DN and SLAPI_CONN_AUTHTYPE parameters.
When an authenticated client requests the server to perform an LDAP operation, the server checks the DN in the SLAPI_CONN_DN parameter 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:
- 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 LDAPv3 controls included with the LDAP bind request.
- If the method of authentication is LDAP_AUTH_SASL (SASL authentication), the server determines whether 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_SUPPORTED result 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_SUCCESS result 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,dexample,dc=com, and the directory root of the server is dc=example,dc=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_REFERRAL result code back to the client (LDAP_PARTIAL_RESULTS if the client only supports the LDAPv2 protocol).
- If the server is not configured with a default referral, the server sends an LDAP_NO_SUCH_OBJECT result code back to the client.
- The server puts the information from the bind request into the parameter block:
- SLAPI_BIND_TARGET is set to the DN as which the client is authenticating.
- SLAPI_BIND_METHOD is set to the authentication method (for example, LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL).
- SLAPI_BIND_CREDENTIALS is set to the credentials (for example, the password) included in the request.
- SLAPI_BIND_SASLMECHANISM (if the authentication method is LDAP_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_DN parameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to LDAP_AUTH_SIMPLE. The server sends an LDAP_SUCCESS result code back to the client and ends the processing of the bind request.
- If the credentials are incorrect, the server sends an LDAP_INVALID_CREDENTIALS result 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, 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, the server continues processing the bind request. The server sends the LDAP_SUCCESS result code back to the client. (The bind function does not do this.)
- If the backend bind function succeeds, the server sets the SLAPI_CONN_DN parameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to the authentication method.
- The server sends an LDAP_SUCCESS result 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," on page 103.
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.
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 as which the client is attempting to authenticate)
- SLAPI_BIND_METHOD - An integer value specifying the authentication method, such as LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL.
- SLAPI_BIND_CREDENTIALS - A berval structure 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_SASLMECHANISM parameter (a string value specifying the name of the SASL mechanism to use for authentication).
Make sure to check the following:
- If the SLAPI_BIND_METHOD parameter is LDAP_AUTH_SIMPLE and the SLAPI_BIND_CREDENTIALS parameter is empty or NULL, the client is attempting to bind anonymously.
- Call slapi_send_ldap_result() to send the LDAP result code LDAP_SUCCESS back to the client.
- If the SLAPI_BIND_METHOD parameter specifies a method that you do not recognize or support, call slapi_send_ldap_result() to send an LDAP_STRONG_AUTH_NOT_SUPPORTED result 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_TARGET parameter, and compare the credentials in the SLAPI_BIND_CREDENTIALS parameter against the known credentials for that entry.
By default, Directory Server uses the userPassword attribute to store the credentials for an entry. The server encodes the password using the scheme specified in the nsslapd-rootpwstoragescheme or passwordStorageScheme attributes of the cn=config entry contained in the dse.ldif file. The scheme can be any of the following:
- CLEAR - Means no encryption and can be defined using the clear-password-storage-scheme plug-in.
- CRYPT - Means Unix crypt algorithm and can be defined using the crypt-password-storage-scheme plug-in.
- SHA - Means Secure Hashing Algorithm and can be defined using the sha-password-storage-scheme plug-in.
- SSHA - Means Salted Secure Hashing Algorithm and can be defined using the ssha-password-storage-scheme plug-in.
If you need to compare the client's credentials against the value of the userPassword attribute, you can call the slapi_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 the userPassword attribute.
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_OBJECT result 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 the matched argument.
- If the client fails to provide the necessary credentials or if credentials cannot be found in the entry, send an LDAP_INAPPROPRIATE_AUTH result 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_CREDENTIALS result code back to the client.
- If a general error occurs, send an LDAP_OPERATIONS_ERROR result code back to the client.
Your function should also return a non-zero value.
You do not need to set any values for the SLAPI_CONN_DN parameter and the SLAPI_CONN_AUTHTYPE parameter. By default, these parameters are set to NULL and LDAP_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 the SLAPI_CONN_DN parameter and the SLAPI_CONN_AUTHTYPE parameter 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_AUTHTYPE to one of the following values:
- SLAPD_AUTH_NONE represents no authentication. (The client is binding anonymously.)
- SLAPD_AUTH_SIMPLE represents the simple authentication method.
- SLAPD_AUTH_SSL represents authentication through SSL.
- SLAPD_AUTH_SASL represents SASL authentication.
- These values differ from the values in the SLAPI_BIND_METHOD parameter. The values listed above are string values defined in the slapi-plugin.h header file, whereas the values of the SLAPI_BIND_METHOD parameter (such as LDAP_AUTH_SIMPLE and LDAP_AUTH_SASL) are integer values defined in the ldap.h header file.
- If the value of the SLAPI_BIND_METHOD parameter is LDAP_AUTH_SASL and you want to return a set of credentials to the client, call slapi_pblock_set() to set the SLAPI_BIND_RET_SASLCREDS parameter to the credentials.
- Call slapi_send_ldap_result() to send an LDAP_SUCCESS return 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," on page 42), call the Functions for Syntax Plug-in function and specify the name of the SASL mechanism. For example:
slapi_register_supported_saslmechanism( "babsmechanism" );If you do not register your SASL mechanism, the Directory Server will send an LDAP_AUTH_METHOD_NOT_SUPPORTED result 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 userpassword attribute 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 the SLAPI_PLUGIN_PRE_BIND_FN parameter to the name of your pre-operation bind function. (For details, see "Registering Your Plug-in Functions," on page 44.)
- If you are using SASL as the authentication method, call the Functions for Syntax Plug-in function 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.
Registering the Plug-in
To register the plug-in, add this to the end of the dse.ldif file, which is located in the server_root /slapd-instance_id /config directory:
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.cUsing 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() or ldap_sasl_bind_s() function to request authentication using SASL. To parse credentials from an asynchronous SASL bind operation, call ldap_parse_sasl_bind_result(). These functions are part of 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:
- ld is the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.
- dn is the distinguished name (DN) as which your client is attempting to authenticate.
- mechanism is 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).
- cred is a pointer to the berval structure containing the credentials that you want to use for authentication.
- serverctrls is a pointer to an array of LDAPControl structures representing the LDAPv3 server controls that you want passed to the server for the bind operation.
- clientctrls is a pointer to an array of LDAPControl structures representing the LDAPv3 client controls applicable to the bind operation.
- msgidp is a pointer to the message ID for this bind operation. To check the result of this operation, call the ldap_result() function and the ldap_parse_sasl_bind_result() function.
- servercredp is a pointer to a pointer to the berval structure 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 the ldap_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:
- ld is the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.
- msgid is the message ID returned as the last argument of the ldap_sasl_bind() function.
- all applies to LDAP search operations. Since this is not an LDAP search operation, you can pass NULL for this argument.
- timeout is the maximum interval to wait for the selection to complete. If timeout is a NULL pointer, the select blocks indefinitely. To effect a poll, the timeout parameter should be a non-NULL pointer, pointing to a zero-valued timeval structure.
- result is a pointer to an LDAPMessage structure containing the results of the bind operation. You need to pass this to the ldap_parse_sasl_bind_result() function.
After calling ldap_result(), you need to call the ldap_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:
- ld is the connection handle, which is a pointer to the LDAP structure containing information about the connection to the LDAP server.
- res is a pointer to the LDAPMessage structure containing the results that you want to parse.
- servercredp is a pointer to a pointer to the berval structure 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.
- freeit specifies whether the result (the LDAPMessage structure) 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.
Previous |
Contents |
Index |
Next |