Table of Contents
This chapter describes the concepts, structure, and key features of the security system.
Basic security definition is used to prevent and detect various types of attacks including an internal attack. A similar concept can be applied to an enterprise or computer environment that handles and provides user information.
The security targets are name, password, and address of users, and resources that provide a service or operate the system. Each system uses a security related software or implements a hardware related security system to protect its critical data and system resources.
The JEUS security service is based on SPI (Service Provider Interface), it provides various security service types to protect user information and resources registered with JEUS.
This guide covers the JEUS security structure and security related information.
The JEUS security system aimed for high design goals. In summary, the new security system should:
Have a flexible and pluggable framework.
Necessary for integrating the security system with any existing 3rd-party security mechanism and/or persistent storage mechanism.
Ensure security.
Prevent any unauthorized access to the system, even in the case when a very clever hacker with an ill intent de-compiles the security system sources.
Provide high performance.
The involvement of security system in the system and application code should have a minimal impact on the overall performance. Note that there is a trade off here: the degree of system security will adversely affect system performance. JEUS security system is designed for high performance and maximum security.
Provide a simple, unambiguous API and SPI for facilitating maintenance and the creation of 3rd party security services.
Maintain data integrity.
Conform with the standards.
JEUS security system satisfies all of the aforementioned high-level goals.
The key features of the new JEUS security system are summarized in the following list. The security system:
Has an open architecture and framework with a complete set of security integration SPI for customers and 3rd parties to use as needed.
Fully supports dynamic principal-to-role and role-to-resource authorization mappings.
This means that the authorization mappings (principal-to-role, Role-to-Resource mapping) are applied at runtime.
This enables the following security policies:
User U is granted the R role only during the 9 to 5 business hours, Monday to Friday
Everyone is granted the R role
No-one is granted the R role
Supports the concept of a security domain (hereafter domain). This allows different J2EE applications access different security services.
Note that domain and security domain refer to different concepts in the JEUS system. In the system, a domain refers to a server management unit and a security domain refers to a security management unit.
Provides default implementations of all critical security operations such as authentication, authorization, repositories, auditing, and clustering.
Supports security auditing mechanisms through a flexible event handling model.
Enables one to programmatically add simple security functions, limited to functions like adding subjects and policies, to the Servlet, EJB, and application source codes.
Fully supports JDK 1.6 and JACC 1.4 specifications.
Provides full support through this document and additional Javadoc.
Runs independently from other JEUS modules, which makes it easy to use in a different context.
The basic architecture of the security system is summarized in the following figure.
The main components (package) of the previous figure are
:
The large box in the middle represents the most central aspect of the security system: the security SPI classes. These abstract classes contain methods that are called by user code (JEUS containers etc.), as well as abstract methods that will be implemented by third party sub-classes.
As shown, there are currently 11 SPI classes available, each related to a specific aspect of security, such as authentication and authorization.
Repository and external security mechanism
At the bottom of the figure are the repositories and external security mechanisms.
Examples of repositories are databases, LDAP servers, or XML files. The repositories are used to persistently store security attributes, such as Subject and Policy information.
External security mechanisms refer to mechanisms that perform authentication or authorization. An example of an external security mechanism is the JACC provider. However, the boundaries for plain repositories and security mechanisms are not clearly defined. As shown, it is the responsibility of the SPI implementation classes (in this case, the class included in jeus.security.impl.* package) to decide which repository and security mechanism to apply.
This chapter covers the core concepts necessary to understand the overall security system.
In the JEUS security system, a login process is simply associating a Subject with an execution thread (Java thread). This concept is thus different from the concept of authentication. In general, authentication occurs before the Subject is associated with an execution thread. If the authentication is successful, login will proceed as normal, but if the authentication fails, login will also fail.
After a Subject has logged in successfully, all authorization will be performed with respect to this Subject. The login concept may thus be seen as an umbrella that spans both authentication and authorization. The opposite of the login operation is the logout operation, which disassociates the current Subject from the execution thread.
Note that the implementation of the login concept requires a stack-based operation. Several Subjects can be logged in at any time with each new Subject being pushed onto the top of the stack. Only the Subject on top of the stack is used for authorization. When the Subject logs out, the top Subject is simply removed from the stack, and the next Subject at the top of the stack is activated.
This mechanism is shown in the following.
In the JEUS security system, only one login stack is allowed for each Java thread. As shown in the Security System Architecture figure, the login mechanism is implemented by the jeus.security.impl.login.CommonLoginService interface.
Authentication is determining the identity of a caller for the purpose of using it for authorization decisions at a later time.
In the JEUS security system, identities are always represented as principals that are defined by the java.security.Principal interface.
These Principals are always stored as attribute values of the Subject. Subject is implemented by the jeus.security.base.Subject class and gets associated with an execution thread, as previously described. Subject also contains Principals and Credentials as its security attributes.
The Subject implementation used in the JEUS security system is NOT equivalent to the JAAS Subject defined by the class javax.security.auth.Subject. However, many similarities exist between these two implementations, and in general, it is possible to convert from one to the other. Even if some information is lost, an alias can be used to refer to it.
The following is a UML diagram for a JEUS Subject.
As shown, the Subject has a main Principal, which is the only
ID of the Subject. The Subject may also carry any number of additional
optional Principals. These are generally non-unique Principals that may
be shared by several Subjects (e.g., group Principals).
Subject can also have public or private credentials. Credentials are usually used as a proof to authenticate the Subject or to deliver specific information. An example of a private credential is a password. An example of a public credential is a digital certificate.
The credentials for a given Subject may be created by using its sub-class, credentialFactory class. The actual credentials are obtained from the credential factories using the refresh() method, and they are added to the public or private credential sets.
Each Subject always belongs to exactly one domain. A Subject with main principal user1 in domain A is thus different from another Subject with main principal user1 in domain B.
In the JEUS security system, authorization is determining whether a previously authenticated entity (Subject) should be allowed to perform a particular operation.
Authorization happens at the system level by, for example, allowing only certain Subjects (usually administrators) to boot or shut down the JEUS server. Authorization also happens at the application level when a JEUS engine checks whether a remote caller should be allowed to access a particular application component, such as a specific EJB method or a certain Servlet.
In the JEUS security system, like in J2EE, authorization is a role-based mechanism. The developer or assembler of a J2EE application sets up the security restrictions according to Roles. During the deployment of the application, the deployer or administrator maps actual Principals in the system to these logical Roles. .
ote that the role-based approach is also used for JEUS system authorization as well as for J2EE applications.
Furthermore, in the JEUS security system, all authorization mappings are expressed as Permissions (actual sub-classes of java.security.Permission). For example, the Principal, user1, may own a Permission that grants him access to a role called R (meaning that user1 is in role R).
The role R may have permission to access the resource JNDI and execute the lookup action.
These concepts are illustrated in the following figure.
As can be seen from the previous figure, only Principals and Roles are actually represented as physical entities. The resource circle in the figure has a dashed outline to denote that resources are implied and not actually modeled in the authorization system.
In the previous figure, the two boxes marked RolePermission and ResourcePermission represent instances of the two classes jeus.security.resource.RolePermission and jeus.security.resource.ResourcePermission, respectively. Both of these classes extend the basic java.security.Permission abstract class, and there are various other sub-classes of the Permission class.
To summarize, a principal owns a set of Permissions and those Permissions grant the principal a set of logical Roles. These Roles in turn own another set of Permissions that grant those Roles access to a set of Actions on the Resources. By following these indirect mappings, one can deduce whether a principal should be allowed to perform a specific Action on a Resource.
The figure above shows that the principal user1 owns a RolePermission. The arrows marked "Owns" in the figure intuitively denotes a direct, static binding. However, the term implies is different. The figure shows that the RolePermission implies role R. It is important to note that this implication binding is not static. It is determines the implication status dynamically at runtime by invoking the method implies(Permission p) on then RolePermission instance.
If the implies() method returns true, the RolePermission is said to imply role R, otherwise it is not. Thus, in the former case, principal user1 is in role R, while in the latter case it is not. The same logic applies for the implication between the role R and the Resource JNDI. For a better understanding of the terminology Permission, refer to the java.security.Permission of J2SE Javadoc.
For more information about Permission refer to the java.security.Permission section in J2SE Javadoc.
Given the previous information, it is not difficult to implement dynamic mappings. If we just change the implementation of the implies() method, we can make a Permission imply a role (or Resource) only under certain special conditions. For example, we might want to create a dynamic mapping from principal user1 to role R, which allows user1 to be in role R only during the business hours (9am to 5pm). To do this, we could simply create a new RolePermission sub-class, called TimeConstrainedRolePermisson, and override the implementation of the implies() method. In this method, you can add a check for the additional time-constraint.
For examples, refer to [Figure 1.5] and [Figure 1.6].
As shown in [Figure 1.5], principal user1 is not part of role R.
As shown in the previous figures, the TimeConstrainedRolePermission class contains two variables, Name and Actions. Name is set to the name of the implied Role, R in this case, and the Actions are set to the times when the implication is valid (between 9am and 5pm). Both Name and Actions are standard variables that are declared in most java.security.Permission class implementations.
Moreover, apart from the basic Permission-based mappings, every Permission in the authorization system belongs to one of the following three categories.
A few examples to illustrate these ideas will be shown later.
In the JEUS security system, all Permission mappings are the classes that implement the jeus.security.base.PermissionMap class. These PermissionMap classes are included in the jeus.security.base.Policy class.
Policy class has two kinds of PermissionMaps.
Principal-to-Role Map(Role Policy0)
Role-to-Resource Map(Resource Policy)
Each PermissionMap contains the 3 aforementioned Permission types, excluded, unchecked and checked permissions. In the case of checked permissions, Permission and role PermissionMap are combined through a principal or Role. Policy and Resource PermissionMap are combined through a context id, which indicates the authorization scope.
The following is a UML diagram of Policy and PermissionMap classes.
All the information is summarized in the following figure.
In the previous figure, we have a Policy instance that contains one principal-to-role mapping (required) and also two role-to-resource mappings with context ids A and B, respectively. All three PermissionMaps contain three sets of permissions as follows.
The elliptical bubbles inside the boxes represent the actual Permission instances (Name: Action) with Name and Action variables.
Assuming that a Subject, with context ID A and the principal user1, wants to access JNDI to perform the action "modify", will user1 be able to perform this action?
The authorization system (actually the Policy implementation) would process this authorization query as follows:
A new ResourcePermission, let's call it RSP, is created with Name of JNDI and Actions of modify.
RSP is passed along with the context ID A and principal user1 to the Policy.
The Role-to-ResourcePermissionMap for context ID A is selected by the Policy.
Policy checks whether Excluded Permission of PermissionMap A contains RSP, and receives the result that RSP is not included in Excluded Permission.
Policy checks whether Unchecked Permission of PermissionMap A contains RSP, and receives the result that RSP is not included in Unchecked Permission.
Policy checks whether Checked Permission of PermissionMap A contains RSP, and receives the result that RSP is included in Checked Permission.
Policy retrieves a list of Permission owners that implied RSP, and finds that there is only one such owner, the role called Administrator.
Policy constructs a RolePermission object with the Name, Administrator. Lets call this RolePermission RLP.
Policy checks whether Excluded Permission of Principal-to-RolePermission contains RLP, and receives the result that RLP is included in Excluded Permission.
The fact RLP is included in Excluded Permission indicates that the role Administrator has Excluded Permission. Therefore, nobody can access the Policy. As a result, the entire authorization process will be terminated, and the value, DENIED, will be returned.
In this process, although user1 is mapped to the role Administrator, since Administrator is also in the excluded set, no one (not even user1) will be in the role Administrator. This is because excluded Permissions have higher precedence over both unchecked and checked Permissions.
Using the previous figure and following the step-by-step instructions above, you should be able to work out the following authorization queries.
[Table 1.1] Examples of Authorization Queries and the Outcomes
Principal | Operation | Context | Outcome |
---|---|---|---|
user1 | JNDI:lookup | A | GRANTED |
user1 | JNDI:modify | A | DENIED |
user1 | JEUS:boot | A | DENIED |
user1 | JEUS:boot | B | GRANTED |
Anonymous | JNDI:lookup | A | GRANTED |
Anonymous | JNDI:lookup | B | DENIED |
Anonymous | JEUS:boot | A | DENIED |
Anonymous | JEUS:boot | B | DENIED |
Security auditing generally involves capturing security-related events (such as failed authentication and runtime exceptions) and evaluating these events for better overall security.
The JEUS security system features a simple yet flexible auditing mechanism using security events. Whenever something significant happens in the system, such as a failed authentication, a failed authorization, or something else that may be of interest, an Event will be posted to a set of registered event handlers.
The handler implementations, which may be fully customized, responds with an appropriate action, such as locking a Subject's credential in case authentication failed too many times in a row.
As we have mentioned before, each class in the security system that implements security functionalities constitutes as a Service. A Service is simply an implementation of an SPI (Service Provider Interface) that provides some security functionality, whether it is authentication, authorization, networking, or other things.
SPI is short for Service Provider Interface and is an abstract class of the Java package jeus.security.spi. These SPI classes should be extended and implemented in order to implement customized security functionality. The extended sub-classes of an SPI class are called Services.
All instances of Services in the security system are treated individually as independent entities whose services are called as needed. However, it is also quite common for a Service implementation to make calls to another SPI, and some dependency may exist among different Services. In order to initialize Services. All Services receives a key–value pair property value used to initialize the Service. The configuration data of a Service can also be saved in a configuration file.
All Services may also optionally define a JMX bean that will be exported to the JEUS management system. The JMX MBean is normally created based on a MBeanInfo instance returned by the Service.getMBeanInfo() method.
All Services have two states, created state and destroyed state. The create() and destroy() methods are called to transition between the two states. Calling these methods will invoke doCreate() and doDestroy() abstract methods. These abstract methods should be implemented by Service sub-classes for service initialization and management.
Following is the Service class
diagram and various SPI classes in the jeus.security.spi package.
At runtime, Service instances are created by the singleton
class called SecurityInstaller. A simple SecurityInstaller class can be
implemented just by writing the necessary code. A more sophisticated
implementation would save the service name and property values to a
specific configuration file and use the information to instantiate and
initialize the Service. The default SecurityInstaller implementation
operates according to the latter approach, providing a very simple and
flexible way to add new Service implementations to the security
system.
Users do not need to understand the Service and SPI architecture when only using the JEUS security system.
Security domain is a collection of security Service instances. Several domains may exist concurrently within the security system. The purpose of a domain is to allow different deployed applications and JEUS sub-systems to use different security Services. A domain separates the security Services for each application.
For example, the JEUS server could be set up to use a special domain. In this case, it's call the SYSTEM_DOMAIN. This domain contains Subjects and Policies that are used to manage the JEUS server. For example, the SYSTEM_DOMAIN contains the user information for a main Subject called administrator, which can be used to boot or shut down the server.
Another domain, let's call it APP_DOMAIN, could be used by a deployed J2EE application. That domain might also contain a user information for a Subject called administrator, which is different from the JEUS server administrator. You could also configure a different repository mechanism for each domain. While the SYSTEM_DOMAIN can be configured to use a simple XML file to store Subject information, the APP_DOMAIN can be configured to use a remote database to read and write Subject information.
The domain concept is illustrated in the following figure.
Use of the domain feature is optional. If no domain is
specified, a special SYSTEM_DOMAIN will be used.
It is our convention to name domains using capital letters and to append "_DOMAIN" to the name. This is not a requirement, just a convention. Also note that whenever the term domain is used within this document, it refers to the Security domain. These Security domains have nothing in common with J2EE server domains.
By default, JEUS uses two domains, SYSTEM_DOMAIN and SHARED_DOMAIN, as follows:
The domain name that is used when managing the JEUS server through its standard management tools (this domain contains JEUS administrator accounts and permissions to manage the JEUS server, such as booting and shutting down).
The name of a special domain whose security services will be shared by all other configured domains. Thus, the SHARED_DOMAIN contains security services that will be applied to all other domains.
To apply different security services to applications, create a separate domain and configure the domain.xml file. For more information about creating and configuring security domains, refer to "Chapter 2. Configuring the Security System".
To a certain degree, the information given in this chapter conflicts with the attributes a security system must have. Basically, there is always a trade-off between performance and security. Thus, users need to control the level of performance and security to an appropriate level according to the task requirements.
This chapter explains how to minimize the performance impact that the security system has on the overall performance of the JEUS Server.
The following are the ways of improving performance of the overall security system.
Do Not Use Secured Connection in JEUS Domain.
Secured connection uses a socket to send an encoded packet, which means that larger amount of data will be transmitted than with a general socket communication.
To improve performance, it is recommended not to use secured connections in JEUS domain.
Do Not Use JEUS SecurityManager
You can avoid executing unnecessary operations by not using the SecurityManager. This means that authorization is not used, but instead authentication is required.
Network blocking occurrences can be reduced by using Non-Blocking I/O. Non Blocking I/O removes blocking while waiting for the next I/O request to occur.
Therefore, CPU usage and the number of FD are reduced because a separate thread for I/O is not needed for each connection. Non Blocking I/O is used in JEUS by default. It guarantees higher performance than Blocking I/O.
This section explains how to improve the security system level despite a performance hit.
The following are the ways to improve overall security level of JEUS:
Set the global system password.
Use secured connection in JEUS security domain
Configure the network security service to use secured connection, which is usually protected with SSL/TLS. Refer to Reference to learn how to set a secured connection when the default network service is used. This prevents anyone from network eavesdropping and picking up sensitive information.
Protect Subject and Policy from Unauthorized Access
It is essential to protect user information of a Subject and the policy repository location from unauthorized access. The method for this depends on the repository type. The following are some example cases.
If a database is in use, the table that stores user information of a Subject and the table where policy is stored must be protected through authentication and authorization configured on the database side. You must also protect connections between the JEUS security repository and the database by using SSL, etc. Refer to the database documents to learn how to configure this setting.
If security information is stored in an XML file such as accounts.xml and policies.xml, you must create proper file access permissions to ensure that only the JEUS security system and administrators have access to this file. Use encryption, if encryption is supported regardless of the repository. Refer to the repository document to learn how to apply security to files. Refer to the operating system manual to learn how to set read/write access to the files.
Use Security Auditing
Create a security event log for events that occur in the system and periodically audit the log. JEUS security auditing mechanism is usually implemented by using the service SPI class, jeus.security.spi.EventHandling. Note that a log file must be protected from unauthorized access. Refer to Reference for information about various security auditing mechanisms.
Use JavaSE SecurityManager
Set JavaSE SecurityManager as explained in "2.7.1. Configuring Java SE SecurityManager" to improve the robustness of the JEUS system and to protect JEUS from potentially malicious EJB and Servlet code injections.
Use Third-Party Security Mechanism
In an environment that deals with sensitive information (such as in a banking application), it is strongly recommended to use additional security mechanisms such as firewalls or VPNs (Virtual Private Networks) along with the JEUS security system.
Configure Security for Operating System
Regardless of the operating system in which JEUS operates, do as follows to protect the operating system.
Restrict physical access to the servers where JEUS is installed. For example, keep the servers in a locked place.
Set process and file privileges so that only trusted administrator can access the JEUS files and processes. Refer to the operating system manual.
Update the operating system with the latest security related patches.
Periodically execute an antivirus software.
Keep all written security related documents safe. For example, keep written passwords in a locked cabinet.