Sun Java System Access Manager 7 2005Q4 Developer's Guide

Chapter 9 Using the C APIs

Sun JavaTM System Access Manager 7 2005Q4 provides C APIs that enable external applications to participate in Access Manager authentication, authorization, single sign-on (SSO), and logging operations. To quickly lookup C API functions and syntax contained in the C header files, see Sun Java System Access Manager 7 2005Q4 C API Reference.

This chapter provides information on how the C APIs work, and includes instructions for using the C sample code that comes with Access Manager. The chapter includes the following topics:

About the C Library for Authentication

C applications can authenticate users with the Access Manager Authentication Service by using the Authentication C API. The C application contacts the Authentication Service to initiate the authentication process, and the Authentication Service responds with a set of requirements. The client application submits authentication credentials back to the Authentication Service and receives further authentication requirements back until there are no more to fulfill. After all requirements have been sent, the client makes one final call to determine if authentication has been successful or has failed.

The sequence of calls necessary to authenticate to Access Manager begins with the function call am_auth_create_auth_context. This call will return an AuthContext structure used for the rest of the authentication calls. Once an AuthContext structure has been initialized, the am_auth_login function is called. This indicates to the Authentication Service that an authentication is desired. Depending on the parameters passed when creating the AuthContext structure and making the am_auth_login function call, the Authentication Service will determine the login requirements with which to respond. For example, if the requested authentication is to an organization configured for LDAP authentication, and no authentication module chaining is involved, the server will respond with the requirements to supply a user name and a password. These attributes correspond to elements in the remote-auth.dtd structure. The user name corresponds to the NameCallback element; the password which corresponds to the PasswordCallback element. The client loops on function call am_auth_has_more_requirements (in this specific case there will be two). The client then fills in the needed information and submits this back to the server with function call am_auth_submit_requirements. The final step is to make function call am_auth_get_status to determine if the authentication was successful or not.

C Sample Code for Authentication

By default, the C Authentication sample checks the directory where Access Manager is installed for a properties file named AMAgent.properties. At installation, the file does not exist. If the file does not exist, you must create an AMAgent.properties file, and add the appropriate properties.

Code Example 6-7 lists the properties that are needed by the C Authentication API. Some of these are defined in AMAgent.properties and some are not. Those that are not defined in AMAgent.properties can be added to the file so they do not have to be identified for each function call. For example, com.sun.am.auth.orgName, which identifies the organization from which you want to authenticate, can be added to AMAgent.properties.

C Header File. The C Authentication API header file, am_auth.h, can be found in AccessManager-base/SUNWam/agents/include. It contains the function prototypes for the function calls available in the C Authentication API.


Example 9–1 AMAgent.properties File


# SOME PROPERTIES LISTED ARE NOT PRE-EXISTING IN THE PROPERTIES FILE

# the identity server naming service url
com.sun.am.namingURL=http://serverexample.domain.com:58080/amserver/namingservice
# the directory to use for logging
com.sun.am.logFile=/home/uid/logs/auth-log
# the logging level, all:5 being the highest and all:3 being medium
com.sun.am.logLevels=all:5
# the directory containing the certificate and key databases
com.sun.am.sslCertDir=/home/level/certdir
# the prefix of the cert7.db and key3.db files, if any
com.sun.am.certDbPrefix=
# the password to the key3.db file
com.sun.am.certDBPassword=11111111
# true to trust SSL certificates not in the client cert7.db
com.sun.am.trustServerCerts=true
# the nick name of the client certificate in the cert7.db
com.sun.am.auth.certificateAlias=Cert-Nickname
# the identity server organization desired for authentication
com.sun.am.auth.orgName=dc=sun,dc=com
            

About the C Library For Policy

Access Manager provides C APIs to allow external applications to determine access privileges and manage policies. Access Manager also provides a library of policy evaluation APIs to enable integration of the policy functionality into for C applications.

The C library provides a comprehensive set of interfaces that query policy results of an authenticated user for a given action on a given resource. The result of the policy evaluation is called an action value and may not always be binary (allow/deny or yes/no). Action values can also be non-boolean. For example, John Smith has a mailbox quota of 100MB. The value 100 is defined by a policy. As policy evaluation results in string values only, the policy evaluation returned is 100 numeric and not 100MB. It is up to the application developer to define metrics for the values obtained appropriately.


Note –

The policy management system is generic and makes no assumptions about any particular policy definition requirement.


Policy Implementation

As the first step of policy implementation, the API abstracts how a resource is represented by mandating that any resource be represented in a string format. For example, on a web server, resources may be represented as URLs. The policy evaluation engine cares only about the relative relevance of one resource to other. Five relative relevances are defined between two resources:

Having represented the resources in string format, the service developer must provide interfaces that establish the relevant relationship between resources.


Note –

Exact pattern match is a special case where resources may be represented collectively as patterns. The information is abstracted from the policy service and the comparison operation must take a boolean parameter to trigger a pattern matched comparison. During the caching of policy information, the policy engine does not care about patterns, whereas during policy evaluation, the comparisons are pattern sensitive.


The service developer must also provide a method to extract the root of the given resource. For example, in a URL, the protocol:// AcceessManager-HostName.domain_name:port portion represents the root. The three functions (has_patterns , get_resource_root and compare_urls) are specializations of resource representations. The set of characteristics needed to define a resource is called a resource trait. Resource traits are taken as a parameter during service initialization in the am_resource_traits_t structure. Using the resource traits, the policy service constructs a resource graph for policy evaluation. In a web server policy sense, the relation between all the resources in the system spans out like a tree with the following being part of the root tree:

protocol:// AcceessManager-HostName.domain_name : port/

Policy Evaluation

Two opaque data structures are defined: am_map_t and am_properties_t. am_map_t provides a key to multiple value mapping and am_properties_t provides a key to single value mapping. am_properties_t provides the additional functionality of loading a configuration file and getting values of specific data types. These are simple data structures that are only used for information exchange to and from the policy evaluation interfaces.

About the C Library for Single Sign-On

The C API are provided in the SUNWamcom package which comes with Access Manager or any of its downloadable agents. The package includes header files, libraries and samples.

C SSO Include Files

Include files for the C SSO API are am_sso.h and am_notify.h. am_sso.h must be included for any SSO routines. am_notify.h must be included for parsing notification messages from the server and calling SSO listeners.

C SSO Properties

Certain properties must be read in and passed to am_sso_init(), the routine which initializes C API. Because of this, am_sso_init() must be called before any other SSO interface. The default properties file used is AMAgent.properties, located in AccessManager-base/SUNWam/config/. The following properties must be set:


Note –

If com.sun.am.notificationEnabled is not found in the properties file, the default is false.


com.sun.am.notificationURL=https://myhost.mydomain.com:8000/myURL

More information on properties in the AMAgent.properties file can be found in the J2EE Policy Agent Guide.

C SSO Interfaces

The C SSO interfaces consist of the following routines. A detailed description of the input and output parameters for each interface is in the header files.

Initialization and Cleanup

To use the C SSO API, the am_sso_init() routine needs to be called before any other routines. This interface initializes the internal SSO module. At the end of all SSO routines, am_cleanup() should be called to cleanup the internal SSO module. Code Example 4-5 on page 90 is a code sample for these interfaces.

am_sso_init() initializes internal data structures for talking to the Session Service. It takes a properties input parameter that contains name value pairs from a configuration or properties file, and returns a status on the success or failure of the initialization.

am_cleanup() cleans up all internal data structures created by am_sso_init, am_auth_init, or am_policy_init. am_cleanup() needs to be called only once when using any of the Access Manager C API interfaces (authentication, SSO or policy).


Example 9–2 Code Sample For am_sso_init and am_cleanup


     #include <am_sso.h>

     int main() {
        am_properties_t *properties;
        am_status_t status;

        /* create a properties handle */
        status = am_properties_create(&properties);
        if (status != AM_SUCCESS) {
             printf("am_properties_create failed.\\n");
             exit(1);
        }

        /* load properties from a properties file */
        status = am_properties_load(properties, "./myPropertiesFile");
        if (status != AM_SUCCESS) {
            printf("am_properties_load failed.\\n");
            exit(1);
        }

        /* initialize SSO module */
        status = am_sso_init(properties);
        if (status != AM_SUCCESS) {
            printf("am_sso_init failed.\\n");
            return 1;
        }

         /* login through auth module, and do auth functions.
          * ...
          */

        /* do sso functions
         * ...
         */

         /* done - cleanup. */
         status = am_cleanup();
         if (status != AM_SUCCESS) {
             printf("am_cleanup failed!\\n");
             return 1;
         }
         /* free memory for properties */
         status = am_properties_destroy(properties);
         if (status != AM_SUCCESS) {
             printf("Failed to free properties.\\n");
             return 1;
         }

         /* exit program successfully. */
         return 0;
     }
                  

Get, Validate, Refresh And Destroy SSO Token

A user needs to be authenticated to get the token ID for the user login session. A token can be obtained with the token ID and the am_sso_create_sso_token_handle interface. This interface checks to see if the token is in its local cache and, if not, goes to the server to get the session information associated with the token ID and caches it. If the reset flag is set to true, this interface will refresh the idle time of the token on the server. Here is the interface of am_sso_create_sso_token_handle:

Once a token handle is obtained, the caller can check if the session is valid with the am_sso_is_valid_token interface. The am_sso_token_validate interface will flush the token handle in the local cache (if any) and go to the server to fetch the latest session information. The am_sso_refresh_token will also flush the token handle in the local cache (if any) and go to the server to fetch the session information. In addition, it will reset the idle time of the session on the server. Here are the token-related interfaces:

When caller is done with a token handle, it must be freed by calling am_sso_destroy_sso_token_handle to prevent memory leak. The following is that interface:

The session associated with the token can be invalidated or ended with am_sso_invalidate_token. Although this ends the session for the user, the proper way to log out is through am_auth_logout. Using the former interface to end a session will result in authentication resources associated with the session to remain on the server unnecessarily until the session has timed out. The following is the interface for am_sso_invalidate_token:

Get Session Information Interfaces

The following interfaces make it convenient to get server-defined information (or properties) about the session associated with a token. This can include the session idle time, maximum session time, and so forth.

Get And Set Property Interfaces

The get and set property interfaces allows an application to get any property (server or application defined) and to set any property in a session. Note that am_sso_set_property will update the sso_token_handle with the latest session properties from Access Manager, including the new property that was set. In addition, if the property that is given in prop_name is a protected property, am_sso_set_property will return success, however the value given will not be set as it is a property protected by Access Manager. These interfaces are:

Code Example 4-6 is a sample of the SSO get, set, create, refresh, validate, invalidate, and destroy interfaces.


Example 9–3 Sample Code For Get, Set, Create, Refresh, Validate, Invalidate, and Destroy Interfaces


     /* initialize sso as in previous sample */

     am_status_t status = NULL;
     am_sso_token_handle_t sso_handle = NULL;
     char *session_status = NULL;
     am_string_set_t principal_set = NULL;

     /* create sso token handle */
     status = am_sso_create_sso_token_handle(&sso_handle, sso_token_id, false);
     if (status != AM_SUCCESS) {
         printf("Failed getting sso token handle for sso token id %s.
					\\n", sso_token_id);
         return 1;
     }

     /* check if session is valid */
     session_status = am_sso_is_valid_token(sso_handle) ? "Valid" : "Invalid";
     printf("Session state is %s\\n", session_status);

     /* check if session is valid using validate. This also updates the handle with 
		 /*info from the server */
     status = am_sso_validate_token(sso_handle);
     if (status == AM_SUCCESS) {
         printf("Session state is valid.\\n");
     } else if (status == AM_INVALID_SESSION) {
         printf("Session status is invalid.\\n");
     } else {
         printf("Error validating sso token.\\n");
         return 1;
     }

     /* get info on the session */
     printf("SSO Token ID is %s.\\n", am_sso_get_sso_token_id(sso_handle));
     printf("Auth type is %s.\\n", am_sso_get_auth_type(sso_handle));
     printf("Auth level is %d.\\n", am_sso_get_auth_level(sso_handle));
     printf("Idle time is %d.\\n", am_sso_get_idle_time(sso_handle));
     printf("Max Idle time is %d.\\n", am_sso_get_max_idle_time(sso_handle));
     printf("Time left is %d.\\n", am_sso_get_time_left(sso_handle));
     printf("Max session time is %d.\\n", am_sso_get_max_session_time(sso_handle));
     printf("Principal is %s.\\n", am_sso_get_principal(sso_handle));
     printf("Host is %s.\\n", am_sso_get_host(sso_handle));
     principal_set = am_sso_get_principal_set(sso_handle);
     if (principal_set == NULL) {
            printf("ERROR: Principal set is NULL!\\n");
     }else {
            printf("Principal set size %d.\\n", principal_set->size);
            for (i = 0; i < principal_set->size; i++) {
                printf("Principal[%d] = %s.\\n", i, principal_set->strings[i]);
            }
            am_string_set_destroy(principal_set);
     }

     /* get "HOST" property on the session. Same as am_sso_get_host(). */
     printf("Host is %s.\\n", am_sso_get_property(sso_handle, "HOST"));

     /* set a application defined property and get it back */
     status = am_sso_set_property(sso_handle, "AppPropName", "AppPropValue");
     if (status != AM_SUCCESS) {
         printf("Error setting property.\\n");
         return 1;
     }
     printf("AppPropName value is %s.\\n", am_sso_get_property
				(sso_handle, "AppPropName");

     /* refresh token, idle time should be 0 after refresh */
     status = am_sso_refresh_token(sso_handle);
     if (status != AM_SUCCESS) {
         printf("Error refreshing token !\\n");
         return 1;
     }
     printf("After refresh, idle time is %d.\\n", am_sso_get_idle_time(sso_handle));

     /* end this session abruptly. am_auth_logout() is the right way 
		 /* to end session */
     status = am_sso_invalidate_token(sso_handle);
     if (status != AM_SUCCESS) {
         printf("Error invalidating token.\\n");
         return 1;
     }

     /* we’re done with sso token handle. free memory for sso handle. */
     status = am_sso_destroy_sso_token_handle(sso_handle);
     if (status != AM_SUCCESS) {
         printf("Failed to free sso token handle.\\n");
         return 1;
     }

     /* call am_cleanup, and other cleanup routines as in previous sample */


                  

Listener And Notify Interfaces

Applications can be notified when a session has become invalid, possibly because it has been idle over a time limit, or it has reached the maximum session time. This is done by implementing a listener function of type am_sso_token_listener_func_t , which takes a SSO token handle, event type, event time, application-defined arguments handle, and a boolean argument to indicate whether the listener function should be called in the calling thread or dispatched to a thread from the internal thread pool managed by the C SDK. This listener function must be registered to be invoked when the session has ended and notification must be enabled for an application to receive notifications. Notification is enabled by setting the property com.sun.am.notificationEnabled to true, and by providing a URL where the application is receiving HTTP messages from Access Manager. The URL where the application is receiving messages from the Access Manager is expected to take any message from the server (as an XML string) and pass it to am_notify(). am_notify() will parse the message and invoke session listeners or policy listeners depending on whether the message is a session or policy notification. Code Example 4-7 is a sample implementation of SSOToken listener and how to register it.


Example 9–4 Sample Implementation Of SSOToken Listener


     void sample_listener_func(
                   am_sso_token_handle_t sso_token_handle,
                   const am_sso_token_event_type_t event_type,
                   const time_t event_time,
                   void *opaque)
     {
         if (sso_token_handle != NULL) {
             const char *sso_token_id = am_sso_get_sso_token_id(sso_token_handle);
             boolean_t is_valid = am_sso_is_valid_token(sso_token_handle);
             printf("sso token id is %s.\\n",
                    sso_token_id==NULL?"NULL":sso_token_id);
             printf("session state is %s.\\n",
                      is_valid == B_TRUE ? "valid":"invalid");
             printf("event type %d.\\n", event_type);
             printf("event time %d.\\n", event_time);
         }
         else {
             printf("Error: sso token handle is null!");
         }
         if (opaque)
             *(int *)opaque = 1;
         return;
     }

     int main(int argc, char *argv[]) {

     am_status_t status;
     char *sso_token_id = argv[1];
     int listener_func_done = 0;

     /* initialize sso as in previous samples */

     /* get sso token handle */
     status = am_sso_create_sso_token_handle(&sso_handle, sso_token_id,  false);

     /* register listener function. notification must be enabled, if not, 
     /* status AM_NOTIF_NOT_ENABLED will be returned. */
 status = am_sso_add_sso_token_listener(sso_handle, sample_listener_func,
				&listener_func_done, B_TRUE);
     if (status != AM_SUCCESS) {
         printf("Failed to register sample listener function.\\n");
         return 1;
     }


                  

Non-Web-Based Applications

Access Manager provides the SSO API primarily for web-based applications, although it can be extended to any non-web-based applications with limitations. With non-web-based applications, you can use the API in one of two ways:

Using the C API Code Samples

Access Manager provides sample code you can use to connect your C application to the Access Manager framework. Access Manager also provides the following resources:

The following provides descriptions of the C code sample files located in the /csdk directory.

am_policy_test.c

Demonstrates how to use the Policy APIs to evaluate policy for specified resources.

am_auth_test.c

Demonstrates how to use the Authentication APIs to log in to an Access Manager server.

am_sso_test.c

Demonstrates how to use the Single Sign-On (SSO) APIs to perform session operations.

am_log_test.c

Demonstrates how to use the Logging APIs to log a message to Access Manager logs.

apache_agent.c

Demonstrates how to use the Policy APIs to build a Web Agent for the Apache Web Server. This is a sample Web Agent and is not intended to serve as a real Web Agent. When you build the sample code, apache_agent.c is not compiled. The apache_agent.c is provided for reference purposes only.

ProcedureTo Build a Sample Program on UNIX platforms

  1. Be sure you have gmake or other compliant make program available. When possible, use the GNU gmake program, version 3.76 or higher. Be sure you have gcc or other compliant C compiler program available.

  2. In the /samples directory, run the make program:

    gmake

    This produces executables of the samples am_*_test in the same directory.

On Red Hat Linux Advanced Server release 2.1AS/i686 platform:

On the Red Hat Linux AS 2.1/i686 platform, due to a bug in the default gcc and glibc that comes with RedHat Linux AS 2.1, you must use the following versions (or later) of gcc and glibc:

The rpms are available at the following locations:

ftp://rpmfind.net/linux/redhat/updates/enterprise/2.1AS/en/os/SRPMS/gcc-2.96-124.7.2.src.rpm

ftp://rpmfind.net/linux/redhat/updates/enterprise/2.1AS/en/os/SRPMS/glibc-2.2.4-32.11.src.rpm

ProcedureTo Build a Sample Program on the Windows Platform

On the Windows platform, you can build sample programs using Microsoft Visual Studio 6.0.

  1. Define WINNT in the compile flags.

  2. Add ../lib as an additional lib path.

  3. Add ../include as an additional include path.

  4. Link with all libraries in the ../lib directory.

  5. Be sure that gmake and MKS Tooolkit are installed on the system.

  6. Run the gmake command:

    C:\samples>gmake

    The Makefile can be used to make all samples.

Executing the Sample Programs

The sample programs operate in command-line mode and demonstrate the use of C APIs for authorization, authentication, single sign-on (SSO), and logging.

Platform Information

To Execute a Sample Program on the Solaris Platform

On the Solaris platform you can run the sample programs by launching the generated executables on the command line. Set the LD_LIBRARY_PATH environment variable to include the following /lib directories:

These directories contain libamsdk.so, libxml2.so , libssl3.so, libnss3.so, libplc4.so, libplds4.so, libnspr4.so, and libucb.so. Include the directory /usr/lib before /usr/ucblib so that common programs such as editors will continue to function.

To Execute a Sample Program on the Linux Platform

On the Linux platform you can run the sample programs by launching the generated executables on the command line. Be sure to set the LD_LIBRARY_PATH environment variable to include the directory AccessManager-base/agent/lib, which contains the following: libamsdk.so, libxml2.so, libssl3.so, libnss3.so, libplc4.so, libplds4.so and libnspr4.so.

To Execute a Sample Program on the Windows Platform

On the Windows platform you can run the sample programs by launching the generated executables on the command line You must have the ../sample/lib directory in your path before launching the sample programs. Alternatively, you can use the run.bat script to launch the sample programs. The run.bat script sets your path appropriately.

To Execute am_policy_test

The sample program am_policy_test evaluates the policy for the given ssoToken, resource name, and action. Before you can run this program, you must have a policy defined for the specified resource in an Access Manager server.

To execute am_policy_test, use the following command:

am_policy_test initPropertyFile ssoToken resourceName action

initPropertyFile

The path to the AMAgent.properties file.

Example: ../config/AMAgent.properties

ssoToken

Valid SSO Token issued by Access Manager. You can get this value from your browser after logging into the Access Manager server. See the documentation for your browser for information about how to determine the cookie values. Once you have that information, you can use the cookie value for iPlanetDirectoryPro as the value for this argument.

If the browser you are using does not provide URL decoded cookie values, you may have to decode the value yourself before using it in this sample program. Alternatively, for test purposes, you can also use the SSO value displayed in the Access Manager debugging logs.

resourceName

Name of a resource for which you want to evaluate a policy. Example:

http://myServer.myDomain .com:80/myResource.html

action

The action name. For example GET or POST .

To Execute am_auth_test

The sample program am_auth_test authenticates to the specified organization using the specified authentication module. You must have an Access Manager server with a user profile set up with the corresponding authentication module before running this program.

To execute am_auth_test, run the following command:

am_auth_test [-u user ] [-p password] [-f properties_file] [-r url ] [-n cert_nick_name] [-o org_name] [-m auth_module ]

The following variables are used:

user

Specify the Access Manager user name.

password

Specify the Access Manager user's password.

properties_file

Specify the complete path of the AMAgent.properties file.

url

(Optional) Specify the authentication login URL.

cert_nick_name

(Optional) Specify the certificate nickname.

org_name

Specify the default organization name.

auth_module

Specify the authentication module type. The default is LDAP.

If no options are supplied on the command line, login uses the org_name specified in the properties file and auth_module LDAP. The user can specify the org_name on the command line to override the value specified in the properties file. Example: dc=iplanet,dc=com . In either case, the user is prompted for User Name and Password.

For certificate—based login, the user specifies auth_module Cert on the command line. The user can specify the cert_nick_name on the command line to override the value specified in the properties files. Other values affecting certificate-based login are taken from the properties file. The default properties file is ../../config/AMAgent.properties. Check to be sure the appropriate properties and values are set in the properties file before calling this program. The following properties are specific to authentication:

To Execute the am_sso_test Program

The sample program am_sso_test logs into an Access Manager server using the specified user and password and the LDAP authentication module, and performs SSO Token operations on the session. Before running this program, you must have an Access Manager with a user profile set up with the LDAP authentication module.

To execute am_sso_test, run the following command:

am_sso_test -u user  -p password
			 [-f  properties_file] [-s session_url  ]
user

User to log in to the Access Manager server using the LDAP authentication module.

password

Password to log in to the Access Manager server using the LDAP authentication module.

properties_file

The path to the properties file. If not set, the default properties file ../../config/AMAgent.properties is used. Check to be sure the appropriate values are set in the properties file before calling this program. See Sun Java System Access Manager Policy Agent 2.2 User’s Guidefor more information on the properties file.

session_url

The session URL of the Access Manager server if known. Example: https://myhost/amserver/sessionservice. If not set (the default is not set), the Naming Service specified in the properties file is used to obtain the session URL for the Token ID of the login session.

am_log_test

The sample program am_log_test logs a message to the specified log file on the Access Manager server, using the specified SSO Token.

To execute the am_log_test sample program, run this command:

am_log_test -n log_name -u logged_by_token_id -u user_token_id -m message [-d log_module] [-f properties_file]

log_name

Name of Log file on the Access Manager server.

logged_by_token_id

SSO token ID with access to the Logging Service on the Access Manager server.

user_token_id

SSO token ID of a user for the log. Can be the logged_by_token_id or something else.

message

The log message.

log_module

The module name, if not specified, the default TestModule is used.

properties_file

path to the properties file. If not set, the default properties file ../../config/AMAgent.properties is used. Check to make sure appropriate values are set in the properties file before calling this program. See the Agents documentation for more information on the properties file.

apache_agent.c

The apache_agent.c sample demonstrates how to implement a web agent plugin for the apache HTTP server. This is a sample only and should not be used as an actual web agent.