4.2 Common Elements and Tasks

As you develop your extension, the extension needs to perform the following tasks:

For information about the Extension API interfaces and class, see the Javadoc API Reference.

4.2.1 Implementing Common Elements

Each extension type has two interfaces:

  • A factory interface that contains the method for initializing an extension object with data from the engine that the extension can use to retrieve data from an external source or to evaluate a condition or an action.

  • An extension interface that contains the methods that need to be implemented for the specific type of extension. For example, the NxpeCondition interface contains the method for evaluating the condition and returning True, False, or Error.

All the extensions need to implement both interfaces for the extension type and use the NxpeResult class for return codes and the NxpeException class for exceptions.

Return Codes in the NxpeResult Class

The NxpeResult class allows an extension to return the following values:

Return Code

Extension Type

Description

Cancel

Reserved

ConditionFalse

Condition

The compared values do not match, so the condition evaluation resolved to False.

ConditionTrue

Condition

The compared values match, so the condition evaluation resolved to True.

ConditionUnknown

Condition

The values could not be compared, so the results are unknown. This is comparable to the Result on Condition Error option when creating a policy.

Deny

Action

A deny action was applied.

ErrorBadData

Context Data

The data cannot be parsed. This result can be returned with the NxpeException class.

ErrorCodeComponent

Reserved.

ErrorConfigInitialization

All

The initialize method for the extension encountered an error. This result can be returned with the NxpeException class.

ErrorDataUnavailable

Context Data

The requested data is not available. This result can be returned with the NxpeException class.

ErrorIllegalArgument

All

The informationContext object contains an unknown parameter. This result can be returned with the NxpeException class.

ErrorIllegalState

Reserved

ErrorInterfaceUnavailable

All

The extension has not implemented one of the required methods in the interface. This result can be returned with the NxpeException class.

ErrorNoMemory

Reserved

GeneralFailure

All

Unknown error. This result can be returned with the NxpeException class.

NoAction

 

Reserved for use by the policy engine.

Obligation

Action

An obligation action was performed.

Pending

Reserved.

Permit

Action

A permit action was performed.

Success

 

Reserved for use by the policy engine.

Constructors in the NxpeException Class

The NxpeException class allows you to use a constructor that throws exceptions with the following information:

  • No information

  • With a string message

  • With a string message and a cause

  • With a result from the NxpeResult class. See Return Codes in the NxpeResult Class.

  • With a cause and a result from the NxpeResult class

  • With a string message and a result from the NxpeResult class

  • With a string message, a cause, and a result from the NxpeResult class

4.2.2 Initializing the Factory Object

All extension types need to implement the factory interface for the extension type and initialize an object specific to its type. The policy engine uses this object to send the parameter information about the user making the request to the extension. The extension uses this object to return its results to the policy engine.

The following code sample illustrates how to implement the factory interface. It uses the NxpeContextDataElementFactory to create an LDAPGroupDataElement object.

1  package ContextDataElement;
2  
3  import com.novell.nxpe.NxpeContextDataElement;
4  import com.novell.nxpe.NxpeContextDataElementFactory;
5  import com.novell.nxpe.NxpeException;
6  
7  public final class LDAPGroupDataElementFactory implements  NxpeContextDataElementFactory
8  {
9      public LDAPGroupDataElementFactory()
10     {
11     }
12 
13     public NxpeContextDataElement getInstance(
14             String strName,
15             int iEnumerativeValue,
16             String strParameter)
17         throws NxpeException
18     {
19         return (new LDAPGroupDataElement(strName, iEnumerativeValue, strParameter));
20 
21     }
22 
23 } /* LDAPGroupDataElementFactory */

The package line needs to be replaced with the package line for your extension.

All extensions need the three import lines for the factory interface. The first two import lines vary with the type of extension you are creating, but you need to import the factory interface and the extension interface.

Lines 7 through 23 implement the factory interface that creates an LDAPGroupDataElement object.

The other factory interfaces are very similar and are as easy to implement.

4.2.3 Retrieving Information from the Identity Server User Store

All extensions need to access an external data store and retrieve information from it. You need to know the type of data that your extension is going to retrieve, and then design how you are going to retrieve it.

If the extension needs to establish a connection to the external data store and log in to retrieve information, consider using one of the following methods:

  • The extension can use the credentials that authenticated the user to the Identity Server to log in as a user in the external data store. This method assumes that the user has the same credentials in the Identity Server user store and the external data store.

  • You can create an LDAP attribute in the Identity Server user store and store an X.509 certificate that you can use to access the external data store.

  • You can create configuration parameters that allow the administrator of the Administration Console to enter a username and password for accessing the external data store. The password is entered in clear text in the Administration Console, so this is not a secure method. To minimize the security risk, you can create a special user in the external data store whose rights are restricted to retrieving only the information required by the extension. If the retrieved information is not sensitive, this simple solution might not present a security risk.

When you create configuration parameters, you need to provide documentation for the administrator who installs the extension. Each configuration parameter requires a name, an ID, and a mapping to a data item. You need to document these for the administrator.

The name and ID you create to fit your programing requirements. These must be mapped to a data item available for the extension type.

NOTE:The data items are returned as strings, or as string arrays if they are multivalued.

Your external data store and the methods available for accessing its data determine whether any of the data items are useful in making the connection to the external data store.

For the data items specific to an extension type, see the following:

4.2.4 Implementing the Extension Interface

All extensions need to perform the following tasks.

Task 1: Specifying the Required Import Files

All extensions need a package line and the following import lines. The package line for the sample needs to be replaced with the package line for your extension. The first import line needs to be modified to import the interface for the extension type you are creating. The other import lines are standard for all extensions.

package ContextDataElement;

import com.novell.nxpe.NxpeContextDataElement;
import com.novell.nxpe.NxpeException;
import com.novell.nxpe.NxpeInformationContext;
import com.novell.nxpe.NxpeParameter;
import com.novell.nxpe.NxpeParameterList;
import com.novell.nxpe.NxpeResponseContext;
import com.novell.nxpe.NxpeResult;

The NxpeExpection class contains the defined constructors for throwing exceptions. For more information, see Constructors in the NxpeException Class.

The NxpeInformationContext class contains methods that allow you to gather information about extension evaluation.

The NxpeParameter class contains methods that allow you to retrieve information about a specific configuration parameter.

The NxpeParamaterList class contains methods that allow you to retrieve information about the configuration parameters you have defined for the extension.

The NxpeResponseContext class contains methods that allow you to configure the information that is sent with the results, such as logging or trace entry.

The NxpeResult class contains the methods and constants to set the return value for the extension. For more information, see Return Codes in the NxpeResult Class.

Task 2: Defining the Configuration Parameters

If your extension requires configuration parameters, you need to define them. The following code snippet contains the parameters for the LDAP group extension. These are the name and ID values that are configured on the Extension Details page (Policies > Extensions > [Extension Name]).

private static final String USER_STORE_NAME = "User Store";
    private static final int EV_USER_STORE = 11;

    private static final String AUTHENTICATION_NAME = "Authentication";
    private static final int EV_AUTHENTICATION = 211;
    private static final String DEFAULT_AUTHENTICATION = "simple";

    private static final String DIRECTORY_TYPE_NAME = "Directory Type";
    private static final int EV_DIRECTORY_TYPE = 222;
    private static final String DEFAULT_DIRECTORY_TYPE = "unknown";

    private static final String PROVIDER_URL_NAME = "User Store Replica";
    private static final int EV_PROVIDER_URL = 31;
    private static final String DEFAULT_PROVIDER_URL = "ldap://localhost:389";

    private static final String LDAP_USER_DN_NAME = "LDAP User DN";
    private static final int EV_LDAP_USER_DN = 41;

    private static final String SECURITY_PRINCIPAL_NAME = "Security Principal";
    private static final int EV_SECURITY_PRINCIPAL = 51;

    private static final String SECURITY_CREDENTIALS_NAME = "Security Credentials";
    private static final int EV_SECURITY_CREDENTIALS = 52;

    private static final String SEARCH_CONTEXT_NAME = "Search Context";
    private static final int EV_SEARCH_CONTEXT = 61;

    private static final String DEBUG_NAME = "Debug";
    private static final int EV_DEBUG = 91;

Not all of the parameters need to be defined in the Administration Console. If you want the administrator to decide the value that is mapped to the parameter, then you need to document the parameter and let the administrator select the mapping.

This is also a good place to define any other static constants your extension needs.

Task 3: Retrieving Configuration Parameters before Policy Evaluation

If your extension needs to be aware of some parameter values before it is called during policy evaluation, you can retrieve the values during the initialize method. Each extension interface (NxpeAction, NxpeCondition, NxpeContextDataElement) has an initialize method that contains a configurationValues object. The following code snippet illustrates what the LDAP group extension defines for this method. The setDebug line shows how to obtain the current value for the debug parameter.

 public void initialize(
            NxpeParameterList configurationValues)
        throws NxpeException
    {
        this.configurationValues = configurationValues;

        setDebug(configurationValues);

        strProviderURL = DEFAULT_PROVIDER_URL;
        strAuthentication = DEFAULT_AUTHENTICATION;
        strDirectoryType = DEFAULT_DIRECTORY_TYPE;

        StringBuffer sbLdapFilter = new StringBuffer(128);

        // setup filter
        sbLdapFilter.append("(|(objectClass=");
        sbLdapFilter.append(CLS_GROUP);
        sbLdapFilter.append(")(objectClass=");
        sbLdapFilter.append(CLS_GROUPOFNAMES);
        sbLdapFilter.append(")(objectClass=");
        sbLdapFilter.append(CLS_GROUPOFUNIQUENAMES);
        sbLdapFilter.append("))");

        strLdapFilter = new String(sbLdapFilter);

        // setup search controls
        searchControls = new SearchControls();
        searchControls.setTimeLimit(0);
        searchControls.setReturningObjFlag(true);
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchControls.setReturningAttributes(new String[] { ATTR_CN });

    }

Task 4: Implementing the Extension Methods

Besides having an initialize method, each extension interface has a few other methods that need to be implemented. The NxpeContextDataElement interface has four get methods. The following code snippet illustrates how the LDAP Group extension implements three of these methods.

public int getEnumerativeValue()
    {
        return (iEnumerativeValue);
    }

    public String getName()
    {
        return (strName);
    }

    public String getParameter()
    {
        return (strParameter);

The fourth method (the getValue method) is described in the next section. See Task 5: Retrieving Configuration Parameters at Policy Evaluation.

Task 5: Retrieving Configuration Parameters at Policy Evaluation

All extension interfaces have a method for retrieving configuration parameters at policy evaluation. The NxpeCondition interface has an evaluate method with an informationContext object. The NxpeAction interface has a doAction method with a informationCxt object. The NxpeContextDataElement interface has a getValue method with an informationContext object. The informationContext object contains information about the user and the user’s request that you need. You populate this object with the parameters that you need to evaluate the policy, and the policy engine supplies the values.

The following code snippet illustrates how the LDAP Group extension retrieves parameter values:

public synchronized Object getValue(
            NxpeInformationContext informationContext,
            NxpeResponseContext responseContext)
        throws NxpeException
    {
        LdapContext ldapContext = null;

        String strUserStore = getUserStore(informationContext);
        String strProviderURL = getProviderURL(informationContext);
        String strAuthentication = getAuthentication(informationContext);
        String strDirectoryType = getDirectoryType(informationContext);

        String strLDAPUserDN = getLDAPUserDN(informationContext);
        String strDN = getSecurityPrincipal(informationContext);

        if (strLDAPUserDN == null)
        {
            strLDAPUserDN = strDN;
        }

        String strPassword = getSecurityCredentials(informationContext);
        String strSearchContext = getSearchContext(informationContext);

Notice that this code snippet does not have an ending parenthesis. All the main work of the extension is done in this method. The next two tasks (Task 6: Connecting with the External Data Source and Task 7: Returning from an Extension) are performed within the getValue method.

Task 6: Connecting with the External Data Source

How you connect to the external data source in your extension is specific to the type of data source you are using. The following code snippet from the LDAP Group extension file illustrates how to connect to an LDAP user store:

try
        {
            HashSet<String> groupDNs = new HashSet<String>();

            ldapContext = newInitialLdapContext(strDN, strPassword);

            NamingEnumeration neGroups = ldapContext.search(strSearchContext, strLdapMemberFilter, searchControls);

This piece of code is very specific to LDAP.

Task 7: Returning from an Extension

The following code snippet from the LDAP Group extension illustrates the tasks you need to complete as you return the results of your extension action/evaluation to the policy engine:

while (neGroups.hasMore())
          {
              Attribute cn;
              SearchResult srGroup = (SearchResult) neGroups.next();
              String strGroupDN = srGroup.getNameInNamespace();

              groupDNs.add(strGroupDN);

              if (debug)
              {
                  System.out.println("LDAPGroupDataElement: \"" + strGroupDN + "\"");

              }
          }

          String[] strGroupDNs = new String[groupDNs.size()];

          groupDNs.toArray(strGroupDNs);
          return (strGroupDNs);

This code searches through the LDAP search results, retrieves the DN of any group found, adds it to the array, then returns the array.

This task is specific to the purpose of the extension. If the purpose of the extension is to evaluate a condition and determine whether the user matches the condition, the code for this task should show the extension obtaining the user’s value for the condition, comparing that value to the expected value, then return True for a match, False for a mismatch, and Error if extension cannot perform the evaluation.

Task 8: Error Handling

Each extension must handle potential error conditions. The following lines illustrate how the LDAP Group extension handles potential errors:

catch (NamingException e)
        {
            if (debug)
            {
                e.printStackTrace();

            }

            throw (new NxpeException(NxpeResult.ErrorDataUnavailable, e));

        }
        finally
        {
            if (ldapContext != null)
            {
                try
                {
                    ldapContext.close();

                }
                catch (NamingException e)
                {
                    if (debug)
                    {
                        System.out.println(e.getMessage());

                    }

Task 9: Performing Extension-Specific Tasks

After your extension has implemented all the required interface methods, the rest of the code implements what the extension requires to perform its purpose. Everything that follows the

********************** LDAPGroupDataElement/private ********************

comment in the LDAPGroupDataElement.java file shows how the LDAP Group extension performs its required tasks. For example, you can see how the extension retrieves parameter information from the policy engine, such as the user’s DN, security credentials, and user store information. With this information the extension interacts with the LDAP user store and retrieves the groups the user belongs to.