Previous Next Contents Index


Writing Secure Applications

This chapter describes how to write secure application components that perform authentication to establish and maintain a user's identity.

The security model described in this chapter was developed for EJBs, and is part of the standard for EJBs. As of the 2.1 servlet specification, there is no standard security model for servlets. NAS has created a model for servlets in order to provide security throughout the application, with some collaboration with the developers of Java standards, so that the model presented here for servlets is based heavily on an emerging standard.

This chapter includes the following sections:


Understanding the Security Model
Secure applications depends on two kinds of validation:

The following diagram shows the basic steps in the security model:

The identity can be used to determine whether a user or group is a member of a certain "role", so that application flow can be controlled based on a user's function in the application paradigm. For example, if part of your application is restricted to paying customers only, those customers can be associated with a group called PayingCustomers. You can then write your components to perform tasks based on a user's membership in that group.

Additionally, each component can have an access control list (ACL) that defines the permissions given to various users or groups with respect to that component. You define the permissions and the users/groups to which they apply either from the NAS Administration Tool or in component configuration files. For example, an EJB that represents an employee database can contain an ACL specifying that members of the group Employee can only read the data, while members of the group Manager can also update the data.

Security Concepts The concepts that describe how security works are similar for EJBs and servlets, though the implementation is slightly different. This is because the servlet 2.1 specification does not describe a security model. NAS adapts the EJB security model for servlets by providing the ICallerContext interface, which allows a servlet to retrieve a caller's identity as well as determine whether the identity is allowed to perform certain tasks based on its membership in a group (a role).

Additionally, both EJBs and servlets benefit from the IServerContext interface, which enables the creation of an identity object (an unspecified task for both EJBs and servlets) as well as the retrieval of that identity from the component's context object (EJBContext or ServletContext). Note that components have read-only access to the identity, and cannot add, change, or delete identity data.

Security for servlets is a representation of the security model for EJBs, described below.

The Security Model for EJBs

The design behind EJBs pushes most of the responsibility for low-level systems management, such as security, from the bean itself to its container and the server. In the EJB security model, a server contains platform-specific user account information that is administered by the system administrator. (In NAS, this information is stored in the directory server.)

The EJB container, which is invisible to you as a developer, is responsible for the following:

As this figure illustrates, the EJB security model separates platform-specific administrative tasks, such as security database maintenance, from EJB run-time activities, such as identity verification. An EJB has read-only access to identity information. Only a system administrator can add, change, or delete records in the security database.

The management and construction of this database is typically vendor/solution specific and outside the scope of the EJB specification.

Note. In NAS, the security database resides in the Directory Server (LDAP).

Also, the EJB security model provides a generic, high-level, and standard interface that permits the EJB writer to share EJBs across platforms without having to know about security models on individual platforms. An EJB that uses the standard security interfaces can be deployed on any platform and in any application without recoding.

The Security Model for Servlets

The servlet specification does not supply a security model, though it will in future versions. For this reason, NAS supplies a declarative and programmatic security model based on the model for EJBs described above, except that servlets do not have a container to manage security issues for them.

Servlets are responsible for the following:

These responsibilities are described in Authenticating a User.

Programmatic Security You perform the following security tasks programmatically:

For more information on how to use programmatic security, see Authenticating a User.

Declarative Security Components can declare a level of security for themselves by establishing access control lists (ACLs). ACLs are named lists in the Directory Server that relate a user or group with one or more permissions. In the case of NAS servlets and EJBs, ACLs determine which users or groups have permission to execute the resource. EJBs can provide bean-level and method-level security this way.

You set up ACLs for specific components in their respective configuration files. If an ACL is present for a given servlet or EJB method, the list is checked to see whether the current user has permission to execute the resource.

You can also set up arbitrary ACLs using the Administration Tool and then inspect permissions programmatically. For more information, see Creating and Using Declarative ACLs.

A client may also be defined in terms of a security role. For example, a company might use its employee database to generate both a company-wide phone book application, and to generate payroll information. Obviously, while all employees might have access to phone numbers and email addresses, only some employees would have access to salary information. Employees with the right to view or change salaries might be defined a having a special security role.

Groups and Roles In addition to identities, a client may also be defined in terms of a security role. For example, a company might use its employee database to generate both a company-wide phone book application, and to generate payroll information. Obviously, while all employees might have access to phone numbers and email addresses, only some employees would have access to salary information. Employees with the right to view or change salaries might be defined a having a special security role.

A role is different from a user group in that a role defines a function in an application, while a group is a set of users that are related in some way. For example, members of the groups astronauts, scientists, and (occasionally) politicians all fit into the role of SpaceShuttlePassenger.

The EJB security model describes roles (as distinguished from user groups) as being described by an application developer and independent of any particular domain. Groups, by contrast, are specific to a deployment domain. The role of the deployer is to map roles into one or more groups.

In NAS, roles correspond to user groups configured in the Directory Server. LDAP groups can contain both users and other groups. Future versions of NAS will provide specific support for roles.

Security and Cookies Since security is based on sessions, and sessions themselves are partially maintained in a session cookie, some aspects of application security are controlled by settings in the session cookie.

In particular, a cookie has an security attribute controlled by the setSecure() method in the Cookie class. If you set this attribute with mySessionCookie.setSecure(true), the session cookie is only transmitted if the connection is secure (for example, with HTTPS). On an unsecure connection, the cookie never appears, and so the session can not be validated.

You can require all session activities to adhere to a secure connection by setting the secure attribute in the SessionInfo structure in the application configuration file appInfo.ntv, as in the following example:

"SessionInfo" NTV { 
    "secure" Bool "true", 
    "timeout" Int "100", 
... 
} 
For more information about configuration files, see Creating Configuration Files.

Guide to Security Information Each of the following types of information is shown with a short description, the location where the information resides, how to create the information, how to access the information, and where to look for further information.

User Information
User name, password, etc.

Location. Directory Server

How to Create. Create using Administration Tool, or programmatically using the LDAP SDK.

How To Access. Provide user name and password to loginSession() to authenticate session.

See Also. Authenticating a User, Storing and Managing Users and Groups in the Administration Guide

Security Roles
Role that defines a function in an application, made up of a number of users and/or groups. LDAP groups function as roles in NAS.

Location. Directory Server

How to Create. Since roles correspond to user groups in this version of NAS, you create them the same way you create users and groups using Administration Tool, or programmatically using the LDAP SDK.

How To Access. Test for a user's membership in a role using isCallerInRole().

See Also. Checking a Client's Security Role

Component ACLs
Optional ACL that governs user permissions for a specific component.

Location. NAS registry, via the component's configuration file

How to Create. Edit the appropriate field in the component's configuration file:

How To Access. NAS uses these lists internally to determine whether the current user can execute the resource. This type of security is declarative, meaning that there is no programmatic impact. You do not have to write any code in order to use ACLs in this way.

See Also. Creating and Using Declarative ACLs, Specifying Access Control and Specifying NAS Registry and ACL Information

General ACLs
Arbitrary named ACLs.

Location. NAS registry

How to Create. NAS Administration Tool

How To Access. Use isAuthorized() from the session to test whether the current user has the listed permission, as in the following example:

if (sess2.isAuthorized("myAcl",
                       "read"))
{...} 

See Also. Creating and Using Programmatic ACLs, Setting Access Control List Authorization in the Administration Guide


Authenticating a User
In order to authenticate a user, create a session for the user, and then validate the user's user name and password and "log into" the session. This creates an identity, an instance of java.security.Identity, that is managed by the server context (a view of the server's state). Components can now access the identity for the user from the context by calling getCallerIdentity(), and can use this identity to test whether a user is authentic or to create an audit trail.

Note that the user's identifier and password must be validated against a user name and password that are already known to NAS. NAS looks for user and group entries, as well as the access control lists that determine their respective permissions, in the directory server.

Note. You can use the NAS Administration Tool to create new users, or you can create entries progammatically within an application using the LDAP JDK included with each installation of NAS. For more information about setting up users in the directory server, see Storing and Managing Users and Groups in the Administration Guide.

Logging In to the Session You can authenticate a user name and password and log into the session using the method loginSession() from the NAS feature HttpSession2 interface. For example, the following code (in a servlet) authenticates the user and logs them into a session:

String name = req.getParameter("username"); 
String pass = req.getParameter("password"); 
HttpSession session = req.getSession(true);  // create user session 
HttpSession2 sess2 = (HttpSession2) session; 
if (sess2.loginSession(name,pass))            // authenticate user 
{ 
    // now we have an authenticated session for this user 
} 
else 
{
    // authentication failed
}
Once the user is logged into the session, the session can be trusted. Any servlets or EJBs that depend on the session being active can also trust that the user is authentic. If the session expires or the user logs out, the identity is no longer available, and attempts to retrieve the identity fail.

At run time, the container (EJBs) or servlet engine (servlets) throws an exception if an unauthorized user attempts to access the component.

Checking Identity The identity that is created in the server when the client logs in is an instance of java.security.Identity. This object contains the client's name and other information pertinent to identification. You can determine which client has invoked a component through the caller's context using the method getCallerIdentity(). See Retrieving a Client's Identity below.

Note. getCallerIdentity() returns null if the session does not exist (i.e. has expired) or if the session is not authenticated.

Identity objects can also identify roles (groups of users). For example, you create an identity for a role in order to test whether the current user is in that role using isCallerInRole(). See Checking a Client's Security Role.

Retrieving a Client's Identity
getCallerIdentity() operates on the standard EJBContext object for EJBs. This example shows an EJB retrieving a caller's identity:

/* Get the security identity of a client. */
Identity caller = EJBContext.getCallerIdentity();
/* Put client's name into human readable form. */
String clientName = caller.getName();
Since the servlet specification does not provide for this type of context, NAS provides two interfaces, ICallerContext and IServerContext, that enable you to derive the caller's identity from the standard ServletContext object. This example shows how to retrieve a caller's identity in a servlet:

ServletContext ctx = getServletContext();
nCtx = (com.netscape.server.IServerContext) ctx; 
com.netscape.server.ICallerContext callerCtx = nCtx.getCallerContext(); 
/* Get the security identity of a client. */
Identity caller = callerCtx.getCallerIdentity();
/* Put client's name into human readable form. */
String clientName = caller.getName();
One possible use for getName() is to create an audit trail by logging the user's name and the current time. For more information, see Controlling Execution Flow. For other methods available in java.security.Identity, see the documentation at:

http://java.sun.com/products/jdk/1.1/docs/api/java.security.Identity.html

Checking a Client's Security Role
Once you create the identity, you can then pass it to a subsequent test for equality or use it as the role parameter of the isCallerInRole() method. The isCallerInRole() method is available in both javax.ejb.EJBContext (for EJBs) and com.netscape.server.ICallerContext (for servlets).

isCallerInRole() requires a java.security.Identity object as a parameter, so to use this method you need an identity that corresponds to the role with which you are concerned. You can create an identity for this role using createIdentityByString("role"), in the IServerContext interface. role must correspond to a user group in the Directory Server.

isCallerInRole() returns a boolean value indicating true or false. For example, in the following code fragment, an EJB checks to see if the client's role is PayrollDept:

/* Check if the client is in the PayrollDept role */
Identity PayRoll = EJBContext.createIdentityByString("PayrollDept");
boolean B = EJBContext.isCallerInRole(PayRoll);
This example shows the same logic in a servlet:

ServletContext ctx = getServletContext();
nCtx = (com.netscape.server.IServerContext) ctx; 
com.netscape.server.ICallerContext callerCtx = nCtx.getCallerContext(); 
/* Check if the client is in the PayrollDept role */
Identity PayRoll = nCtx.createIdentityByString("PayrollDept");
boolean B = callerCtx.isCallerInRole(PayRoll);
Controlling Execution Flow
You can test a client's membership in a role in order to control execution flow. For example, in the following EJB code snippet, if a client is a member of the Payroll department, one set of statements is executed, while if the client is not a member of Payroll, a different set of statements is executed.

/* Check if the client is in the PayrollDept role */
Identity PayRoll = EJBContext.createIdentityByString("PayrollDept");
if (callerCtx.isCallerInRole(PayRoll)) 
{
    // client can edit payroll entries 
}
else
{
    // client can only view payroll entries 
}
This example shows the same logic in a servlet:

ServletContext ctx = getServletContext();
nCtx = (com.netscape.server.IServerContext) ctx; 
com.netscape.server.ICallerContext callerCtx = nCtx.getCallerContext(); 
/* Check if the client is in the PayrollDept role */
Identity PayRoll = nCtx.createIdentityByString("PayrollDept");
if (callerCtx.isCallerInRole(PayRoll)) 
{
    // client can edit payroll entries 
}
else
{
    // client can only view payroll entries 
}
Checking Permission You can check whether a user or group has permission to execute a given resource by using isAuthorized() to access a programmatic ACL. For more information about ACLs, see Access Control Lists.

Note. This is different from declarative security, described in Declarative Security, as this ACL is an arbitrary list and is not connected to any specific resource. You can define any permissions you want in a named ACL.

For example, assume you have an ACL named HR_Database that like this:

john_smith     write
fred_jones     readwrite
bill_white     read 
In a servlet, you can conditionally execute a block of code based on the user's stated permissions, as in the following example:

HttpSession session = req.getSession; // assume an authorized session 
HttpSession2 sess2 = (HttpSession2) session;
if ( sess2.isAuthorized(HR_Database, "read") } 
    { ... } 
In the above example, the conditional block of code executes if the user is john_smith.

Logging Out of the Session When authentication is no longer necessary, you can log out of the session using logoutSession(). The session still exists, but it is no longer authenticated. Any subsequent calls to getCallerIdentity() return null.

For example, the following statement nullifies the authenticated identity, though the session remains:

sess2.logoutSession(); 

Authentication also ends if the session expires or is deleted.

Access Control Lists
You can control access to a resource by creating an access control list (ACL). There are two types of ACLs that serve different purposes:

These ACLs are described in the following sections.

Creating and Using Declarative ACLs Components can declare a level of security for themselves by establishing component-specific ACLs in their configuration files. These ACLs determine which users or groups have permission to execute the resource.

If an ACL is present for a given servlet or EJB method, NAS checks the list to see whether the current user has permission to execute the resource. You do not have to write any code in the resource. In fact, the resource is not executed at all if the user is not permitted to execute the resource.

You can create ACLs specifically for a given servlet by specifying the acl field in the ServletRegistryInfo section of the servlet's configuration file. For more information, see Specifying NAS Registry and ACL Information.

You can create ACLs specifically for a given EJB by specifying values in the bean's property file. For more information, see Specifying Access Control. You can also create an ACL for a bean using the NAS Deployment Manager. For more information, see the Administration Guide.

Creating and Using Programmatic ACLs Programmatic ACLs are named lists in the Directory Server that relate a user or group with a permission, as in the following example ACL:

john_smith   write
managers     readwrite
employees    read 
In this example, the user john_smith and the group managers can both write to this resource, but john_smith (possibly a data-entry person) can not read from it. Members of the group employees can only read from the resource. You must then provide code in the resource to verify these permissions.

Once a client is authenticated and logged in, you can use the method isAuthorized() (in HttpSession2) to determine whether the current client is permitted to perform certain tasks. You provide the name of the ACL and the required permission.

The following example tests whether the current user is permitted to update a payroll record, and assume that there is an ACL called PayRollACL with permissions called update and view. This example is from a servlet. The same logic works in an EJB, though a client normally logs into a session from a servlet rather than from an EJB.

HttpSession session = req.getSession; 
HttpSession2 sess2 = (HttpSession2) session;
if ( sess2.loginSession(username,password) ) //log into session
{
    if ( sess2.isAuthorized("PayrollACL", "update") } 
    { updatePayrollEntries(); }
    else if ( sess2.isAuthorized("PayrollACL", "view") )
    { viewPayrollEntries(); }
    else
    { errorNotAllowed(); // return error page, not permitted }
}
ACLs and their permissions can be named anything. You create programmatic ACLs using the NAS Administration Tool. For more information, see Setting Access Control List Authorization in the Administration Guide.

 

© Copyright 1999 Netscape Communications Corp.