Use the default propagation token to propagate security attributes
A default propagation token is located on the running thread for applications and the security infrastructure to use. The product propagates this default propagation token downstream and the token stays on the thread where the invocation lands at each hop.
The data is available from within the container of any resource where the propagation token lands. Remember that we must enable the propagation feature at each server where a request is sent for propagation to work. Make sure that we enable security attribute propagation for all of the cells in the environment where we want propagation
There is a WSSecurityHelper class that has application programming interfaces (APIs) for accessing the PropagationToken attributes. This topic documents the usage scenarios and includes examples. A close relationship exists between the propagation token and the work area feature. The main difference between these features is that after we add attributes to the propagation token, we cannot change the attributes. We cannot change these attributes so that the security runtime can add auditable information and have that information remain there for the life of the invocation. Any time that we add an attribute to a specific key, an ArrayList object is stored to hold that attribute. Any new attribute that is added with the same key is added to the ArrayList object. When we call getAttributes, the ArrayList object is converted to a String array and the order is preserved. The first element in the String array is the first attribute added for that specific key.
In the default propagation token, a change flag is kept that logs any data changes to the token. These changes are tracked to enable WebSphere Application Server to know when to send the authentication information downstream again so that the downstream server has those changes. Normally, Common Secure Interoperability v2 (CSIv2) maintains a session between servers for an authenticated client. If the propagation token changes, a new session is generated and subsequently a new authentication occurs. Frequent changes to the propagation token during a method cause frequent downstream calls. If we change the token prior to making many downstream calls or we change the token between each downstream call, we might impact security performance.
Tasks
- Obtain the server list from the default propagation token.
Every time the propagation token is propagated and used to create the authenticated Subject, either horizontally or downstream, the name of the receiving application server is logged into the propagation token. The format of the host is "Cell:Node:Server", which provides we access to the cell name, node name, and server name of each application server that receives the invocation.
The following code provides you with this list of names and can be called from a Java 2 Platform, Enterprise Edition (J2EE) application.
The format of each server in the list is: cell:node:server. The output, for example, is: myManager:node1:server1
String[] server_list = null;
// If security is disabled on this application server, do not bother checking
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
// Gets the server_list string array
server_list = com.ibm.websphere.security.WSSecurityHelper.getServerList();
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
if (server_list != null)
{
// print out each server in the list, server_list[0] is the first server
for (int i=0; i<server_list.length; i++)
{
System.out.println("Server[" + i + "] = " + server_list[i]);
}
}
}- Obtain the list of callers, using the getCallerList API.
A default propagation token is generated any time an authenticated user is set on the running thread or anyone tries to add attributes to the propagation token. Whenever an authenticated user is set on the thread, the user is logged in the default propagation token. At times, the same user might be logged in multiple times if the RunAs user is different from the caller. The following list provides the rules used to determine if a user that is added to the thread gets logged into the propagation token:
- The current Subject must be authenticated. For example, an unauthenticated Subject is not logged.
- The current authenticated Subject is logged if a Subject is not previously logged.
- The current authenticated Subject is logged if the last authenticated Subject that is logged does not contain the same user.
- The current authenticated Subject is logged on each unique application server involved in the propagation process.
The following code sample shows how to use the getCallerList API.
The format of each caller in the list is: cell:node:server:realm:port_number/securityName. The output, for example, is: myManager:node1:server1:ldap.austin.ibm.com:389/jsmith.
String[] caller_list = null;
// If security is disabled on this application server, do not check the caller list
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
// Gets the caller_list string array
caller_list = com.ibm.websphere.security.WSSecurityHelper.getCallerList();
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
if (caller_list != null)
{
// Prints out each caller in the list, caller_list[0] is the first caller
for (int i=0; i<caller_list.length;i++)
{
System.out.println("Caller[" + i + "] = " + caller_list[i]);
}
}
}- Obtain the security name of the first authenticated user, using the getFirst Caller API.
Whenever we want to know which authenticated caller started the request, we can call the getFirstCaller method and the caller list is parsed. However, this method returns the security name of the caller only. If we need to know more than the security name, call the getCallerList method and retrieve the first entry in the String array. This entry provides all the caller information.
The following code sample retrieves the security name of the first authenticated caller using the getFirstCaller API.
The output, for example, is: jsmith.
String first_caller = null;
// If security is disabled on this application server, do not bother checking
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
// Gets the first caller
first_caller = com.ibm.websphere.security.WSSecurityHelper.getFirstCaller();
// Prints out the caller name
System.out.println("First caller: " + first_caller);
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
}- Obtain the name of the first application server for a request, using the getFirstServer method.
Whenever we want to know what the first application server is for this request, call the getFirstServer method directly.
The following code sample retrieves the name of the first application server using the getFirstServer API.
The output, for example, is: myManager:node1:server1.
String first_server = null;
// If security is disabled on this application server, do not bother checking
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
// Gets the first server
first_server = com.ibm.websphere.security.WSSecurityHelper.getFirstServer();
// Prints out the server name
System.out.println("First server: " + first_server);
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
}- Add custom attributes to the default propagation token, using the addPropagationAttribute API.
We can add custom attributes to the default propagation token for application usage. This token follows the request downstream so that the attributes are available when needed. When we use the default propagation token to add attributes, we must understand the following issues:
- Add information to the propagation token affects CSIv2 session caching. Add information sparingly between remote requests.
- After adding information with a specific key, the information cannot be removed.
- We can add as many values to a specific key as we need. However, all of the values must be available from a returned String array in the order that they were added.
- The propagation token is available only on servers where propagation and security are enabled.
- The Java 2 Security javax.security.auth.AuthPermission wssecurity.addPropagationAttribute attribute is needed to add attributes to the default propagation token.
- An application cannot use keys that begin with either com.ibm.websphere.security or com.ibm.wsspi.security. These prefixes are reserved for system usage.
The following code sample shows how to use the addPropagationAttribute API.
// If security is disabled on this application server,
// do not check the status of server security
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
// Key and values
String key = "mykey";
String value1 = "value1";
String value2 = "value2";
// Sets key, value1
com.ibm.websphere.security.WSSecurityHelper.
addPropagationAttribute (key, value1);
// Sets key, value2
String[] previous_values = com.ibm.websphere.security.WSSecurityHelper.
addPropagationAttribute (key, value2);
// Note: previous_values should contain value1
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
}- Obtain our custom attributes with the get PropagationAttributes API.
Custom attributes are added to the default propagation token using the addPropagationAttribute API. Retrieve these attributes using the getPropagationAttributes API. This token follows the request downstream so the attributes are available when needed. When we use the default propagation token to retrieve attributes, we must understand the following issues:
- The propagation token is available only on servers where propagation and security are enabled.
- The Java 2 Security javax.security.auth.AuthPermission "wssecurity.getPropagationAttributes" permission is needed to retrieve attributes from the default propagation token.
See Add custom attributes to the default PropagationToken to add attributes using the addPropagationAttributes API.
The following code sample shows how to use the getPropagationAttributes API.
// If security is disabled on this application server, do not bother checking
if (com.ibm.websphere.security.WSSecurityHelper.isServerSecurityEnabled())
{
try
{
String key = "mykey";
String[] values = null;
// Sets key, value1
values = com.ibm.websphere.security.WSSecurityHelper.
getPropagationAttributes (key);
// Prints the values
for (int i=0; i<values.length; i++)
{
System.out.println("Value[" + i + "] = " + values[i]);
}
}
catch (Exception e)
{
// Performs normal exception handling for the application
}
}The output, for example, is:
Value[0] = value1
Value[1] = value2- Modify the propagation token factory configuration to use a token factory other than the default token factory.
When WAS generates a default propagation token, the Application Server utilizes the TokenFactory class specified using the com.ibm.wsspi.security.token.propagationTokenFactory property.
The default token factory specified for this property is called com.ibm.ws.security.ltpa.AuthzPropTokenFactory. This token factory encodes the data in the propagation token and does not encrypt the data. Because the propagation token typically flows over CSIv2 using SSL, encrypting the token is not required. However, if we need additional security for the propagation token, we can associate a different token factory implementation with this property to get encryption. For example, if we choose to associate the com.ibm.ws.security.ltpa.LTPAToken2Factory token factory with this property, the token is AES encrypted. However, we need to weigh the performance impacts against our security needs. Adding sensitive information to the propagation token is a good reason to change the token factory implementation to something that encrypts rather than just encodes.
- Open the administrative console.
- Click Security > Global security.
- Click Custom properties.
- Perform our own signing and encryption of the default propagation token.
To perform our own signing and encryption of the default propagation token, we must implement the following classes:
- com.ibm.wsspi.security.ltpa.Token
- com.ibm.wsspi.security.ltpa.TokenFactory
Your token factory implementation instantiates and validates your token implementation. We can choose to use the Lightweight Third Party Authentication (LTPA) keys and have them pass into the initialize method of the token factory, or we can use our own keys. If we use our own keys, they must be the same everywhere to validate the tokens generated using those keys. See the API documentation, available through a link on the front page of the information center, for more information on implementing our own custom token factory.
- Associate your token factory with the default propagation token.
- Open the administrative console.
- Click Security > Global security.
- Click Custom properties.
- Locate the com.ibm.wsspi.security.token.propagationTokenFactory property and verify that the value of this property matches our custom token factory implementation.
- Verify that your implementation classes are put into the app_server_root/classes directory so that the WAS class loader can load the classes.
- Verify that your implementation classes are located in the ${USER_INSTALL_ROOT}/classes directory so that the WAS class loader can load the classes.
- (iSeries) Verify that the QEJBSVR user profile has read, write, and execute (*RWX) authority to the classes directory. Use the Work with Authority (WRKAUT) command to view the authority permissions for the directory.
Example
Authenticating users Propagating security attributes among application servers