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.
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.
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:
The com.sun.am.namingURL property specifies the URL for the Naming Service. This service is used to find the URL of the Session Service for the given SSOToken ID. This property must be set as:
com.sun.am.namingURL = https://myhost.mydomain.com:58080/amserver/namingservice
The com.sun.am.notificationEnabled and com.sun.am.notificationURL properties specify whether notification is enabled, and if enabled, a URL where the application can listen for messages from Access Manager. These properties must be set as:
com.sun.am.notificationEnabled=true
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
The com.sun.am.sso.cacheEntryLifeTime property specifies how long, in minutes, a session token can live in cache before it should be removed. This property must be set as:
com.sun.am.sso.cacheEntryLifeTime=5
If not set, the default is 3 minutes.
The com.sun.am.sso.checkCacheInterval property specifies how often, in minutes, the cache should be checked for entries that have reached the cache entry life time. This property must be set as:
com.sun.am.sso.checkCacheInterval=5
The com.sun.am.sso.maxThreads specify the maximum number threads the SSO API should invoke for handling notifications. The API maintains a thread pool and invokes a thread for each notification. If the maximum number of threads has been reached, the notification will wait until a thread is available. If not specified the default maximum number of threads is 10. This property must be set as:
com.sun.am.sso.maxThreads = 5
The com.sun.am.cookieEnabled property specifies whether the session ID found in the cookie is URL encoded. If true, it will be URL decoded before sent to Access Manager for any session operation. This property must be set as:
com.sun.am.cookieEncoded = true|false
More information on properties in the AMAgent.properties file can be found in the J2EE Policy Agent Guide.
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
Get, Validate, Refresh And Destroy SSO Token
Get Session Information Interfaces
Get And Set Property Interfaces
Listener And Notify Interfaces
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).
#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; } |
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:
am_status_t am_sso_create_sso_token_handle(am_sso_token_handle_t * sso_token_handle_ptr, const char *sso_token_id, boolean_t refresh_token);
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:
boolean_t am_sso_is_valid_token(am_sso_token_handle_t sso_token_handle);
am_status_t am_sso_validate_token(am_sso_token_handle_t sso_token_handle);
am_status_t am_sso_refresh_token(am_sso_token_handle_t sso_token_handle);
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:
am_status_t am_sso_destroy_sso_token_handle(am_sso_token_handle_t sso_token_handle);
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:
am_status_t am_sso_invalidate_token(am_sso_token_handle_t sso_token_handle);
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.
const char * am_sso_get_sso_token_id(const am_sso_token_handle_t sso_token_handle);
const char * am_sso_get_auth_type(const am_sso_token_handle_t sso_token_handle);
unsigned long am_sso_get_auth_level(const am_sso_token_handle_t sso_token_handle);
time_t am_sso_get_idle_time(const am_sso_token_handle_t sso_token_handle);
time_t am_sso_get_max_idle_time(const am_sso_token_handle_t sso_token_handle);
time_t am_sso_get_time_left(const am_sso_token_handle_t sso_token_handle);
time_t am_sso_get_max_session_time(const am_sso_token_handle_t sso_token_handle);
const char * am_sso_get_principal(const am_sso_token_handle_t sso_token_handle);
am_string_set_t am_sso_get_principal_set(const am_sso_token_handle_t sso_token_handle);
const char * am_sso_get_host(const am_sso_token_handle_t sso_token_handle);
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:
const char * am_sso_get_property(const am_sso_token_handle_t sso_token_handle, const char *prop_name);
am_status_t am_sso_set_property(am_sso_token_handle_t sso_token_handle, const char *prop_name, const char *prop_value);
Code Example 4-6 is a sample of the SSO 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 */ |
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.
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; } |
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:
The application has to obtain the Access Manager cookie value and pass it into the SSO client methods to get to the session token. The method used for this process is application-specific.
Command line applications, such as amadmin, can be used. In this case, session tokens can be created to access the Directory Server directly. There is no session created, making the Access Manager access valid only within that process or VM.