Previous     Contents     Index     DocHome     Next     
iPlanet Application Server 6.0 Programmer's Guide (C++)



Chapter 9   Writing Secure Applications


This chapter describes how to implement iPlanet Application Server security features.

The following topics are included in this chapter:



Introduction to iPlanet Application Server Security

During the testing phase and initial deployment of your application, you are responsible for implementing application security by performing the following steps:

  1. Register security information, such as users and access control lists, with iPlanet Application Server. To register security information, edit the .gxr file, as described in , "Running and Debugging Applications."

  2. In your application code, implement secured sessions. When you start a secured session, iPlanet Application Server uses the security information, which you previously registered, to ensure that unauthorized users are not granted access to sensitive portions of code. For more information, see Secure Sessions.

The iPlanet Application Server offers application security in the following ways:

  • Authentication by user

  • Authentication by roles

  • Access Control List authorization

  • AppLogic access authorization

The rest of this section explains the differences between users and roles, the type of security each provides, and how they are used with Access Control Lists.


About User Authentication

User-based security allows access to an application by authenticating a user's username and password. You must set up each user of the application with a username and password. A user is anyone who will be accessing the application, including developers, special user-types, administrators, and so on.

Once a user is logged into the system, his or her access to specific AppLogic objects can be managed programmatically by code in each AppLogic. Alternatively, users can be managed by explicitly mapping them to the AppLogic objects to which they have access. This is a more tedious approach to application security, but it might be useful when first deploying and testing the application.

When you install an iPlanet Application Server, two default usernames and passwords are stored in the registry, kdemo/kdemo for sample application users, and the administrator username and password you specify during install.


How the iPlanet Application Server Stores Users

The information you specify for each user you create is stored in the local registry, which is managed by the Global Directory Service (GDS). The local registry is not held in a database, but rather a local file system that is typically cached in active memory. The information held in the registry is shared between all iPlanet Application Servers when you have multiple servers supporting an application.

Because each user is stored in the local registry, this level of application security is most useful for applications where the number of expected users is limited. For example, for an Internet online shopping with potentially tens of thousands of customers, the local registry is not the best place to manage those users. Instead, you should use roles. For more information about roles, see , "Writing Secure Applications."


About Role Authentication

Role security is based on the type of user accessing an application, and not directly on the user's exact identity. A role is based on the usage characteristic of a group of users, such as Application_Admin, Application_Vendor, or Application_Employee roles.

In contrast to security based on strict user identity, where an iPlanet Application Server authenticates a user by their username and password, role security only authenticates the existence of a role and the permissions of that role. Role security does not authenticate the individual user.

You must manage how users are authenticated and determine what role a user has. This is typically done by referencing a database table that would keep track of actual user-identity information. You are responsible, in this case, for managing and accessing the user records in the database.

For example, you could construct a database table that stores the user's username and password, obtained from a login screen, along with other pertinent information, such as credit card numbers, shipping address, and so on. Along with this information is the user's role, assigned the first time the user logs in. When the user logs in, the application can verify the user and their password, and link this information with their role for further use within the application. For first-time users, the application can quickly create a new record and add that user to the database.

As the user traverses through the application, certain AppLogic objects might require a secure login. Before putting the user session into secured mode, your code would obtain the user's role from the database table, also verifying that the user is valid.

You determine the roles for your application. For example, if the application is for purchasing products over the Web, and a user entered through the publicly available access page, that user's role might be Public_User. This role might change later, if, for example, the application determines that the user is actually a vendor or a partner. The updating and assignment of roles is under application logic control and, as long as the role is defined with the iPlanet Application Server, the user obtains the appropriate privileges.


How the iPlanet Application Server Stores Roles

A role and a user are stored and verified by the iPlanet Application Server in the same way, using the local registry. Implementing role security requires less administration maintenance than explicit user security because the system administrator does not have to make updates for every user. Mapping users to roles is the responsibility of the application developer and is done in the database through application code. In addition, the number of roles you create for an application is typically much less than the number of users that use the application.

Role security is the most scalable way to provide security. It requires more planning from the application developer to create the user database table. Once the database table is created, however, all further maintenance of users is handled by the application. Role security is a must for Intranet and Internet applications with a large number of users where tracking the actual users in a database table is required for scalability.


About Access Control List Authorization

The Access Control List, or ACL, allows you to set specific permissions for users and roles. A permission relates to an action the user is allowed to perform, such as a read or write.

The iPlanet Application Server comes with default permissions, but you can also create your own application specific permissions and ACLs. You name the ACL when you create it, so you can later refer to the ACL in code.

For example, a segment of an AppLogic object might perform a read action. Before this segment of code is executed, the application developer can request iPlanet Application Server to verify that the current user or role has read permissions. iPlanet Application Server checks the local registry to verify that the current ACL name has this user as a member and that the user has read permission.

If a user does not have a certain permission, the application developer can proceed to the next logical step for either exiting the user from the application, allowing them to re-login, or directing them to a different part of the application.


About Groups

Rather than adding individual users and roles as members to the ACL, it is recommended that you create groups to which users and roles belong and add only groups to the ACL. This is especially useful if you are using individual user-based security rather than role-based security.

This saves the maintenance of updating users and roles in the ACL when users and roles change. For example, if you have created users for an Intranet application, and a user leaves the company, you only need to remove that user from the appropriate group or groups, as opposed to removing the user from the groups and any ACLs.



Providing Application Security in Code



Before users gain access to your application, they must pass through several types of security tests that are provided by the Web server and the iPlanet Application Server. The Web server provides security between the Web browser and the iPlanet Application Server. The iPlanet Application Server itself provides features, such as event logging and user groups, that you can use to ensure that the server is secure.

Once a user has access to an iPlanet Application Server, controlling access to the applications must be done at the application level. You can use several techniques to ensure that users running AppLogics do not gain unauthorized access or perform intentional or unintentional harmful actions:

  • Use secure sessions.

    For more information, see Secure Sessions.

  • Make a single AppLogic the only valid entry point to the application.

    For more information, see Writing a Login AppLogic Object.

  • Verify all incoming AppLogic parameters, especially from forms filled out by users.

    For more information, see Validating Input to AppLogic Objects.

  • Make sure that unauthorized users cannot access cached AppLogic results.

    For more information, see Secure Caching.

  • Implement referrer checking or history checking so that the only users who can run the AppLogic are either those viewing or submitting from a certain HTML page, or those who have viewed a certain HTML page sometime during their session.

    For more information, see , "Managing Session and State Information."



Secure Sessions

You can set up user IDs and groups and specify their security permissions, by registering them through a .gxr file passed to the kreg utility. In code, you can refer to this security information to make sessions secure. In order to make use of the security features of iPlanet Application Server, your application must include sessions.

This section describes how to make sessions secure. Before reading this section, it would be advisable to have an understanding of sessions themselves. For more information about creating and using sessions, see , "Managing Session and State Information."

In applications with a large number of users, such as an Internet online catalog, normally you do not set up a user ID for each user. Instead, the users' individual records are kept in a database and, as part of each record, a user ID is assigned. Each user ID can be used for multiple actual end users. In an application with a large user base, the user IDs normally represent groups of users, or roles, rather than individual users.

Before using secure sessions, you must register the security information with the iPlanet Application Server. For more information, see , "Running and Debugging Applications."


Starting a Secured Session

To make a session secure, call LoginSession( ) (after calling CreateSession( ) or GetSession( )) and pass in one of the user IDs that has already been set up and registered. The LoginSession( ) call puts the session into secured mode. If this method returns successfully, the iPlanet Application Server begins to automatically check whether the user is authorized to run each AppLogic as it is requested during the user's session.


Example
The following code starts a secured session:

// Get login parameters

m_pValIn->GetValString("NAME", bufferName, sizeof(bufferName);

m_pValIn->GetValString("PASSWORD", bufferpw, sizeof(bufferpw);

IGXSession2 *mySess = NULL;

HRESULT hr;

hr = GetSession(0, NULL, NULL, &mySess);

if (hr != NOERROR || !mySess)

   // If no session, create one

   hr = CreateSession(0, 60000, NULL, NULL, NULL, &mySess);

// Here, lookup user NAME/PASSWORD in database

// and see what role the user has. The database

// should have a user table which tracks all the

// users of the online shop application.

//

LPSTR role;

role = /* Database lookup here. */ "Shop_Customer";

// The role might be Shop_Customer, Shop_Admin,

// Shop_Accounting, or Shop_Supplier

//

// Setup the session with that role. Future requests

// to AppLogics in this session will now operate under

// the right role.

//

LoginSession(role, "");

SaveSession(NULL);

if (mySess)

   mySess->Release();


Checking a User's Authorization

To check access to other resources, such as databases and files, use the IsAuthorized( ) method. Unlike AppLogics, iPlanet Application Server does not automatically check access to these resources.


Example
The following code checks to see whether the currently logged-in user is authorized to perform some of the more advanced operations, and returns the appropriate main menu page:

DWORD auth_result = 0;

if ((IsAuthorized("Shop_Inventory", "READ", &auth_result)

   == NOERROR &&

   auth_result == (DWORD) GXACL_ALLOWED) ||

   (IsAuthorized("Shop_Daily_Forecast", "READ",

      &auth_result) == NOERROR

   &&

   auth_result == (DWORD) GXACL_ALLOWED) ||

   (IsAuthorized("Shop_Weekly_Forecast", "READ",

      &auth_result) == NOERROR

   &&

   auth_result == (DWORD) GXACL_ALLOWED))

   // If the user is authorized, return this menu

   return EvalOutput("kivaapp/shop/mainmenu_advanced",

      (IGXTemplateData *) NULL,

      (IGXTemplateMap *) NULL, NULL, NULL);

// If the user is not authorized, return a different menu

return EvalOutput("kivaapp/shop/mainmenu_regular",

   (IGXTemplateData *) NULL,

   (IGXTemplateMap *) NULL, NULL, NULL);


Stopping a Secured Session

When the user exits the application, or exits the secured portion of it, you can remove the security enforcement on the session by calling LogoutSession( ). For example:

LogoutSession(0);

After this method call, iPlanet Application Server stops validating the user for each AppLogic. In your AppLogic code, perform all security operations between a LoginSession( ) call and its corresponding LogoutSession( ) call.



Writing a Login AppLogic Object



To secure an application, the you can write an authentication AppLogic through which all users access the application. This AppLogic could use any combination of the following techniques:


Example
The following code is the login AppLogic from the Online Bank sample application:

HRESULT hr=GXE_SUCCESS;

OBSession *pSession=NULL;

(hr=GetOBSession(&pSession);

LPSTR userName=GXGetValListString(m_pValIn, "userName");

LPSTR password=GXGetValListString(m_pValIn, "password");

// Validate the username and password

if(ValidateString(userName, "User Name", TRUE, 10,

    FALSE)&& ValidateString(password, "Password", TRUE,

   10, FALSE)) {

   // Validate existence of user in database

    // Get database connection

    IGXDataConn *pConn=NULL;

    hr=GetOBDataConn(&pConn);

    // Create a query

    IGXQuery *pQuery=NULL;

   hr=CreateQuery(&pQuery);

   pQuery->SetTables("OBUser, OBCustomer");

   pQuery->SetFields("OBUser.userName, userType, ssn,

      lastName, firstName");

   pQuery->SetWhere("OBUser.userName *=

      OBCustomer.userName AND OBUser.userName= :userName AND

      password= :password");

   IGXPreparedQuery *pPrepQuery=NULL;

   hr=pConn->PrepareQuery(0, pQuery, NULL, NULL,

      &pPrepQuery);

   IGXValList *pList=GXCreateValList();

   GXSetValListString(pList, ":userName", userName);

   GXSetValListString(pList, ":password", password);

   IGXResultSet *pResultSet=NULL;

   hr=pPrepQuery->Execute(0, pList, NULL, NULL,

      &pResultSet);

   ULONG count=0;

   pResultSet->RowCount(&count);

   if(count) {

      // Save login criteria in the session

      pSession->SetUserName(userName);

      pSession->SetPassword(password);

      // Determine what type of user this is and bring

      // up page

      ULONG ord=0;

      pResultSet->GetColumnOrdinal("userType", &ord);

      ULONG userType=0;

      pResultSet->GetValueInt(ord, &userType);

      pSession->SetUserType(userType);

      // Save session before streaming. This is because the

      // session is initally transmitted as a cookie and

      // needs to go in the http header

      SaveSession(NULL);

      ord=0;

      pResultSet->GetColumnOrdinal("ssn", &ord);

      char ssn[50];

      pResultSet->GetValueString(ord, ssn, 50);

      pSession->SetSSN(ssn);

      pSession->SaveSession();

      // Show the correct menu page

      NewRequest("AppLogic CShowMenuPage", m_pValIn,

         m_pValOut, 0);

   }

   else

   {

      Result("<HTML><BODY>Incorrect user name and password.

         </BODY></HTML>");

      pResultSet->Release();

   }

else

{

   Result(NULL);

   pSession->Release();

}

pList->Release();

pPrepQuery->Release();

pQuery->Release();

pConn->Release();

pSession->Release();

return GXE_SUCCESS;


Prompting for ID and Password

The login AppLogic can prompt the user for a login ID and password, then verify that the entries are valid. If the login ID and password are invalid, the user is not granted access to the application. In addition, valid logins can be assigned access levels based on business rules.

For example, suppose an employee is accessing a human resources application to change existing employee data and add new employees. It is crucial that this sensitive employee data is accessible only to authorized personnel in the human resources department.

A second employee is using another application to maintain the company's supply of office products such as paper, pens, and diskettes. To avoid unnecessary orders being made, it is important that only authorized personnel access this application.

Because the company does not want all employees to have access to all applications, the applications must verify who is attempting to gain access and admit only those users who are authorized. Therefore, the login AppLogics of these applications prompt all users for IDs and passwords, and do not allow them to continue using the application until valid IDs and passwords are given.

If the user did not type a user ID and password, you can return from the AppLogic at that point, displaying a prompt that asks the user to type the required information. The login AppLogic will not continue executing until the correct user ID and password are supplied. Once they are, the login AppLogic can create a session and call LoginSession( ).

For more information about securing user sessions, see , "Writing Secure Applications."

You can save the user's login ID and password as part of the session data. At any point in AppLogic code, you can refer to the user ID and password for other operations, such as logging into a database.

You can also use the user security information to choose from several alternatives in code. For example, the AppLogic might choose from several HTML templates to format reports differently for different users.


Writing Login Attempts to the Event Log

The login AppLogic can record all login attempts in the event log by using the Log( ) method. The iPlanet Application Server system administrator can then view the log to monitor who is attempting to use the application.

For example, suppose the system administrator is monitoring the iPlanet Application Server event log and notices an attempted security breach. The system administrator could take the login AppLogic off line for a period of time. Without the login AppLogic, there is no access to the application.



Validating Input to AppLogic Objects



An application should always validate the incoming parameters to an AppLogic. Don't trust the input coming from the user. HTML forms, in particular, cannot adequately enforce the type and range of input. Be sure to check for the following cases:

  • Although your HTML input form might provide a drop-down SELECT list, the value sent by the Web browser during a request might not necessarily be a value from your selection list.

  • Your HTML input form might specify the maximum length for input control fields, but the Web browser might send more characters than are specified. For example, your AppLogic might receive a user name 4000 characters long.

  • Check for special characters that might be embedded in the incoming input.

  • Check ranges when converting strings to numbers.


Example
The following code, from the BaseAppLogic in the Online Bank sample application, validates an input social security number (SSN). The BaseAppLogic also contains several other methods to validate input such as phone numbers and other strings.

STDMETHODIMP_(BOOL)

OBBaseAppLogic::ValidateSSNString(LPSTR pTestString, LPSTR pName, BOOL isRequired)

{

   if(!((pTestString)&&(strlen(pTestString)))) {

      if(isRequired) {

         char tmpStr[50];

         sprintf(tmpStr, "%s is a required field.", pName);

         HandleOBValidationError(tmpStr);

         return FALSE;

      }

   }

   else if(strlen(pTestString)!=9) {

      char tmpStr[50];

      sprintf(tmpStr, "%s must be of format ###-##-####",

         pName);

      HandleOBValidationError(tmpStr);

      return FALSE;

   }

   return TRUE;

}



Secure Caching



If your AppLogic is used in an environment in which high security is of critical importance, make sure that you attach security information to all cached AppLogic results. If an AppLogic caches its results, subsequent requests for the same AppLogic will cause iPlanet Application Server to check for cached results first to avoid running the AppLogic unnecessarily. Because the security checking code is in the AppLogic, which might not run, subsequent unauthorized users might be able to get the cached results.

To make sure caching is secure, include security information as part of the cache criteria. For example, the criteria could include the user ID and password parameters or other security information, such as the session ID. If the incoming request contains a user ID and password that match those stored with the cached results, then the user is authorized to get the results and the cache can be used.

iPlanet Application Server passes the session ID in the input IGXValList object. The name uses the following syntax:

gx_session_id_appName

where appName is the name of the application that you passed in the call to GetSession( ) or that was registered using the kreg utility. For example, the input IGXValList object for AppLogics in an application called Catalog might be an item with the following name:

gx_session_id_Catalog

The cache criteria for AppLogics in this application might look like the following example:

SetCacheCriteria(3600, 1, "gx_session_id_Catalog");

For more information about cache criteria, see , "Writing Server-Side Application Code."


Previous     Contents     Index     DocHome     Next     
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.

Last Updated April 26, 2000