Security 1-2-3 | |
Author: Jordan Reed (jreed at sapient.com) Version: $Revision: 1.4 $($Author: araman $ / $Date: 2003/05/05 07:47:01 $) Created: February 2003
|
| |
This document is meant to give an engineer unfamiliar with the design
and implementation of security in a J2EE environment an overview
of how to use the J2EE security model and Carbon security services
and features.
|
| |
|
J2EE defines a robust groundwork for security within applications.
Teams designing and building a J2EE application should take the
time to understand what is provided by the J2EE model and how to
use it as the basis for their application-specific security service.
Choosing to implement a security service separate from the one
J2EE provides will decrease the security of your application and
forego the time-saving security options provided by J2EE itself,
the application server, and 3rd-party utilities.
The Sun J2EE Tutorial provides an overview of J2EE security at:
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Security.html
At the heart of the J2EE security model are the concepts of
Principals, Roles and Resources.
Principal - (
java.security.Principal
) Represents an entity in the system. Principal is most often used
either to represent an individual user or a group of users (
java.security.acl.Group
). In a J2EE system Principals are usually identified by their login
name to the system.
Role - A logical user concept
that will be granted permissions on various resources in the system.
An "administrator" role might be granted access to the administration
section of the site. Roles do not have to be restricted to
actual users of the system. For example, an "order-processor role"
might be given to engines running on the back-end of the system
that can call order processing EJBs.
Resource - Logical items
in the system that users will attempt to access and perform actions
on. In a J2EE system the most common resources are JSPs, Servlets,
EJBs, etc.
These concepts tie together in J2EE security in the following
paradigm:
-
A user is a Principal and is in a Group (a specialized Principal
that is a collection of other Principals)
- A Principal (usually a Group) is assigned to a Role
- A Role is given access to a resource
Here's an example:
-
A User, identified by "jreed" is in a Group called "Production
Support Team" that is responsible for maintaining a web site.
-
The Group, "Production Support Team" is assigned to the role
"Web site Administrator"
-
The Role, "Web site Administrator" is given access to all
administration web pages on a site.
It is important to remember many of these mappings
are many to many. "jreed" could be in multiple groups in the
system. He may also be in a "Customer" group or "Supplier"
group. Groups be assigned to multiple roles. Roles can
contain multiple Principals (the use of Principals is
important. Roles can contain both Users and Groups which are
both Principals).
|
|
Security in the J2EE model is separated between declarative
security and programmatic security.
Declarative security is the process of declaring
security conditions inside of deployment descriptors and allowing the
application server to manage the enforcement of those requirements.
Programmatic security is the process of a project
team writing Java code that retrieves the currently authenticated user
and performs project-specific authorizations for that user beyond the
scope of J2EE-provided security.
Project teams are always required to write
programmatic security on top of declarative security to protect
resources the declarative security model misses. Since the declarative
security model protects logical J2EE components, projects need to
write programmatic security to protect business components and data
objects.
Declarative Security will allow a project team to:
-
Restrict URL's to only be accessible to Principals with given
roles (e.g. "/admin/*" is restricted to the "administrator" role)
-
Restrict URL's to only be accessible by various protocols (e.g.
"/customer/*" is restricted to only be accessible via HTTPS)
-
Restrict Servlets to only be accessible by Principals with given
roles (e.g. "SiteShutdownServlet" is restricted to the "god" role)
-
Restrict individual methods on EJBs to only be accessible by
various Principals with given roles (e.g. "PurchasingEJB" is
restricted to the "customer" role)
-
Assign a login page to automatically display to the user when
she requests a restricted page, but is not yet logged into the
system.
Declarative Security will NOT
allow a project team to:
-
Restrict URL's based on URL parameters (e.g.
"/showPage.jsp?type=1" is restricted to the "customer" role, but
"/showPage.jsp?type=2" is restricted to the "admin" role).
|
|
The first step in the security of an application
is logging in to the system to identify the Principal accessing
it. This example will go over the login process from a web
application (thick client apps logging in directly to business layer are
handled differently and can be read about in the
J2EE Security Tutorial
).
Login is defined inside the web.xml deployment
descriptor used in the application. It involves restricting a
portion of the site to a specific role, and then defining what login
technique the application server is supposed to use when a user
attempts to access that restricted portion of the site. When
unauthenticated users attempts to access a restricted page, they are
automatically presented with the login page (this is called contextual
or passive login). An authenticated user with the proper rights
will see the page without issue, and a user without those rights will
be presented with a security error which can be mapped to a
project-specific page.
web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> <!-- ... --> <!-- Define the security constraint. This will limit the /admin/* portion of the application to only be accessible to users within the "admin" role. When an unauthenticated user attempts to access this section of the site, they will be automatically presented with the login page. --> <security-constraint> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/admin/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <!-- Define the roles that are allowed to access this URL with the given methods --> <auth-constraint> <role-name>admin</role-name> </auth-constraint> <!-- Transport guarantee could be used to guarantee an HTTPS protocol --> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint>
<!-- Define the method for authenticating a user when requesting a restricted page. Methods include BASIC (the simple pop-up dialog), FORM and CERTIFICATE. --> <login-config> <auth-method>FORM</auth-method> <!-- Application servers may have multiple realms a user can authenticate against. The most common case would be if there are multiple applications running, each authenticating against a different user store, this could be handled through multiple realms on the application server. --> <realm-name>Default Realm</realm-name> <form-login-config> <!-- This is the location of the page that will be presented to the user by the application server upon the first request of a restricted page. --> <form-login-page>/login/login.jsp</form-login-page> <!-- This is the location of the page that will be presented to the user by the application server if the name/password entered on the login page do not validate against the user store. Notice that the URL given here is a struts action which could do various security processing (such as locking out a user after three failed logins). It can also server side forward back to the login page, which is popular behavior for most sites. --> <form-error-page>/security/securityError.do</form-error-page> </form-login-config> </login-config>
<!-- Finally a list of all security roles in the application must be given. --> <security-role> <description>Capable of administrating the site</description> <role-name>admin</role-name> </security-role> </web-app>
Now when unauthenticated users request any page
under the /admin/ path in the application, they will be presented with
the /login/login.jsp page. This page is used to submit a login
request back to the application server that will authenticate the user.
/login/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Example - Login Page</title> </head> <body> <h1>Login Please</h1> <%-- The form must post to the action of "j_security_check". This is a special URL recognized by the application server as a request into the security authentication service that it provides. --%> <form method="post" action="j_security_check" > <table border="0" cellspacing="5"> <tr> <th align="right">Username: </th> <%-- The username field must be "j_username" --%> <td align="left"><input type="text" name="j_username"></td> </tr> <tr> <th align="right">Password:</th> <%-- The password field must be "j_password" --%> <td align="left"><input type="password" name="j_password"></td> </tr> <tr> <%-- The form can be submit in anyway, so long as it posts to the proper place. --%> <td align="right"><input type="submit" value="Login"></td> <td align="left"></td> </tr> </table> </form> </body> </html>
Passive vs. Active Login Screens
The J2EE login concept is built around passive
logins. Passive logins means that the user requests a protected
page, is presented with login, and is then shown the original page they
request. No business logic is needed to determine where to take
the user after login, because it was the users request to a page the
initiated the login sequence.
Active login occurs when the site presents a way
for the user to specifically request the login page. J2EE does not
directly support the concept of active login, but the process is not
difficult to make it support such a procedure. Below describes the
procedure in Struts terminology, but the model works in any
presentation framework (or none through the user a Servlet or JSP
instead of the Struts action).
-
Create a LoginAction and restrict its URL to a role that all
users in the system have access to
-
Link to this LoginAction as the login page in the application
-
When the user clicks on this action, they will not be presented
with this protected action, but the with actual login page specified in
web.xml
-
Upon successful authentication, the application server will
forward the user to the LoginAction
-
The LoginAction will have access to the Principal object and can
redirect the user to the appropriate after-login page.
|
|
Restricting of EJB resources is similar to
restricting Web resources and done within the EJB deployment descriptors
on a method-based system.
ejb-jar.xml
<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>
<ejb-jar> <enterprise-beans> <!-- ... List all the beans here ... --> </enterprise-beans> <assembly-descriptor> <security-role> <!-- Just like in web.xml, each security role must be listed. These roles will be mapped back to principals in the application in the application server specific deployment descriptors. --> <description>Capable of administrating the site</description> <role-name>admin</role-name> </security-role> <method-permission> <!-- List the roles that this permission applies to --> <role-name>admin</role-name> <!-- List the methods that the permission applies to. In this case access has been given to all methods on the administrator ejb --> <method> <ejb-name>org.examples.securitydemo.AdminEjb</ejb-name> <method-name>*</method-name> </method> </method-permission> </assembly-descriptor> </ejb-jar>
|
|
Programmatic Security is entirely defined within
various methods of the J2EE API.
These methods, while somewhat useful, do not
provide robust abilities to check a user's ability to access specific
data objects or functions within the system. For example, in a
banking application if a user's account number is 12345, there is no
way in this model to test that. Instead, the business logic of
the application must determine the accounts a user has access to given
her principal name.
|
|
This example gave a brief overview of how to use
the provided APIs in the J2EE security model. There are many
pieces of functionality that are still missing to be able to build a
robust, secure J2EE application. Carbon provides services that
solve many of the generic problems (discussed in the next section) but
many are application-specific.
|
|
| |
Carbon provides services built to compliment the
standard J2EE security model and fill in some of the missing pieces in
application security. Carbon services are designed around
providing the plumbing for the application, but the
application-specific business code and logic is still left in the
hands of the project team to design and implement.
|
The Carbon User Manager service provides a generic
API for accessing and managing a store of users. Most J2EE
applications will store their list of users and the users'
association to groups inside either a relational database or an LDAP
server.
The User Manager provides a programmatic security
API similar to the J2EE programmatic API. In fact, when the User
Manager is fully integrated with the application server (explained
later), calls to the standard J2EE security API will pass directly
into the User Manager APIs. This means that the application can
simply pass around a reference to the current principal, and using
Carbon's User Manager service be able to execute similar programmatic
security checks without the need to have a reference to an
HttpServletRequest or EJBContext object.
For additional information on the User Manager
service, please see specific documentation:
|
|
Carbon provides adapter classes that allow
application servers to integrate with the Carbon User Manager
service. This means that authentication checks and checks of a
user's membership in roles will go through the same User Manager
system that programmatic application security goes through. It
unites all parts of security and user management in the application to
a single API.
For additional information on the Application
Server Adapters, please see specific documentation:
Project Team's Responsibility
|
|
Applications generally contain a large collection
of data objects that are restricted. For example, a banking
application would have all of the users' accounts stored inside its
database. These are items which must be restricted, but are not
good candidates for the standard J2EE APIs or Carbon User Manager
APIs.
Restricting Data Objects should be done at the
manager level programmatically. When a call is made into the
business layer, typically through a stateless session bean, the
current user's Principal object is available through the
EJBContext. This should then be passed to the account manager
object responsible for knowing which are the correct accounts to
return for the given Principal:
findAccountsByPrincipal(user : Principal)
: Collection - Returns the collection of all accounts the
Principal is associated with.
|
|
It is often desirable to have HTML pages
customized based on the current user's role and privilege. Some
level of this can be done using the two Struts logic tags of
<logic:present> and
<logic:notPresent>. These tags can be used to
optionally display sections of html based on the presence of a Role in
the authenticate user's memberships.
Beyond this simple logic, custom tags and other
logic must be used to provide html customization to the end-user.
Additional Questions
What is the Role of JAAS?
Java introduced the Java Authentication and
Authorization Service (JAAS) to create a standard way to handle a user's
security in an application. The JAAS API can be downloaded as an
extension to Java 2, and is part of the standard packages in J2SE 1.4.
JAAS has a high level of integration with J2SE,
but has not yet acheived that level with J2EE. Currently, there
is no standard to tie a J2EE Container into a JAAS security
system. Application servers are moving towards using JAAS'
authentication APIs (the LoginModule) but are still not using JAAS'
authorization APIs.
Weblogic 7 has begun using JAAS to support all
of its security services. For Carbon's User Manager service to
integrate with Weblogic 7 requires, as one step, the creation of a
JAAS Login Module that allows login against the Carbon User Manager
service. The Weblogic 7 Adapter calls into this JAAS Login Module,
which in turn calls the Carbon User Manager Service.
Appendices
Definitions
Term |
Definition |
Principal |
A description of a unique entity in the system.
This can either be a user or a group. |
Credential |
A piece of information used by a Principal to
prove his identity. Common credentials include passwords and
certificates. |
Declarative Security |
Security restrictions defined against components
of an application by declaring them in configuration files. |
Programatic Security |
Security restrictions defined against
process-flow inside of a component through code that checks the
user and alters process flow accordingly. |
Passive Login
|
A login dialog is presented to
the user after the user has requested a restricted resource. Upon
successful authentication, the user is taken to the requested resource.
|
Active Login
|
A user specifically requests to
login to an application. Upon successful authentication, the
application must determine the proper destination to take the user to.
|
Trust Relationship |
A relationship where one object trusts the
security of another. Used to allow the user to sign-on with one
object, and then not need to pass a credential to another object. |
|
|
|