Writing Functional Requirements in an IAM project

Functional requirements capture the intended behavior of a system. This behavior usually express tasks or functions the system is required to perform. As a consultant, you probably will have to wear the analyst hat sometimes, and therefore know how to capture functional requirements.

Use cases are one of the primary tools used for capturing and documenting functional requirements in an IAM project. The same tool can also be extended to capture non-functional requirements associated with use cases. The table below describes common properties usually found in a use case.

Table 1 – Use Case properties

Name Description
Use Case ID Use case identifier and/or reference number
Description Goal to be achieved by use case and sources for requirement
Actors List of actors involved in the use case
Assumptions Conditions that must be true for the use case to terminate successfully
Steps/Process Diagram Interactions between actors and system that are necessary to achieve goal. Usually a process diagram is included along with different scenarios or variations
Variations/Scenarios Any variation in the steps of a use case
Issues List of issues that remain to be resolved

Variations or scenarios are instances of a use case, it represent a single path through the use case. For example: one scenario for the main flow and other scenarios for each possible variation of flow through the use case (trigger by options, errors, security breaches, etc).

Based on the above, let’s make a sample IAM use case. The following paragraphs show a use case for Change Password of User Account:

Table 2 – Sample IAM Use Case

Use Case 01: Change Password of User Account

Description

This use case allows a user to change the password of a personal account.  This use case is applicable if the user wants to:

  • Synchronize passwords on multiple accounts
  • Change a password that is about to expire

Actors

The following actors are involved:

  • Employees
  • Business Partners

Assumptions

  • A user is logged in to the IAM system and authorized to perform the operation.

Process Diagram

2010-02-09 Use Case Diagram

Steps

  1. An employee or business partner selects the option to change password from the IAM system home page.
  2. The employee or business partner enters the new password twice and selects OK to continue.
  3. IAM system verifies the password against the password policy.
  4. IAM system changes the IAM password.
  5. IAM system sends a request to update other accounts (Active Directory and LDAP).
  6. The password for the Active Directory account is updated.
  7. The password for the LDAP account is updated.

Alternative Scenarios

  • Alternative to step #3: The passwords do not match.
    IAM system displays a message that the passwords do not match. Return to step #2.
  • Alternative to step #3: The password does not meet the password policy.
    IAM system displays a message that the password does not meet the password policy requirements. Return to step #2

Now, you probably are wondering…great! I have a guide to follow, but how the structure of my document is going to look like? Well there are many ways to do this; the following Table of Contents (TOC) will give you an idea on how you can structure your document.

Table 3 – Sample IAM Functional Requirements TOC

1          Introduction
A brief introduction about the IAM system. Describe the business drivers and main goals of the system.
2          Scope
2.1          Objectives
2.2          System Context
3          Functional Requirements
3.1          Actors
You should describe here the different actors involved in the IAM system. For example employee, manager or approver, etc.
3.2      Use Cases
In this section you should describe each use case, use as a template the use case described in Table 2.
3.2.1        Log On to Application
3.2.2       Log Off from Application
3.2.3       Create User Account
3.2.4       Enable User Account
3.2.5       Suspend User Account
3.2.6       Delete User Account
3.2.7       Approve the Request
3.2.8       Deny the Request
3.2.9       Change Password of User Account
4          Appendixes

As I mentioned at the beginning, use cases can be re-used to write other documents like the ones required during the test phase. Add a test script or procedure to test a use case and you will have in hand a test cases/test scripts document ready for your test phase.

Notes about Sun-Oracle IAM integration

Now that the acquisition is completed, Oracle has published a webcast about how the Sun IAM products will be integrated with the existing Oracle IAM suite.

In summary this is what I got from the webcast:

  • Sun Identity Manager will be renamed to Oracle Waveset; but Oracle Identity Manager will be the strategic product. This sounds like that in the long term Sun IdM will be demoted or confined to a small market, however Oracle have plans to enhance Oracle Identity Manager with functionality in Sun Identity Manager.
  • Sun Directory Server Enterprise Edition (DSEE) will co-exist with Oracle Internet Directory Server as the strategic enterprise directories. Here, I believe they will integrate some of the Oracle Directory Server technologies into Sun DSEE and maybe enhance the integration between both products.
  • Sun OpenSSO will continue as an open source; however Oracle Access Manager will be the strategic product, meaning that upgrade tools will be delivered to facilitate the migration from OpenSSO to Oracle Access Manager.
  • Sun Role Manager, will be renamed to Oracle Identity Analytics (good news), making it the strategic product for identity governance.

And now your comments…

Extending IBM Tivoli Access Manager’s Authorization Engine

Overview

The authorization engine is one of the core components of IBM Tivoli Access Manager for e-Business (TAMeb), specifically the entitlement service plug-in that provides a mechanism to retrieve access decision information (ADI) used by TAMeb to perform authorization rule evaluations.

Entitlement service plug-ins are share libraries that extend the TAMeb authorization engine with their own entitlement model, manipulating authorization structures such as user credentials and attribute lists. TAMeb version 6.0 and later includes a new class of entitlement service known as Dynamic Retrieval Service that is designed to retrieve ADI data that could exist in the register but also on external sources or even be calculated.

The following paragraphs describe how to create and invoke a dynamic entitlement service plug-in to extend the TAMeb authorization engine.

Some assumptions to consider

  • This article assumes that you are working with TAMeb version 6.0 or later. Testing the plug-in with an early version may lead to unexpected results.
  • Knowledge of C/C++ programming language and Microsoft Visual C++ 2005 development environment is required.
  • Knowledge of XML/XSL format and processing.
  • Knowledge of TAMeb’s authorization engine is also recommended to better understand this article, as it assumes that some concepts are familiar to the reader.

Introduction

To understand how a dynamic entitlement service plug-in works, I will describe a use case scenario where the customer is looking for ways to prevent URL tampering (i.e. based on URL redirects). The idea is to include a hash value or fingerprint in the URL string and have it verified with the plug-in to assure that no one have tampered with the parameters. Figure 1 shows the use case in detail.

Figure 1 – Using TAMeb’s entitlement service plug-in to prevent URL tampering

2009-09-20 Use Case

The use case is as follows:

  1. A URL request to access a protected resource is submitted. The URL string contains a hash value to verify the integrity of the parameters.
  2. TAMeb’s reverse proxy intercepts the URL request, authenticates user credentials and passes its control to the authorization engine for rule evaluation.
  3. If an authorization rule has been defined, the appropriated entitlement service plug-in is called to retrieve additional information (ADI data).
  4. The plug-in calculates a hash value using the URL’s parameters and a shared key known by TAMeb and the requestor only. The value is returned to the authorization rule engine.
  5. The authorization rule engine uses the returned value to evaluate the rule criterion, which states that the returned value must match the URL request’s value.
  6. If the rule criterion is met, the request is redirected to the protected resource for further processing.
  7. If failure to met the rule criterion, an error message is returned to the requestor.

Step 1: Creating a Dynamic Entitlement Service Plug-in

Entitlements service plug-ins are created using TAMeb’s C application programming interface (API) which requires a C compiler and TAMeb’s Application Development Kit (ADK). Each plug-in is a standalone module that is dynamically loaded in memory by the authorization engine. The TAMeb’s authorization engine recognizes and registers an entitlement service plug-in with the service dispatcher by reading entries in the aznapi-configuration stanza or in the aznapi.conf file.

The API model provides a standard interface to the service dispatcher to initialize and shut down all types of service plug-ins. For service plug-ins at least three functions must be implemented:

  • azn_svc_initialize()
    Initialize the entitlement service
  • azn_svc_entitlement_get_entitlements()
    Main function called when the authorization engine evaluates authorization rules
  • azn_svc_shutdown()
    Shutdown the entitlement service

The following listing shows the source code for the plug-in. I have included log information that can be useful to debug the results but the code is self explanatory, however one thing to consider is the use of application context attributes that will give you information about the URL request. You will need these attributes to calculate the hash value.

/***************************************************************************************
* File Name: azn_ent_srv_hash.c
* Dynamic ADI Entitlement Service Plug-in that extend TAMeb authorization engine.
* Function: Validates integrity of URL string, can be used to prevent URL tampering.
* To be called an authorization rule (Authzrule)) must be defined.
*
* Note: Based on sample code provided by TAMeb authorization development kit.
***************************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//#include <strings.h>
#include <ctype.h>

#include <ogauthzn.h>
#include <azn_svc_protos.h>
#include <aznutils.h>

// this version
#define ENT_SVC_DEMO_VER "Sample Dynamic ADI Entitlement Service Plug-In v1.0"
#define MAX_ATTR_LENGTH (2048)
#define LINELEN          (128)

#ifdef WIN32
#define STRCASECMP _stricmp
#define STRNCASECMP _strnicmp
#else
#define STRCASECMP strcasecmp
#define STRNCASECMP strncasecmp
#endif /* WIN32 */

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

#ifdef __cplusplus
extern "C" {
#endif

void attrlist_dump(azn_attrlist_h_t);
void check_status(char*, unsigned);
int readVar(const char*, char*, int);
static const char * HASH_ATTRIBUTE = "fingerprint";

/*
* Ignore_unauth will be set to true if we should not attempt to update
* the credentials of unauthenticated users.
*/
int ignore_unauth = FALSE;

/*
* Dump_cred will be set to true if we should print out the contents of
* the credential before asking for new attributes.
*/
int dump_cred = FALSE;

FILE *stream;

/******************************************************************************
* Interface function definitions.                                            *
******************************************************************************/
/**
* FUNCTION NAME
*      azn_svc_initialize
*
* DESCRIPTION
*      init the credattrs entitlements service
*
* ARGUMENTS
*      [in] argc       The count of arguments to the service.
*      [in] argv       The array of argument strings.
*      [in] svcInit    List of initialization attributes for the service.
*      [out] svcInfo   attr list ptr for attributes returned by the service.
*
* RETURN VALUE
*      AZN_S_COMPLETE on success, error code on failure
*/
AZN_DECLSPEC
	azn_status_t
	AZN_CALLTYPE
	azn_svc_initialize(const int                 argc,       /* in */
	const char                **argv,     /* in */
	const azn_attrlist_h_t    svcInit,    /* in */
	azn_attrlist_h_t          *svcInfo    /* out */
	)
{
	azn_status_t status = AZN_S_COMPLETE;
	azn_string_t svcid = NULL;
	azn_string_t azn_code_set = NULL;
	azn_string_t conf_file = NULL;
	azn_string_t domain = NULL;
	azn_boolean_t freeAttrlist = FALSE;
	int i=0;

	//Log file
	fopen_s(&stream, "azn_ent_svc_hash.log", "a+" );
	fprintf_s(stream,"Entitlement Service init...\n");

	//If not arguments return error
	if (svcInfo == NULL)
	{
		return(azn_util_errcode(AZN_S_SVC_ENT_INVALID_SVCINFO_HDL, 0));
	}

	//If invalid arguments return error
	if ((argc < 0) || (argc == 0 && argv != NULL))
	{
		return(azn_util_errcode(AZN_S_SVC_ENT_INVALID_ARG_COUNT, 0));
	}

	//If inconsistent arguments return error
	if ((argc > 0) && (argv == NULL))
	{
		return(azn_util_errcode(AZN_S_SVC_ENT_INVALID_ARG_COUNT, 0));
	}

	//Get service id - defined in TAM config file
	status = azn_attrlist_get_entry_string_value(svcInit, azn_svc_init_my_service_id, AZN_C_INITIATOR_INDEX, &svcid);
	if (status == AZN_S_COMPLETE || svcid != NULL)
	{
		fprintf_s(stream,"Entitlement Service ID: %s\n", svcid);
		azn_release_string(&svcid);
	}
	else
	{
		return(azn_util_errcode(status, 0));
	}

	//Get conf file if there is one (you can define your own entitlement service config file)
	status = azn_attrlist_get_entry_string_value(svcInit, azn_init_cfg_file, AZN_C_INITIATOR_INDEX, &conf_file);

	if (status == AZN_S_COMPLETE || conf_file != NULL)
	{
		fprintf_s(stream,"Configuration File: %s\n", conf_file);
		azn_release_string(&conf_file);
	}

	//Get codepage
	status = azn_attrlist_get_entry_string_value(svcInit, azn_svc_init_code_set, AZN_C_INITIATOR_INDEX, &azn_code_set);

	if (status == AZN_S_COMPLETE || azn_code_set != NULL)
	{
		fprintf_s(stream,"Entitlement Service Codepage: %s\n", azn_code_set);
		azn_release_string(&azn_code_set);
	}

	//Get the local domain this app is configured into
	//if the attribute is not set then assume NULL which means Default
	status = azn_attrlist_get_entry_string_value(svcInit, azn_init_ssl_local_domain, AZN_C_INITIATOR_INDEX, &domain);

	if (status == AZN_S_COMPLETE || domain != NULL)
	{
		fprintf_s(stream,"Entitlement Service Domain: %s\n", domain);
		azn_release_string(&domain);
	}

	//Return the service version to the dispatcher
	if (*svcInfo == AZN_C_INVALID_HANDLE)
	{
		azn_attrlist_create(svcInfo);
		freeAttrlist = TRUE;
	}
	//Add this version info to svcInfo
	status = azn_attrlist_add_entry(*svcInfo, (const azn_string_t)azn_svc_version, (const azn_string_t)ENT_SVC_DEMO_VER);
	if (status != AZN_S_COMPLETE)
	{
		if (freeAttrlist)
		{
			azn_attrlist_delete(svcInfo);
		}

		fprintf_s(stream,"Entitlement Service version error\n");
	}

	fclose(stream);
	return(azn_util_errcode(AZN_S_COMPLETE, 0));
}

/**
* FUNCTION NAME
*      azn_svc_shutdown
*
* DESCRIPTION
*      shutdown the ext_attr entitlements service.
*      The initialization parameters are passed in
*      again on shutdown but are ignored. No version info
*      is returned.
*
* ARGUMENTS
*      [in] argc       The count of arguments to the service.
*      [in] argv       The array of argument strings.
*      [in] svcInit    List of initialization attributes for the service.
*      [out] svcInfo   attr list ptr for attributes returned by the service.
*
* RETURN VALUE
*      AZN_S_COMPLETE on success, error code on failure
*/
AZN_DECLSPEC
	azn_status_t
	AZN_CALLTYPE
	azn_svc_shutdown(const int                 argc,       // in
	const char                **argv,     // in
	const azn_attrlist_h_t    svcInit,    // in
	azn_attrlist_h_t          *svcInfo    // out
	)
{
	//Log file
	fopen_s(&stream, "azn_ent_svc_hash.log", "a+" );
	fprintf_s(stream,"Entitlement Service shutdown...\n");
	fclose(stream);
	return(azn_util_errcode(AZN_S_COMPLETE, 0));
}

/**
* FUNCTION NAME
*      azn_svc_entitlement_get_entitlements
*
* DESCRIPTION
*      Returns extended attribute information associated with
*      the cred passed in
*
* ARGUMENTS
*      [in]    creds           The credentials of the caller
*      [in]    svc_id          The id of the entitlements service
*      [in]    app_context     attribute list containing information
*                              on which extended attributes to get
*      [out]   entitlements    attribute list containing the extended
*                              attributes
*
* RETURN VALUE
*      AZN_S_COMPLETE on success, error code on failure
*
*
*/
AZN_DECLSPEC
	azn_status_t
	AZN_CALLTYPE
	azn_svc_entitlement_get_entitlements(
	const azn_creds_h_t       creds,         /* in */
	const azn_string_t        svc_id,        /* in */
	const azn_attrlist_h_t    app_context,   /* in */
	azn_attrlist_h_t          *entitlements) /* out */
{

	azn_status_t status = AZN_S_COMPLETE;
	unsigned num = 0;
	unsigned numval = 0;
	int      i = 0;
	int      j = 0;
	azn_attrlist_h_t cred_attrs = AZN_C_INVALID_HANDLE;
	azn_string_t attr_name = NULL;
	azn_string_t auth_type = NULL;
	azn_boolean_t free_enthdl = FALSE;
	azn_string_t attr_id = NULL;
	azn_boolean_t    done = FALSE;
	char hash_value[MAX_ATTR_LENGTH];    

	//Log file
	fopen_s(&stream, "azn_ent_svc_hash.log", "a+" );
	fprintf_s(stream,"\n%s\n", ENT_SVC_DEMO_VER);

	//Check that we dont have an invalid handle
	if (entitlements == NULL)
	{
		fprintf_s(stream,"Error invalid handle.\n");
		fclose(stream);
		return(azn_util_errcode(AZN_S_INVALID_ENTITLEMENTS_HDL, 0));
	}

	fprintf_s(stream,"Service ID: %s\n\n", svc_id);

	if (*entitlements == AZN_C_INVALID_HANDLE)
	{
		status = azn_attrlist_create(entitlements);
		if (status != AZN_S_COMPLETE)
		{
			fprintf_s(stream,"Error reading entitlements.\n");
			fclose(stream);
			return(status);
		}
		free_enthdl = TRUE;
	}

	//Bypass if unauth users
	if (ignore_unauth)
	{
		// Check to see whether the user is unauthenticated, and leave quickly if they are
		status = azn_creds_get_attr_value_string(creds, AZN_C_INITIATOR_INDEX, azn_cred_mech_id, &auth_type);
		check_status((char*)"azn_creds_get_attr_value_string", status);
		if (status == AZN_S_COMPLETE && strcmp(auth_type, IV_UNAUTH) == 0)
		{
			azn_release_string(&auth_type);
			fprintf_s(stream,"Unauthenticated user, skipping adding extended attributes.\n");
			fclose(stream);
			return(AZN_S_COMPLETE);
		}
	}

	//Display credentials info
	if (dump_cred)
	{
		/* Display the attrlist for the principal */
		status = azn_creds_get_attrlist_for_subject(creds, AZN_C_INITIATOR_INDEX, &cred_attrs);
		check_status((char*)"azn_creds_get_attrlist_for_subject", status);
		if (status == AZN_S_COMPLETE)
		{
			fprintf_s(stream,"[User Credential Attributes]\n");
			attrlist_dump(cred_attrs);
			azn_attrlist_delete(&cred_attrs);

			fclose(stream);
			fopen_s(&stream, "azn_ent_svc_hash.log", "a+" );

		}
	}

	//If the app_context contains stuff then prompt to enter the attribute value
	//otherwise, prompt to enter attribute name and value.
	if (app_context != AZN_C_INVALID_HANDLE)
	{
		//Look for azn_perminfo_rules_adi_request
		attr_id = azn_perminfo_rules_adi_request;
		status = azn_attrlist_name_get_num(app_context, attr_id, &num);

		//App_context is valid and non-empty handle
		if (status == AZN_S_COMPLETE && num > 0)
		{
			fprintf_s(stream,"[Application Context Attributes]\n");
			attrlist_dump(app_context);

			//Scan all attributes values and look for the attr-value _'myhash'
			for (i = 0; i < num && !done ; i++)
			{
				status = azn_attrlist_get_entry_string_value(app_context, attr_id, i, &attr_name);

				if (status != AZN_S_COMPLETE)
				{
					break;
				}
				else
				{
					//If known attribute, we call the hash function to generate the hash value. The
					//function use the URL string parametrs and a shared key to calculate the value.
					//For simplicity we hardcode the result instead of calling the funcion.
					if (strcmp( attr_name, HASH_ATTRIBUTE ) == 0)
					{
						fprintf_s(stream,"\nCalling hash function...\n\n");

						hash_value[0]=(char)NULL;
						strcpy(hash_value, "hashvalue\0");

						status = azn_attrlist_add_entry(*entitlements, (const azn_string_t) attr_name, (const azn_string_t) hash_value);
						check_status((char *)"azn_attrlist_add_entry", status);
						if (status != AZN_S_COMPLETE)
						{
							done = TRUE;
							break;
						}
					}
				}
				azn_release_string(&attr_name);
			}

			if (status != AZN_S_COMPLETE)
			{
				if (free_enthdl)
				{
					azn_attrlist_delete(entitlements);
				}
			}
			else
			{
				fprintf_s(stream,"[Entitlement Attributes]\n");
				attrlist_dump(*entitlements);
			}

			fclose(stream);
			return(status);
		}
	}

	fclose(stream);
	return(status);
}

/*
* check status and print a message.
*/
void check_status(char *info, unsigned status)
{
	azn_string_t errstr = NULL;
	unsigned majerr, minerr;
	azn_status_t rc;

	if (status == AZN_S_COMPLETE)
		return;

	majerr = azn_error_major(status);
	minerr = azn_error_minor(status);

	fprintf_s(stream,"\n%s: ", info);

	rc = azn_error_get_string(status, &errstr);
	if (rc == AZN_S_COMPLETE && errstr)
	{
		fprintf_s(stream,"%s (0x%08x/0x%08x)\n\n", errstr, majerr, minerr);
		azn_release_string(&errstr);
	}
	else
		fprintf_s(stream,"API failure (0x%08x/0x%08x)\n\n", majerr, minerr);
}

/*
* Prompt the user for a variable.
*/
int readVar(const char *prompt, char *var, int len)
{
	char *startpos;
	char *endpos;
	char buffer[MAX_ATTR_LENGTH];

	/* Display prompt */
	fprintf_s(stream,"%s [%s]: ", prompt, var);
	fflush(stdout);

	/* Get user input */
	if (fgets(buffer, len, stdin) == NULL)
		return(FALSE);

	buffer[len-1] = '\0';

	/* Skip leading white space */
	startpos = buffer;
	while (*startpos && isspace(*startpos))
	{
		startpos++;
	}

	/* If empty, return the current value */
	if (! *startpos)
	{
		return(TRUE);
	}

	/* Skip trailing white space */
	endpos = startpos + strlen(startpos) - 1;
	while (endpos != startpos && isspace(*endpos))
	{
		endpos--;
	}
	endpos[1] = '\0';

	/* check for end of exit marker */
	if (STRCASECMP(startpos, "exit") == 0)
		return(FALSE);

	/* Copy the user's input to return */
	strcpy(var, startpos);
	return(TRUE);
}

/*
* dump attributes to the standard output
*/
void attrlist_dump(azn_attrlist_h_t perminfo)
{
	azn_string_t* attr_names;
	int i ,j;
	unsigned int count;
	azn_status_t aznStatus;
	azn_buffer_t buffer_value;
	azn_string_t str_value;
	azn_ulong_t ulong_value;

	aznStatus = azn_attrlist_get_names(perminfo, &attr_names);
	check_status((char *)"azn_attrlist_get_names", aznStatus);
	if (attr_names)
	{
		for (i = 0; attr_names[i] != NULL ;i++)
		{
			aznStatus = azn_attrlist_name_get_num(perminfo,
				attr_names[i],  &count);
			check_status((char *)"azn_attrlist_name_get_num", aznStatus);

			fprintf_s(stream,"\n-----------------------------\n");
			fprintf_s(stream,"Attr Name = %s\n" , attr_names[i]);
			fprintf_s(stream,"Values are : \n");

			for (j=0;j<count;j++)
			{
				aznStatus = azn_attrlist_get_entry_string_value(perminfo,attr_names[i],j,&str_value);
				if (aznStatus == AZN_S_COMPLETE)
				{
					fprintf_s(stream,"%s\n", str_value);
					azn_release_string(&str_value);
				}
				else
				{
					aznStatus = azn_attrlist_get_entry_buffer_value(perminfo,attr_names[i],j,&buffer_value);
					if (aznStatus == AZN_S_COMPLETE)
					{
						fprintf_s(stream,"0x%08x\n" , buffer_value);
						azn_release_buffer(&buffer_value);
					}
					else
					{
						aznStatus = azn_attrlist_get_entry_ulong_value(perminfo,attr_names[i],j,&ulong_value);
						if (aznStatus == AZN_S_COMPLETE)
							fprintf_s(stream,"%d\n" , ulong_value);
					}

				}
			}
		}
	}
}

#ifdef __cplusplus
}
#endif

If using Microsoft Visual C++ 2005 Express Edition, you must follow these steps to compile the plug-in:

  1. Be sure you to have installed the following components:
    Visual Studio Express 2005 (C++)
    TAMeb’s Application Development Kit (ADK)
    Microsoft Platform SDK 2003 SP1 or SDK 2005 Express
  2. The following libraries are required to compile the source code. For example if you have installed TAMeb’s ADK and Microsoft Visual C++ in your C drive:
    C:\Tivoli\PolicyDirector\lib\pdauthzn.lib
    C:\Program Files\Microsoft Platform SDK\Lib\kernel32.lib
    C:\Program Files\Microsoft Visual Studio 8\VC\lib\msvcrt.lib
    C:\Program Files\Microsoft Platform SDK\Include\crt
    C:\Program Files\Microsoft Visual Studio 8\VC\lib\msvcmrt.lib
  3. Open a command prompt window by selecting Program Files -> Visual C++ 2005 Express Edition -> Visual Studio Tools -> Visual Studio 2005 Command Prompt
  4. Run the command SetEnvLaunchWinXP32Retail.cmd to set the variables used by the compiler
  5. Modify the sample makefile.in that comes with TAMeb ADK to compile you source file. Make sure to add the following value to parameter WINNT_4x_CFLAGS: /D_CRT_SECURE_NO_DEPRECATE
    This will avoid warnings in depreciated functions like strcpy. Also replace msvcrt.lib with libcmt.lib to use runtime static library.
  6. If using strdup in your source code (.c file) replace it with _strdup.
  7. Run nmake makefile.in to compile and generate the plug-in (.dll file).

Step 2: Deploying the Plug-in

Once the plug-in is compiled, the resulting DLL file (azn_ent_svc_hash.dll) must be copied to folder C:TivoliPolicyDirectorbin (assuming that TAMeb is installed in drive C). For example:

C:\Tivoli\PolicyDirector\bin\azn_ent_svc_hash.dll

Add the following entries to ivmgrd.conf, ivacld.conf and webseald-default.conf files to register the entitlement service plug-in:

</pre>
[aznapi-configuration]
……
dynamic-adi-entitlement-services = AZN_ENT_SVC_HASH_ID

[aznapi-entitlement-services]
……
AZN_ENT_SVC_HASH_ID = azn_ent_svc_hash & -dump_cred

Step 3: Defining the Authorization Rule

Authorization rules are defined in XSLT format using TAMeb’s Web Portal Manager or the command line interface. Entitlement service plug-ins are automatically loaded when authorization rules are evaluated, so to invoke our plug-in we define a rule attached to the junction that points to the protected resource. For simplicity, the protected resource will be a local directory containing a sample text file.

1. Create a junction that points to the resource to be protected. Log in to TAMeb Web Portal Manager and select WebSEAL -> Create Junction, enter the following values:

WebSEAL Server Name: default-webseald-2gwin2k3
Junction Point: /testrules
Type: Local
Local Directory: C:/TestRules

2. Create an ACL to restrict access to the junction. Go to ACL -> Create ACL and enter the following values:

ACL Name: testrules-acl-ro
ACL Entries:
sec_master    user        Tc-mdbsvaB-R--l---[WP6]-
tuser         user        T------v----r-l---[WP6]-

tuser is a sample user that will be used to test the authorization rule and consequently the plug-in.

3. Create the authorization rule. Go to AuthzRule -> Create AuthzRule and enter the following values:

Name: validateURLstring
AuthxRule Text: <xsl:if test='AMWS_hd_user-agent != "" and AMWS_qs_param1 != "" and AMWS_qs_param2 != "" and AMWS_qs_param3 != "" and AMWS_qs_param4 = fingerprint'>!TRUE!</xsl:if>

Click on Create button to confirm the creation. AMWS_hd_user_agent and AMWS_qs_paramX are application context attributes (Browser) populated by TAMeb; fingerprint is the ADI attribute whose value will be resolved by the entitlement service plug-in.

4. Go to Object Space -> Browse Object Space and attach the authorization rule and ACL to the junction created in the first step. Log off from TAMeb Web Portal Manager.

Figure 2 – Attaching ACL and Auth-Rule to TAMeb junction using Web Portal Manager

2009-09-20 Attach ACL and Auth-Rule

Step 5: Testing the Plug-in

Testing the plug-in is as simple as submitting the URL requests to access the protected resource. In our case we access a text file that resides in a local folder protected by TAMeb. The URL string must contain among other parameters a hash value, calculated using the remaining parameters and a shared key known by the requestor and the plug-in only. The value is unique and can not be reproduced unless the key is compromised.

1. Submitting the URL request to access a text file:


https://2gwin2k3.iam.com/testrules/notes.txt?param1=data1&param2=data2&param3=data3&param4=hashvalue

Figure 3 – URL request with valid signature succeeds in accessing protected resource

2009-09-20 Valid URL Access

2. If an invalid hash value is provided TAMeb returns an error:


https://2gwin2k3.iam.com/testrules/notes.txt?param1=data1&param2=data2&param3=data3&param4=othervalue

Figure 4 – URL request with invalid signature fails to access protected resource

2009-09-20 Invalid URL Access

Conclusion

The sample code in this article will give you a head start to develop plug-ins for the TAMeb’s authorization engine, however I strongly suggest to take a look to the following documents:

New site for updated SUN Identity Manager documentation

The latest updates and corrections to Sun Identity Manager publications are now posted in a new Sun website:

http://blogs.sun.com/idmdocupdates/

Also, an RSS feed is available to check for updates. To subscribe, download a feed reader and click in the link under Feeds on the right side of the main page in the above site. Starting with version 8.0, separate feeds are available for each release.

SUN Identity Manager 8.1 Patch 4

Released a couple of weeks ago, the new patch is fixing some of the issues founded in previous revisions including the “HTTP 404 Error” when the OK button is pressed in the Forgot Password screen. A complete list of the issues fixed and instructions to download the patch are available in the following link:

http://sunsolve.sun.com/search/document.do?assetkey=1-21-141642-04-1