Sun Java System Application Server Platform Edition 8 Developer's Guide |
Chapter 2
Securing J2EE ApplicationsThis chapter describes how to write secure J2EE applications, which contain components that perform user authentication and access authorization for servlets and EJB business logic. For information about administrative security for the server, see the Sun Java System Application Server Administration Guide.
This chapter contains the following sections:
Sun Java System Application Server Security GoalsIn an enterprise computing environment, there are many security risks. The Sun Java System Application Server’s goal is to provide highly secure, interoperable, and distributed component computing based on the J2EE security model. Security goals include:
- Full compliance with the J2EE security model (for more information, see the J2EE specification, v1.4 Chapter 3 Security)
- Full compliance with the EJB v2.1 security model (for more information, see the Enterprise JavaBean specification v2.1 Chapter 15 Security Management). This includes EJB role-based authorization.
- Full compliance with the Java Servlet v2.3 security model (for more information, see the Java Servlet specification, v2.3 Chapter 11 Security). This includes servlet role-based authorization.
- Support for single sign-on across all Sun Java System Application Server applications within a single security domain.
- Security support for ACC Clients.
- Support for several underlying authentication realms, such as simple file and LDAP. Certificate authentication is also supported for SSL client authentication. For Solaris, OS platform authentication is supported in addition to these.
- Support for declarative security via Sun Java System Application Server specific XML-based role mapping.
- Support for JACC (Java Authorization Contract for Containers) pluggable authorization as included in the J2EE 1.4 specification and defined by JSR-115.
Sun Java System Application Server Specific Security FeaturesThe Sun Java System Application Server supports the J2EE v1.4 security model, as well as the following features which are specific to the Sun Java System Application Server:
Sun Java System Application Server Security ModelSecure applications require a client to be authenticated as a valid application user and have authorization to access servlets, JSPs, and EJB business logic. Sun Java System Application Server supports security for web, ACC, web service, and JMS clients.
Applications with secure web and EJB containers may enforce the following security processes for clients:
The following diagram shows the Sun Java System Application Server security model.
Web Application and URL Authorizations
Secure web applications may have authentication and authorization properties. The web container supports three types of authentication: basic, certificate, and form-based. When a browser requests the main application URL, the web container collects the user authentication information (for example, username and password) and passes it to the security service for authentication.
Sun Java System Application Server consults the security policies (derived from the deployment descriptors) associated with the web resource to determine the security roles used to permit resource access. The web container tests the user credentials against each role to determine if it can map the user to the role.
Invocation of Enterprise Bean Methods
Once the browser client has been authenticated and authorized by the web container and the servlet or JSP performs a method call to the EJB component, the user’s credentials (gathered during the authentication process) are propagated to the EJB container. A secure EJB container has a deployment descriptor with authorization properties, which are used to enforce access control on the bean method. The EJB container uses role information received from the EJB JAR deployment descriptors to decide whether it can map the caller to the role and allow access to the bean method.
ACC Client Invocation of Enterprise Bean Methods
For ACC clients, a secure EJB container consults its security policies (obtained from the deployment descriptors) to determine if the caller has the authority to access the bean method. This process is the same for both web and ACC clients.
Security Responsibilities OverviewA J2EE platform’s primary goal is to isolate the developer from the security mechanism details and facilitate a secure application deployment in diverse environments. This goal is addressed by providing mechanisms for the application security specification requirements declaratively and outside the application.
Application Developer
The application developer is responsible for the following:
- Specifying application roles.
- Defining role-based access restrictions for the application components (Servlets/JSPs and EJB components).
- If programmatic security is used, verifying the user roles and authorizing access to features based on these roles. (Programmatic security management is discouraged since it hard codes the security login in the application instead of allowing the containers to manage it.)
Application Assembler
The application assembler or application component provider must identify all security dependencies embedded in a component including:
Application Deployer
The Sun Java System Application Server deploytool is used to map the views provided by the assembler to the policies and mechanisms specific to the operational environment. The security mechanisms configured by the application deployer are implemented by the containers on behalf of the components hosted in the containers.
The application deployer takes all component security views provided by the assembler and uses them to secure a particular enterprise environment in the application, including:
Common Security TerminologyThe most common security processes are authentication, authorization, realm assignment, and role mapping. The following sections define this terminology.
Authentication
Authentication verifies the user. For example, the user may enter a username and password in a web browser, and if those credentials match the permanent profile stored in the active realm, the user is authenticated. The user is associated with a security identity for the remainder of the session.
Authorization
Authorization permits a user to perform the desired operations, after being authenticated. For example, a human resources application may authorize managers to view personal employee information for all employees, but allow employees to only view their own personal information.
Realms
A realm, also called a security policy domain or security domain in the J2EE specification, is a scope over which a common security policy is defined and enforced by the security administrator of the security service. Supported realms in Sun Java System Application Server are file, ldap, certificate, and solaris. For information about how to configure a realm, see Realm Configuration.
Role Mapping
A client may 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 the salary information. Employees with the right to view or change salaries might be defined as 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 who 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 are specific to a deployment domain. It is up to the deployer to map roles into one or more groups for each application or module.
In the Sun Java System Application Server, roles correspond to users or groups (or both) configured in the active realm.
Container SecurityThe component containers are responsible for providing J2EE application security. There are two security forms provided by the container:
Programmatic Security
Programmatic security is when an EJB component or servlet uses method calls to the security API, as specified by the J2EE security model, to make business logic decisions based on the caller or remote user’s security role. Programmatic security should only be used when declarative security alone is insufficient to meet the application’s security model.
The J2EE specification, v1.4 defines programmatic security as consisting of two methods of the EJB EJBContext interface and two methods of the servlet HttpServletRequest interface. The Sun Java System Application Server supports these interfaces as specified in the specification.
For more information on programmatic security, see the following:
Declarative Security
Declarative security means that the security mechanism for an application is declared and handled externally to the application. Deployment descriptors describe the J2EE application’s security structure, including security roles, access control, and authentication requirements.
The Sun Java System Application Server supports the DTDs specified by J2EE v1.4 and has additional security elements included in its own deployment descriptors. Declarative security is the application deployer’s responsibility.
There are two levels of declarative security, as follows:
Application Level Security
The application XML deployment descriptor (application.xml) contains authorization descriptors for all user roles for accessing the application’s servlets and EJB components. On the application level, all roles used by any application container must be listed in a role-name element in this file. The role names are scoped to the EJB XML deployment descriptors (ejb-jar.xml and sun-ejb-jar.xml files) and to the servlet XML deployment descriptors (web.xml and sun-web.xml files). The sun-application.xml file must also contain matching security-role-mapping elements for each role-name used by the application.
Component Level Security
Component level security encompasses web components and EJB components.
A secure web container authenticates users and authorizes access to a servlet or JSP by using the security policy laid out in the servlet XML deployment descriptors (web.xml and sun-web.xml files). Once the user has been authenticated and authorized, the servlet passes on user credentials to an EJB component to establish a secure association with the bean.
The EJB container is responsible for authorizing access to a bean method by using the security policy laid out in the EJB XML deployment descriptors (ejb-jar.xml and sun-ejb-jar.xml files).
Guide to Security InformationEach information type below 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, and so on.
Location:
The location of the user information depends on the realm being used:
- For the file realm, the users and groups are listed in the key file, which is located in domain_dir/config.
- For the ldap realm, the users and groups are stored in an external LDAP directory.
- For the certificate realm, the user identities are obtained from cryptographically verified client certificates in the cacerts.jks and keystore.jks files. These files are located in domain_dir/config by default.
- For the solaris realm, the users and groups are stored in the underlying Solaris user database, as determined by the system’s PAM configuration.
For more information about these realms, see Realm Configuration.
How to Create:
How to create users and define groups is specific to the realm being used. The Sun Java System Application Server does not provide administration capabilities for external realms such as Solaris/PAM or LDAP. Consult your Solaris or LDAP server documentation for details.
Security Roles
Role that defines an application function, made up of a number of users, groups, or both. The relationship between users and groups is determined by the specific realm implementation being used.
Location:
Roles are defined in the J2EE application deployment descriptors.
How to Create:
Use the Sun Java System Application Server Administration Console, the deploytool, or the asadmin deploy command for application assembly and deployment.
How To Access:
Use isCallerInRole() to test for a user’s role membership. For example, in the following code, if securedMethod() can be accessed by the Manager role, the call to sctx.isCallerInRole("Manager") returns true.
public class SecTestEJB implements SessionBean
{
private SessionContext sctx = null;
public void setSessionContext(SessionContext sc)
{
sctx = sc;
}
public void securedMethod( )
{
System.out.println( sctx.isCallerInRole( "Manager" ) );
}
}
Realm ConfigurationThis section covers the following topics:
How to Configure a Realm and Set the Default Realm
You can configure a realm in one of these ways:
If you use the Administration Console or edit the domain.xml file, you can set the default realm.
Using the Administration Console
To configure a realm using the Administration Console:
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Open the Security component.
- Open the Realms component under the Security component.
- Go to the Realms page.
- Click on the check boxes of the realms you wish to activate.
- Use the New and Delete buttons to add and remove realms. To edit a realm, click on its name.
- If you are adding or editing a realm, enter the realm’s name and classname.
- To add a property, click the Add Property button and enter the property name and value. To delete properties, check the properties you want to delete, then click the Delete Properties button.
- For the file realm, you can click on the Manage Users button to add, delete, or edit users. See file.
- Select the Save button to finish adding or editing the realm.
- Go to the Security page.
- Select a default realm, then select the Save button.
- Restart the server.
Using the asadmin Command
You can use the asadmin command to configure realms on local servers.
asadmin create-auth-realm
The asadmin create-auth-realm command configures a realm. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin create-auth-realm --user user --classname realm_class [--isdefault=true] [--property (name=value)[:name=value]*] realm_name
For more information about the optional general asadmin parameters (--password, --passwordfile, --host, --port, --secure, --terse, --echo, and --interactive), see the Sun Java System Application Server Administration Guide.
For example, the following command configures the certificate realm:
asadmin create-auth-realm --user joeuser --classname com.sun.enterprise.security.auth.realm.certificate.CertificateRealm certificate
asadmin delete-auth-realm
The asadmin delete-auth-realm command deactivates a realm. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin delete-auth-realm --user user realm_name
For example, the following command deactivates the certificate realm:
asadmin delete-auth-realm --user joeuser certificate
asadmin list-auth-realms
The asadmin list-auth-realms command lists all realms. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin list-auth-realms --user user [config_name]
For example, the following command lists all realms in the server1 instance:
asadmin list-auth-realms --user joeuser
Editing the domain.xml File
Behind the scenes, the default realm is set in the security-service element in the domain.xml file. The security-service configuration looks like this:
<security-service default-realm="file">
<auth-realm name="file"
classname="com.sun.enterprise.security.auth.realm.file.FileRealm">
<property name="file" value="domain_dir/config/keyfile"/>
<property name="jaas-context" value="fileRealm"/>
</auth-realm>
...
</security-service>The default-realm attribute points to the realm the server is using. It must point to one of the configured auth-realm names. The default is the file realm.
The audit flag determines whether auditing information is logged. If set to true, the server logs audit messages for all authentication and authorization events.
If you change the realm configuration, you must restart the server for the change to take effect.
For more information about the domain.xml file, see the Sun Java System Application Server Reference.
How to Set a Realm for an Application or Module
The following deployment descriptor elements have optional realm or realm-name data subelements that override the domain’s default realm:
If modules within an application specify conflicting realms, these are ignored. If present, the realm defined in sun-application.xml is used, otherwise the domain’s default realm is used.
For example, a realm is specified in sun-application.xml as follows:
<sun-application>
...
<realm>ldap</realm>
</sun-application>For more information about the deployment descriptor files and elements, see Chapter 5, “Deployment Descriptor Files.”
Supported Realms
The following realms are supported in Sun Java System Application Server:
file
The file realm is the default realm when you first install the Sun Java System Application Server. It has the following configuration characteristics:
Required properties are as follows:
The user information file is initially empty, so you must add users before you can use the file realm. You can configure users in one of these ways:
Using the Administration Console
To configure a user in the file realm using the Administration Console:
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Open the Security component.
- Open the Realms component under the Security component.
- Go to the file page.
- Click on the Manage Users button.
- To activate a user, check the box by the user’s name.
- To add a new user, click on the New button. To modify information for a user, click on the user’s name in the list. In either case, enter the following information:
- Click on the Save button.
- You do not need to restart the server.
Using the asadmin Command
The asadmin create-file-user command creates one user in the file realm. Its syntax is as follows, with defaults shown for optional parameters that have them:
asadmin create-file-user --user user [--userpassword user_password] [--authrealmname auth_realm_name] [--groups user_group[:user_group]*] user_name
For more information about the optional general asadmin parameters (--password, --passwordfile, --host, --port, --secure, --terse, --echo, and --interactive), see the Sun Java System Application Server Administration Guide.
For example, the following command adds user dsanchez to the file realm and assigns secret as this user’s password. The --user parameter specifies the administrative user.
asadmin create-file-user --user joeuser --userpassword secret dsanchez
The asadmin delete-file-user command removes one user from the file realm. Its syntax is as follows, with defaults shown for optional parameters that have them:
asadmin delete-file-user --user user user_name
For example, the following command removes user dsanchez from the file realm. The --user parameter specifies the administrative user.
asadmin delete-file-user --user joeuser dsanchez
The asadmin update-file-user command changes information for one user in the file realm. Its syntax is as follows, with defaults shown for optional parameters that have them:
asadmin update-file-user --user user [--userpassword user_password] [--groups user_group[:user_group]*] user_name
For example, the following command changes the password for user dsanchez to private. The --user parameter specifies the administrative user.
asadmin update-file-user --user joeuser --userpassword private dsanchez
The asadmin list-file-users command lists users in the file realm. Its syntax is as follows, with defaults shown for optional parameters that have them:
asadmin list-file-users --user user [config_name]
For example, the following command lists file realm users. The --user parameter specifies the administrative user.
asadmin list-file-users --user joeuser
The asadmin list-file-groups command lists groups in the file realm. Its syntax is as follows, with defaults shown for optional parameters that have them:
asadmin list-file-groups --user user [--name user_name] [config_name]
For example, the following command lists file realm groups for user dsanchez. The --user parameter specifies the administrative user.
asadmin list-file-groups --user joeuser --name dsanchez
ldap
The ldap realm allows you to use an LDAP database for user security information. It has the following configuration characteristics:
Required properties are as follows:
You can add the following optional properties to tailor the LDAP realm behavior.
- search-filter - The search filter to use to find the user. The default is uid=%s (%s expands to the subject name).
- group-base-dn - The base DN for the location of groups data. By default it is same as the base-dn, but it can be tuned if necessary.
- group-search-filter - The search filter to find group memberships for the user. The default is uniquemember=%d (%d expands to the user element DN).
- group-target - The LDAP attribute name that contains group name entries. The default is CN.
- search-bind-dn - An optional DN used to authenticate to the directory for performing the search-filter lookup. Only required for directories that do not allow anonymous search.
- search-bind-password - The LDAP password for the DN given in search-bind-dn.
You must create the user(s) in your LDAP directory. You can do this from the Sun Java System Directory Proxy Server 5 2004Q2 console in the Users & Groups main tab, or through any other administration tool which supports LDAP and your directory’s schema.
The principal-name used in the deployment descriptors must correspond to your LDAP user information.
For example, suppose an LDAP user, joe java, is defined in your LDAP directory as follows:
uid=jjava,ou=People,dc=acme,dc=com
uid=jjava
givenName=joe
objectClass=top
objectClass=person
objectClass=organizationalPerson
objectClass=inetorgperson
sn=java
cn=joe javaThe required properties in the ldap realm configuration would be as follows:
- The directory would be the LDAP URL to your server, for example:
ldap://ldap.acme.com:389
- The base-dn could be ou=People,dc=acme,dc=com. Note that it could also be rooted at a higher point, for example dc=acme,dc=com, but searches would traverse a larger part of the tree, impacting performance.
- The jaas-context must be ldapRealm.
certificate
The certificate realm supports SSL authentication. This realm sets up the user identity in the Sun Java System Application Server’s security context, and populates it with user data obtained from cryptographically verified client certificates in the cacerts.jks and keystore.jks files, which are located in domain_dir/config by default. The J2EE containers then handle authorization processing based on each user’s DN from his or her certificate. This realm has the following configuration characteristics:
You can add the following optional property to tailor the certificate realm behavior.
When you deploy an application, you must specify CLIENT-CERT as the authentication mechanism in the web.xml file as follows:
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>You must obtain a client certificate and install it in your browser to complete the setup for client certificate authentication. For details on how to set up the server and client certificates, see the Sun Java System Application Server Administration Guide.
You can configure SSL authentication in these ways:
- Configure an ssl subelement of an http-listener or iiop=listener element in domain.xml, then restart the server. For more information about the domain.xml file, see the Sun Java System Application Server Reference.
- Use the Administration Console, as follows:
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Open the HTTP Service or ORB component.
- Open the HTTP Listeners or IIOP Listeners component.
- Select the listener for which you want to configure SSL.
- Edit the SSL3/TLS Settings for the listener.
- Select the Save button.
- Restart the server.
You can change the location of the cacerts.jks and keystore.jks files as follows:
- Set the $TRUSTSTORE and $KEYSTORE system variables to the locations of the cacerts.jks and keystore.jks files.
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Go to the Application Server page.
- Select the JVM Settings tab and the General option (JVM is an abbreviation of Java Virtual Machine).
- Add the following to the Debug Options field:
-Djavax.net.ssl.trustStore=$TRUSTSTORE -Djavax.net.ssl.keyStore=$KEYSTORE
- Click Save.
- Restart the server.
solaris
The solaris realm allows authentication using Solaris username+password data. This realm is only supported on Solaris 9. It has the following configuration characteristics:
Required properties are as follows:
- jaas-context - The value must be solarisRealm.
Creating a Custom Realm
You can create a custom realm by providing a Java Authentication and Authorization Service (JAAS) login module and a realm implementation. Note that client-side JAAS login modules are not suitable for use with Sun Java System Application Server. For more information about JAAS, refer to the JAAS specification for Java 2 SDK, v 1.4, available here:
http://java.sun.com/products/jaas/
A sample application that uses a custom realm is available with the Sun Java System Application Server here:
install_dir/samples/security/realms
Custom realms must extend the com.sun.enterprise.security.auth.login.PasswordLoginModule class. This class extends javax.security.auth.spi.LoginModule. Custom realms must not extend LoginModule directly.
Custom login modules must provide an implementation for one abstract method defined in PasswordLoginModule:
abstract protected void authenticate() throws LoginException
This method performs the actual authentication. The custom login module must not implement any of the other methods, such as login(), logout(), abort(), commit(), or initialize(). Default implementations are provided in PasswordLoginModule which hook into Sun Java System Application Server infrastructure.
The custom login module can access the following protected object fields, which it inherits from PasswordLoginModule. These contain the user name and password of the user to be authenticated:
protected String _username;
protected String _password;
The authenticate() method must end with the following sequence:
String[] grpList;
// populate grpList with the set of groups to which
// _username belongs in this realm, if any
return commitAuthentication(_username, _password, _currentRealm, grpList);Custom realms must also implement a Realm class which extends the com.sun.enterprise.security.auth.realm.IASRealm class.
Custom realms must implement the following methods:
public void init(Properties props) throws BadRealmException, NoSuchRealmException
This method is invoked during server startup when the realm is initially loaded. The props argument contains the properties defined for this realm in domain.xml. The realm can do any initialization it needs in this method. If the method returns without throwing an exception, Sun Java System Application Server assumes the realm is ready to service authentication requests. If an exception is thrown, the realm is disabled.
public String getAuthType()
This method returns a descriptive string representing the type of authentication done by this realm.
public abstract Enumeration getGroupNames(String username) throws InvalidOperationException, NoSuchUserException
This method returns an Enumeration (of String objects) enumerating the groups (if any) to which the given username belongs in this realm.
JACC SupportJACC (Java Authorization Contract for Containers) is part of the J2EE 1.4 specification and defined by JSR-115. JACC defines an interface for pluggable authorization providers. This provides third parties with a mechanism to develop and plug in modules that are responsible for answering authorization decisions during J2EE application execution. The interfaces and rules used for developing JACC providers are defined in the JACC 1.0 specification.
The Sun Java System Application Server provides a simple file-based JACC-compliant authorization engine as a default JACC provider. As part of specifying an alternate provider, you can configure the provider in the Sun Java System Application Server in one of these ways:
Using the Administration Console
To specify an alternate JACC provider using the Administration Console:
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Open the Security component.
- Open the JACC Providers component under the Security component.
- Go to the JACC Providers page.
- Click on the check boxes of the JACC providers you wish to activate.
- Use the New and Delete buttons to add and remove JACC providers. To edit a JACC provider, click on its name.
- If you are adding or editing a JACC provider, enter the following information:
- Select the Save button.
- Restart the server.
Editing the domain.xml File
Behind the scenes, the JACC provider is set in the security-service element in the domain.xml file. The security-service configuration looks like this:
<security-service jacc="default">
...
<jacc-provider
name="default"
policy-provider="com.sun.enterprise.security.provider.PolicyWrapper"
policy-configuration-factory-provider="com.sun.enterprise.security.provider.PolicyConfigu rationFactoryImpl">
<property name="repository"
value="domain_dir/generated/policy"/>
</jacc-provider>
...
</security-service>For more information about the domain.xml file, see the Sun Java System Application Server Reference.
Pluggable Audit Module SupportYou can create a custom audit module. This section covers the following topics:
Configuring an Audit Module
To configure an audit module, you can perform one of the following tasks:
Using the Administration Console
To specify an audit module using the Administration Console:
- Login to the Administration Console by going to the following URL in your web browser:
http://host:port/asadmin
For example:
http://localhost:4848/asadmin
- Open the Security component.
- Open the Audit Modules component under the Security component.
- Go to the Audit Modules page.
- Click on the check boxes of the audit modules you wish to activate.
- Use the New and Delete buttons to add and remove audit modules. To edit an audit module, click on its name.
- If you are adding or editing an audit module, enter the following information:
- Select the Save button.
- Restart the server.
Using the asadmin Command
You can use the asadmin command to configure realms on local servers.
asadmin create-audit-module
The asadmin create-audit-module command configures an audit module. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin create-audit-module --user user --classname audit_module_class [--property (name=value)[:name=value]*] audit_module_name
For more information about the optional general asadmin parameters (--password, --passwordfile, --host, --port, --secure, --terse, --echo, and --interactive), see the Sun Java System Application Server Administration Guide.
For example:
asadmin create-audit-module --user joeuser --classname com.sun.enterprise.security.Audit audit1
asadmin delete-audit-module
The asadmin delete-audit-module command deactivates an audit module. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin delete-audit-module --user user audit_module_name
For example:
asadmin delete-audit-module --user joeuser audit1
asadmin list-audit-modules
The asadmin list-audit-modules command lists all audit modules. The syntax is as follows, with defaults shown for optional parameters that have them:
asadmin list-audit-modules --user user [config_name]
For example, the following command lists audit modules.
asadmin list-audit-modules --user joeuser
Editing the domain.xml File
Behind the scenes, an audit module can be set in the security-service element in the domain.xml file. The security-service configuration looks like this:
<security-service>
...
<audit-module
name="default"
classname="com.sun.enterprise.security.Audit">
<property name="auditOn" value="false"/>
</audit-module>
...
</security-service>The classname must extend com.sun.appserv.security.AuditModule.
For more information about the domain.xml file, see the Sun Java System Application Server Reference.
The AuditModule Class
You can create a custom audit module by implementing a class that extends com.sun.appserv.security.AuditModule. The AuditModule class provides default “no-op” implementations for each of the following methods, which your custom class can override.
public void init(Properties props)
This method is invoked during server startup when the audit module is initially loaded. The props argument contains the properties defined for this module in domain.xml. The module can do any initialization it needs in this method. If the method returns without throwing an exception, Sun Java System Application Server assumes the module realm is ready to service audit requests. If an exception is thrown the module is disabled.
public void authentication(String user, String realm, boolean success)
This method is invoked when an authentication request has been processed by a realm for the given user. The success flag indicates whether the authorization was granted or denied.
public void webInvocation(String user, HttpServletRequest req, String type, boolean success)
This method is invoked when a web container call has been processed by authorization. The success flag indicates whether the authorization was granted or denied. The req object is the standard HttpServletRequest object for this request. The type string is one of hasUserDataPermission or hasResourcePermission (see JSR-115).
public void ejbInvocation(String user, String ejb, String method, boolean success)
This method is invoked when an EJB container call has been processed by authorization. The success flag indicates whether the authorization was granted or denied. The ejb and method strings describe the EJB component and its method that is being invoked.
public void shutdown()
This method is invoked once, during normal server shutdown. It provides the audit module an opportunity to record server shutdown events and to perform any necessary internal cleanup.
The server.policy FileEach Sun Java System Application Server domain has its own standard J2SE policy file, located in the domain root directory, typically install_dir/domains/domain_dir/config. The file is named server.policy.
Sun Java System Application Server is a J2EE 1.4-compliant application server. As such, it follows the requirements of the J2EE specification, including the presence of the security manager (the Java component that enforces the policy) and a limited permission set for J2EE application code.
This section covers the following topics:
Default Permissions
Internal server code is granted all permissions. These are covered by the AllPermission grant blocks to various parts of the server infrastructure code. Do not modify these entries.
Application permissions are granted in the default grant block. These permissions apply to all code not part of the internal server code listed previously. Sun Java System Application Server does not distinguish between EJB and web module permissions. All code is granted the minimal set of Web component permissions (which is a superset of the EJB minimal set).
A few permissions above the minimal set are also granted in the default server.policy file. These are necessary due to various internal dependencies of the server implementation. J2EE application developers must not rely on these additional permissions.
One additional permission is granted specifically for using connectors. If connectors are not used in a particular domain, you should remove this permission, because it is not otherwise necessary.
Changing Permissions for an Application
The default policy for each domain limits the permissions of J2EE deployed applications to the minimal set of permissions required for these applications to operate correctly. If you develop applications that require more than this default set of permissions, you can edit the server.policy file to add the custom permissions that your applications need.
You should add the extra permissions only to the applications that require them, not to all applications deployed to a domain. Do not add extra permissions to the default set (the grant block with no codebase, which applies to all code). Instead, add a new grant block with a codebase specific to the application requiring the extra permissions, and only add the minimally necessary permissions in that block.
As noted in the J2EE specification, an application should provide documentation of the additional permissions it needs. If an application requires extra permissions but does not document the set it needs, contact the application author for details.
As a last resort, you can iteratively determine the permission set an application needs by observing AccessControlException occurrences in the server log. If this is not sufficient, you can add the -Djava.security.debug=all JVM option to the domain. For details, see the Sun Java System Application Server Administration Guide or the Sun Java System Application Server Reference.
You can use the J2SE standard policytool or any text editor to edit the server.policy file. For more information, see:
http://java.sun.com/docs/books/tutorial/security1.2/tour2/index.html
For detailed information about the permissions you can set in the server.policy file, see:
http://java.sun.com/j2se/1.4/docs/guide/security/permissions.html
The Javadoc for the Permission class is here:
http://java.sun.com/j2se/1.4/docs/api/java/security/Permission.html
Programmatic LoginProgrammatic login allows a deployed J2EE application to invoke a login method. If the login is successful, a SecurityContext is established as if the client had authenticated using any of the conventional J2EE mechanisms.
Programmatic login is useful for an application that has special needs which cannot be accommodated by any of the J2EE standard authentication mechanisms.
Note
Programmatic login is specific to Sun Java System Application Server and not portable to other application servers.
This section contains the following topics:
Precautions
The Sun Java System Application Server is not involved in how the login information (user, password) is obtained by the deployed application. Programmatic login places the burden on the application developer with respect to assuring that the resulting system meets their security requirements. If the application code reads the authentication information across the network, it is up to the application to determine whether to trust the user.
Programmatic login allows the application developer to bypass the application server-supported authentication mechanisms and feed authentication data directly to the security service. While flexible, this capability should not be used without some understanding of security issues.
Since this mechanism bypasses the container-managed authentication process and sequence, the application developer must be very careful in making sure that authentication is established before accessing any restricted resources or methods. It is also the application developer’s responsibility to verify the status of the login attempt and to alter the behavior of the application accordingly.
The programmatic login state does not necessarily persist in sessions or participate in single sign-on.
Lazy authentication is not supported for programmatic login. If an access check is reached and the deployed application has not properly authenticated via the programmatic login method, access is denied immediately and the application may fail if not properly coded to account for this occurrence.
Granting Programmatic Login Permission
The ProgrammaticLoginPermission permission is required to invoke the programmatic login mechanism for an application. This permission is not granted by default to deployed applications because this is not a standard J2EE mechanism.
To grant the required permission to the application, add the following to the domain_dir/config/server.policy file:
grant codeBase "file:jar_file_path" {
permission com.sun.appserv.security.ProgrammaticLoginPermission
"login";
};The jar_file_path is the path to the application’s JAR file.
For more information about the server.policy file, see The server.policy File.
The ProgrammaticLogin Class
The com.sun.appserv.security.ProgrammaticLogin class enables a user to perform login programmatically. This class has four login methods, two for servlets or JSPs and two for EJB components.
The login methods for servlets or JSPs have the following signatures:
public Boolean login(String user, String password, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
public Boolean login(String user, String password, String realm, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, boolean errors) throws Exception
The login methods for EJB components have the following signatures:
public Boolean login(String user, String password)
public Boolean login(String user, String password, String realm, boolean errors) throws Exception
All of theselogin methods:
The methods with errors flags propagate to the caller any exceptions encountered during the authentication and return true upon a successful authentication. The login occurs on the realm specified unless it is null, in which case the domain’s default realm is used. The methods with no realm parameter use the domain’s default realm.
The logout method for servlets or JSPs has the following signature:
public Boolean login(String user, String password, String realm, HttpServletRequest request, HttpServletResponse response, boolean errors) throws Exception
The logout method for EJB components has the following signature:
public Boolean login(String user, String password, String realm, boolean errors) throws Exception
The errors flags are used to propagate to the caller any exceptions encountered during the logout. These methods return true upon a successful logout. The logout occurs on the realm specified unless it is null, in which case the domain’s default realm is used.
User Authentication for Single Sign-onThe single sign-on across applications on the Sun Java System Application Server is supported by the Sun Java System Application Server servlets and JSPs. This feature allows multiple applications that require the same user sign-on information to share this information between them, rather than having the user sign-on separately for each application. These applications are created to authenticate the user one time, and when needed this authentication information is propagated to all other involved applications.
An example application using the single sign-on scenario could be a consolidated airline booking service that searches all airlines and provides links to different airline web sites. Once the user signs on to the consolidated booking service, the user information can be used by each individual airline site without requiring another sign-on.
Single sign-on operates according to the following rules:
- Single sign-on applies to web applications configured for the same realm and virtual server. The realm is defined by the realm-name element in the web.xml file. For information about virtual servers, see the Sun Java System Application Server Administration Guide or the Sun Java System Application Server Reference.
- As long as users access only unprotected resources in any of the web applications on a virtual server, they are not challenged to authenticate themselves.
- As soon as a user accesses a protected resource in any web application associated with a virtual server, the user is challenged to authenticate himself or herself, using the login method defined for the web application currently being accessed.
- Once authenticated, the roles associated with this user are used for access control decisions across all associated web applications, without challenging the user to authenticate to each application individually.
- When the user logs out of one web application (for example, by invalidating or timing out the corresponding session if form based login is used), the user’s sessions in all web applications are invalidated. Any subsequent attempt to access a protected resource in any application requires the user to authenticate himself or herself again.
The single sign-on feature utilizes HTTP cookies to transmit a token that associates each request with the saved user identity, so it can only be used in client environments that support cookies.
To configure single sign-on, set the following properties in the virtual-server element of the domain.xml file:
- sso-enabled - If false, single sign-on is disabled for this virtual server, and users must authenticate separately to every application on the virtual server. The default is true.
- sso-max-inactive-seconds - Specifies the time after which a user’s single sign-on record becomes eligible for purging if no client activity is received. Since single sign-on applies across several applications on the same virtual server, access to any of the applications keeps the single sign-on record active. The default value is 5 minutes (300 seconds). Higher values provide longer single sign-on persistence for the users at the expense of more memory use on the server.
- sso-reap-interval-seconds - Specifies the interval between purges of expired single sign-on records. The default value is 60.
Here is an example configuration with all default values:
<virtual-server id="server1" ... >
...
<property name="sso-enabled" value="true"/>
<property name="sso-max-inactive-seconds" value="300"/>
<property name="sso-reap-interval-seconds" value="60"/>
</virtual-server>
Defining RolesYou define roles in the J2EE deployment descriptor file, web.xml, and the corresponding role mappings in the Sun Java System Application Server deployment descriptor file, sun-application.xml (or sun-web.xml for individually deployed web modules).
For more information regarding web.xml elements, see Chapter 13, “Deployment Descriptor,” of the Java Servlet Specification, v2.3. For more information regarding sun-web.xml and sun-application.xml elements, see Chapter 5, “Deployment Descriptor Files.”
Each security-role-mapping element in the sun-application.xml or sun-web.xml file maps a role name permitted by the web application to principals and groups. For example, a sun-web.xml file for an individually deployed web module might contain the following:
<sun-web-app>
<security-role-mapping>
<role-name>manager</role-name>
<principal-name>jgarcia</principal-name>
<principal-name>mwebster</principal-name>
<group-name>team-leads</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>administrator</role-name>
<principal-name>dsmith</principal-name>
</security-role-mapping>
</sun-web-app>Note that the role-name in this example must match the role-name in the security-role element of the corresponding web.xml file.
Note that for J2EE applications (EAR files), all security role mappings for the application modules must be specified in the sun-application.xml file. For individually deployed web modules, the roles are always specified in the sun-web.xml file. A role can be mapped to either specific principals or to groups (or both). The principal or group names used must be valid principals or groups in the current default realm.
Authenticating an Application Client Using the JAAS ModuleUsing the JAAS module, you can provide security in your application client code by creating a LoginModule that describes the interface implemented by authentication technology providers. For general information about application clients, see Chapter 9, "Developing Java Clients."
The following steps are involved in creating a LoginModule:
- Write the LoginModule interface.
public class ClientPasswordLoginModule implements LoginModule{
private static Logger _logger=null;
static{
_logger=LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
}
}
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
...
}The standard JAAS package required by this class is javax.security. The code line below illustrates how you can import the package in your client application:
import javax.security.*;
- Initialize the LoginModule interface that you just created.
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
}- Use login() method to fetch the login information from the client application and authenticate the user.
public boolean login() throws LoginException {
if (uname != null) {
username = new String (uname);
pswd = System.getProperty (LOGIN_PASSWORD);
...
}The login information is fetched using the CallBackHandler.
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback(localStrings.getLocalString("login.username", "ClientPasswordModule username: "));
callbacks[1] = new PasswordCallback(localStrings.getLocalString("login.password", "ClientPasswordModule password: "), false);
username = ((NameCallback)callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
The login() method tries to connect to the server using the login information that is fetched. If the connection is established, the method returns the value true.
- Use commit() method to set the subject in the session to the user name that is verified by the login method. If the commit method returns a value true, then this method associates PrincipalImpl with the subject located in the LoginModule. If this LoginModule’s own authentication attempt is failed, then this method removes any state that was originally saved.
public boolean commit() throws LoginException {
if (succeeded == false) {
return false;
} else {
// add a Principal (authenticated identity)to the Subject
// assume the user we authenticated is the PrincipalImpl
userPrincipal = new PrincipalImpl(username);
...
}- Use logout() method to remove the privilege settings associated with the roles of the subject.
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
succeeded = false;
succeeded = commitSucceeded;
username = null;
if (password != null) {
for (int i = 0; i < password.length; i++)
password[i] = ’ ’;
password = null;
}
userPrincipal = null;
return true;
}- Edit the sun-acc.xml deployment descriptor to configure JAAS authentication for the client.
- Integrate the LoginModule with the application server. Edit the deployment descriptor to make the following changes:
- Assemble the application client.
Sample Code
The sample code of ClinetLoginPasswordModule is given below:
package com.sun.enterprise.security.auth.login;
import java.util.*;
import java.io.IOException;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import com.sun.enterprise.security.auth.login.PasswordCredential;
import com.sun.enterprise.security.PrincipalImpl;
import com.sun.enterprise.security.auth.LoginContextDriver;
import com.sun.enterprise.util.LocalStringManagerImpl;
import java.util.logging.*;
import com.sun.logging.*;public class ClientPasswordLoginModule implements LoginModule {
private static Logger _logger=null;
static{
_logger=LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
}private static final String DEFAULT_REALMNAME = "default";
private static LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(ClientPasswordLoginModule.class);// initial state
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;private boolean debug =
com.sun.enterprise.util.logging.Debug.enabled;// the authentication status
private boolean succeeded = false;
private boolean commitSucceeded = false;// username and password
private String username;
private char[] password;private final PasswordCredential passwordCredential=null;
// testUser’s PrincipalImpl
private PrincipalImpl userPrincipal;
public static String LOGIN_NAME = "j2eelogin.name";
public static String LOGIN_PASSWORD = "j2eelogin.password";public void initialize(Subject subject, CallbackHandler
callbackHandler, Map sharedState, Map options) {this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;// initialize any configured options
debug =
"true".equalsIgnoreCase((String)options.get("debug"));}
/* Authenticate the user by prompting for a username and password. @return true in all cases since this <code>LoginModule</code> should not be ignored.*/
/* @exception FailedLoginException if the authentication fails. @exception LoginException if this <code>LoginModule</code> is unable to perform the authentication.*/
public boolean login() throws LoginException {
// prompt for a username and password
if (callbackHandler == null){
String failure =
localStrings.getLocalString("login.nocallback","Error:
no CallbackHandler available to garner authentication
information from the user");throw new LoginException(failure);
}String uname = System.getProperty (LOGIN_NAME);
String pswd;if (uname != null) {
username = new String (uname);
pswd = System.getProperty (LOGIN_PASSWORD);
char[] dest;
if (pswd == null){
dest = new char[0];
password = new char[0];
} else {
int length = pswd.length();
dest = new char[length];
pswd.getChars(0, length, dest, 0 );
password = new char[length];
}
System.arraycopy (dest, 0, password, 0, dest.length);
} else {
Callback[] callbacks = new Callback[2];
callbacks[0] = new
NameCallback(localStrings.getLocalString("login.username",
"ClientPasswordModule username: "));
callbacks[1] = new
PasswordCallback(localStrings.getLocalString("login.password",
"ClientPasswordModule password: "), false);
}try {
callbackHandler.handle(callbacks);
username = ((NameCallback)callbacks[0]).getName();
if(username == null){
String fail =
localStrings.getLocalString("login.nousername",
"No user specified");
throw new LoginException(fail);
}char[] tmpPassword =
((PasswordCallback)callbacks[1]).getPassword();if (tmpPassword == null) {
// treat a NULL password as an empty password
tmpPassword = new char[0];
}
password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0,
password, 0, tmpPassword.length);
((PasswordCallback)callbacks[1]).clearPassword();
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
String nocallback =
localStrings.getLocalString("login.callback","Error:
Callback not available to garner authentication
information from user(CallbackName):" );throw new LoginException(nocallback +
uce.getCallback().toString());}
// print debugging information
if (debug) {for (int i = 0; i < password.length; i++){
//System.out.print(password[i]);
}
//System.out.println();
}// by default - the client side login module will always say
// that the login successful. The actual login will take place
// on the server side.
if (debug) {
_logger.log(Level.FINE," [ClientPasswordLoginModule] "
+"authentication succeeded");
succeeded = true;
return true;
}}
public boolean commit() throws LoginException {
if (succeeded == false) {
return false;
} else {
// add a Principal (authenticated identity)to the Subject
// assume the user we authenticated is the PrincipalImpl
userPrincipal = new PrincipalImpl(username);
if (!subject.getPrincipals().contains(userPrincipal))
subject.getPrincipals().add(userPrincipal);
if (debug) {
_logger.log(Level.FINE,"[ClientPasswordLoginModule] "
+ "added PrincipalImpl to Subject");
}PasswordCredential pc = new PasswordCredential(username,
new String(password), realm);
if(!subject.getPrivateCredentials().contains(pc))subject.getPrivateCredent ials().add(pc);username = null;
for (int i = 0; i < password.length; i++){
password[i] = ’ ’;
password = null;
commitSucceeded = true;
return true;
}
}
}public boolean abort() throws LoginException {
if (succeeded == false) {
return false;
} else if (succeeded == true && commitSucceeded == false) {
// login succeeded but overall authentication failed
succeeded = false;
username = null;
if (password != null) {
for (int i = 0; i < password.length; i++)
password[i] = ’ ’;
password = en das ull;
}userPrincipal = null;
} else {// overall authentication succeeded and commit succeeded,
// but someone else’s commit failed
logout();
}
return true;
}public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
succeeded = false;
succeeded = commitSucceeded;
username = null;
if (password != null) {
for (int i = 0; i < password.length; i++)
password[i] = ’ ’;
password = null;
}
userPrincipal = null;
return true;
}}