Upload
agnes-webster
View
216
Download
0
Tags:
Embed Size (px)
Citation preview
11
SecuritySecurity
Most Java EE applications need to provide identity to users who access them and security for that access. Applications may want to prevent hostile users from logging into their systems.
They might also want to restrict the actions of the individuals using their systems.
The Java EE and EJB specifications provide a core set of security services that application developers can integrate declaratively and programmatically. These include:
Authentication Authorization Confidentiality and integrity protection
22
SecuritySecurity
Although a small programmatic API is available for interacting with Java EE security services, users rarely have to write any code to secure their applications because setting up security is usually a static declarative process.
Only session beans can be secured in EJB land. Java Persistence does not yet have a mechanism to secure access, but it is possible - depending on the RDBMS system you are using - to assign privileges at the database level.
This lesson focuses on how to set up authentication and authorization for your session beans.
33
Authentication and IdentityAuthentication and Identity In a secure EJB application, authentication involves verifying
that a user is who she says she is. When a remote client logs on to the EJB system, it is
associated with a security identity for the duration of that session.
Once a remote client application has been associated with a security identity, it is ready to use beans to accomplish some task.
When a client invokes a method on a bean, the EJB server implicitly passes the client's identity with the method invocation.
When the EJB object receives the method invocation, it checks the identity to ensure that the client is valid and is allowed to invoke that method.
44
Authentication and IdentityAuthentication and Identity
Unfortunately the EJB specification does not specify how authentication happens. It also does not define how the application server stores and retrieves authentication information.
The vendor must decide how to package and provide these services on the client and server.
When invoking on a remote EJB, many application servers accomplish authentication by using the JNDI API.
For example, a client using JNDI can provide authenticating information using the JNDI API to access a server or resource in the server.
This information is frequently passed when the client attempts to initiate a JNDI connection on the EJB server.
55
Authentication and IdentityAuthentication and Identity
The following code shows how a client's password and username can be added to the connection properties for obtaining a JNDI connection to the EJB server:
properties.put(Context.SECURITY_PRINCIPAL, userName);
properties.put(Context.SECURITY_CREDENTIALS, userPassword);
InitialContext ctx = new InitialContext(properties);
Object ref = jndiContext.lookup("TravelAgent");
TravelAgentRemote remote = (TravelAgentRemote)
PortableRemoteObject.narrow(ref, TravelAgentRemote.class);
66
Authentication and IdentityAuthentication and Identity
In this example, the user is authenticated with the connection to the JNDI InitialContext.
The username and password are associated with the client thread and propagated to the server internally when calls are made to remote EJBs.
Many application servers provide a mechanism other than JNDI with which to authenticate.
For instance, the JBoss application server uses the JAAS specification, which provides a rich API for performing authentication.
77
AuthorizationAuthorization
Once a user is authenticated by a vendor-specific mechanism, he must be checked to see if he is allowed to invoke a particular EJB method.
Authorization is performed in Java EE and EJB by associating one or more roles with a given user and then assigning method permissions based on that role.
While an example of a user might be "Scott" or "Gavin," roles are used to identify a group of users—for instance, "administrator," "manager," or "employee."
In EJB, you assign access control on a per-method basis. You do not assign these permissions on a per-user basis, but
rather, on a per-role basis.
88
AuthorizationAuthorization
Unlike authentication, authorization is something that the EJB specification clearly defines.
You begin by declaring the roles that are accessed programmatically in your code base. Then you assign permissions for each method in your class.
This is done declaratively through Java annotations or through the ejb-jar.xml deployment descriptor.
To illustrate, let's secure access to the ProcessPayment EJB defined in Lesson 11.
99
Assigning Method PermissionsAssigning Method Permissions
To assign method permissions to an EJB's methods, use the @javax.annotation.security.RolesAllowed annotation:
package javax.annotation.security;
@Target({TYPE, METHOD}) @Retention(RUNTIME)
public @interface RolesAllowed {
String[] value( );
}
The @javax.annotation.security.PermitAll annotation specifies that any authenticated user is permitted to invoke the method.
1010
Assigning Method PermissionsAssigning Method Permissions As with @RolesAllowed, you can use this annotation on the
bean class to define the default for the entire bean class, or you can use it on a per-method basis.
@PermitAll is also the default value if no default or explicit security metadata is provided for a method.
This means that if you do not use any security annotations on your bean class, every user is granted unlimited access.
Let's apply these annotations to ProcessPaymentBean using the permissions we discussed earlier:
package com.titan.processpayment;
import com.titan.domain.*;
import javax.ejb.*;
import javax.annotation.Resource;
import javax.annotation.security.*;
1111
Assigning Method PermissionsAssigning Method Permissions@Stateless
@RolesAllowed("AUTHORIZED_MERCHANT")
public class ProcessPaymentBean implements ProcessPaymentRemote,
ProcessPaymentLocal
{
...
@PermitAll
public boolean byCash(Customer customer, double amount)
throws PaymentException
{
...
}
@RolesAllowed("CHECK_FRAUD_ENABLED")
public boolean byCheck(Customer customer, CheckDO check, double amount)
throws PaymentException
{
...
}
1212
Assigning Method PermissionsAssigning Method Permissions
public boolean byCredit(Customer customer, CreditCardDO card,
double amount) throws PaymentException
{
...
}
private boolean process(int customerID, double amount, String type, String checkBarCode, int checkNumber, String creditNumber,
java.sql.Date creditExpDate) throws PaymentException
{
...
}
}
Let's apply this security metadata with XML instead:
1313
Assigning Method PermissionsAssigning Method Permissions<ejb-jar version="3.0">
<assembly-descriptor>
<security-role>
<description>This role represents an authorized merchant</description>
<role-name>AUTHORIZED_MERCHANT</role-name>
</security-role>
<security-role>
<description>
This role represents a merchant that has check fraud enabled
</descripton>
<role-name>CHECK_FRAUD_ENABLED</role-name>
</security-role>
<method-permission>
<role-name>AUTHORIZED_MERCHANT</role-name>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCredit</method-name>
</method>
</method-permission>
1414
Assigning Method PermissionsAssigning Method Permissions <method-permission>
<role-name>CHECK_FRAUD_ENABLED</role-name>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
</method>
</method-permission>
<method-permission>
<unchecked/>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>
1515
Wildcard declarationsWildcard declarations The method name in a <method> element can be a simple
wildcard (*). A wildcard applies to all methods of the bean's home and
remote interfaces. For example:
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>*</method-name>
</method>
Although it's tempting to combine the wildcard with other characters, don't do this.
The value get*, for example, is illegal. The asterisk character can only be used by itself.
1616
Named method declarationsNamed method declarations Named declarations apply to all methods defined in the
bean's remote and local interfaces that have the specified name.
For example:
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
</method>
This declaration applies to all methods with the given name in any business interface.
It does not distinguish between overloaded methods.
1717
Specific method declarationsSpecific method declarations Specific method declarations use the <method-params>
element to pinpoint a method by listing its parameters, which allows you to differentiate between overloaded methods.
The <method-params> element contains zero or more <method-param> elements that correspond, in order, to each parameter type (including multidimensional arrays) declared in the method.
For example, let's look again at our ProcessPayment EJB, to which we have added some overloaded byCheck( ) methods.
Here are three <method> elements, each of which unambiguously specifies one of the methods by listing its parameters:
1818
Specific method declarationsSpecific method declarations<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
<method-params>
<method-param>com.titan.domain.Customer</method-param>
<method-param>com.titan.processpayment.CheckDO</method-param>
<method-param>double</method-param>
</method-params>
</method>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
<method-params></method-params>
</method>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>byCheck</method-name>
<method-params>double[]</method-params>
</method>
1919
Remote/home/local differentiationRemote/home/local differentiation
There's one problem left. The same method name can be used in the remote interface and the local interface.
To resolve this ambiguity, add the <method-intf> element to a method declaration as a modifier.
Five values are allowed for a <method-intf> element: Remote, Home, LocalHome, Local, and ServiceEndpoint.
All of these styles of method declarations can be used in any combination and within any element that uses the <method> element.
The <method-permission> elements are combined to form a union of role-to-method permissions.
2020
Remote/home/local differentiationRemote/home/local differentiation
For example, in the following code, the first <method-permission> element declares that only administrators have access to the remote methods of the ProcessPayment EJB:
<method-permission>
<role-name>administrator</role-name>
<method>
<ejb-name>ProcessPaymentBean</ejb-name>
<method-name>*</method-name>
<method-intf>Remote</method_intf>
</method>
</method-permission>
2121
Excluded MethodsExcluded Methods EJB security metadata has a rarely used feature that allows
you to forbid access to one or more methods. Excluded methods are identified with the @javax.annotation.security.DenyAll annotation or with the <exclude-list> element.
Denying access to a particular method with an annotation isn't a very useful proposition.
Why would you write a bean class method, add it to the business interface, and then annotate it so that it couldn't be used?
Using this feature in XML, though, does have some uses. What if the ProcessPayment EJB was part of a third-party
vendor library?
2222
Excluded MethodsExcluded Methods The <exclude-list> element could be used to turn off various
features of the API per deployment. Let's look at an example:
<ejb-jar> <assembly-descriptor> <exclude-list> <method> <ejb-name>ProcessPaymentBean</ejb-name> <method-name>byCash</method-name> </method> </exclude-list> </assembly-descriptor></ejb-jar>
This example disallows all access to the ProcessPaymentBean.byCash( ) method. The <exclude-list> element can take one or more method signatures.
2323
The RunAs Security IdentityThe RunAs Security Identity In addition to specifying the roles that have access to an
enterprise bean's methods, the deployer can also specify the runAs role for the entire enterprise bean.
While the @RolesAllowed annotation and <method-permission> elements specify which roles have access to the bean's methods, runAs specifies the role under which the method will run.
The @javax.annotation.security.RunAs annotation is used to specify this special role.
Although they are not allowed to use method permissions, message-driven beans can use the @RunsAs feature:
2424
The RunAs Security IdentityThe RunAs Security Identitypackage javax.annotation.security;
public @interface RunAs {
String value( );
}
@RunAs could be used to simplify our role mapping for the ProcessPayment EJB.
Let's look at how TravelAgentBean would use the @RunAs annotation:
package com.titan.travelagent;
import javax.ejb.*;
import javax.annotation.security.*;
2525
The RunAs Security IdentityThe RunAs Security Identity@Stateful@RunAs("AUTHORIZED_MERCHANT")public class TravelAgentBean implements TravelAgentRemote{...}
This can also be expressed in ejb-jar.xml:<ejb-jar version="3.0"> <enterprise-beans> <session> <ejb-name>TravelAgentBean</ejb-name> <security-identity> <run-as> <role-name>AUTHORIZED_MERCHANT</role-name> </run-as> </security-identity> </session> </enterprise-beans></ejb-jar>
2626
The RunAs Security IdentityThe RunAs Security Identity To specify that an enterprise bean will execute under the
caller's identity rather than a propagated run-as identity, the <security-identity> role contains a single empty element, <use-caller-identity/>.
The following declarations specify that the EmployeeService EJB should always execute under the caller's identity:<enterprise-beans> <entity> <ejb-name>EmployeeService</ejb-name> <security-identity>
<user-caller-identity/> </security-identity> </entity></enterprise-beans>
The use of <security-identity> applies to session beans. Message-driven beans have only a runAs identity; they never execute under the caller identity because there is no "caller."
2727
Programmatic SecurityProgrammatic Security Most of the security features in this chapter have focused
solely on declarative security metadata, or metadata that is statically defined before an application even runs.
EJB also has a small programmatic API for gathering information about a secured session.
Specifically, the javax.ejb.EJBContext interface has a method for determining the concrete user that is invoking on the EJB.
It also has a method that allows you to check whether the current user belongs to a certain role:package javax.ejb;
public interface EJBContext { javax.security.Principal getCallerPrincipal( ); boolean isCallerInRole (String roleName);}
2828
Programmatic SecurityProgrammatic Security The getCallerPrincipal( ) method returns a standard Java SE
javax.security.Principal security interface. A Principal object represents the individual user that is
currently invoking on the EJB. We can expand our ProcessPayment EJB to store the travel
agent that logged the payment for a customer as well. This addition allows us to audit the payment if there are any
problems with the transaction.
package com.titan.processpayment;
import javax.security.Principal;
import javax.ejb.*;
import javax.annotation.*;
2929
Programmatic SecurityProgrammatic Security@Statelesspublic class ProcessPaymentBean implements ProcessPaymentLocal {
@Resource SessionContext ctx;...
private boolean process(int customerID, double amount, String type,String checkBarCode, int checkNumber, String
creditNumber, java.sql.Date creditExpDate) throws PaymentException
{Principal caller = ctx.getCallerPrincipal( ); String travelAgent = caller.getName( ); // add travelAgent to payment record ... }}
The EJBContext.isCallerInRole( ) method allows you to determine whether the current calling user belongs to a certain role.
For instance, we might want to forbid large payment transactions above a certain dollar amount for junior travel agents.
3030
Programmatic SecurityProgrammatic Security To make the EJB container's job easier, you must declare all
programmatic role access using the @javax.annotation.security.DeclareRoles annotation:
package javax.annotation.security;
@Target(TYPE) @Retention(RUNTIME)public @interface DeclareRoles { String[] value( );}
Let's use isCallerInRole( ) with the ProcessBean EJB: package com.titan.processpayment;
import javax.security.Principal;import javax.ejb.*;import javax.annotation.*;import javax.annotation.security.*;
3131
Programmatic SecurityProgrammatic Security@Stateless
@DeclareRoles
("JUNIOR_TRAVEL_AGENT")
public class ProcessPaymentBean implements ProcessPaymentLocal {
@Resource SessionContext ctx;
@Resource double maximumJuniorTrade = 10000.0;
...
private boolean process(int customerID, double amount, String type,
String checkBarCode, int checkNumber,
String creditNumber, java.sql.Date creditExpDate) throws PaymentException
{
if (amount > maximumJuniorTrade &&
ctx.isCallerInRole("JUNIOR_TRAVEL_AGENT"))
throw new PaymentException("Travel agent is not authorized to make such
a large purchase. Manager approval is required.");
...
}
}
3232
Programmatic SecurityProgrammatic Security If you do not use the @DeclareRoles annotation, then you
must use the <security-role-ref> element within the session bean's declaration:
<ejb-jar version="3.0"> <enterprise-beans> <session> <ejb-name>ProcessPaymentBean</ejb-name> <security-role-ref> <role-name>JUNIOR_TRAVEL_AGENT</role-name> </security-role-ref> </session> </enterprise-beans></ejb-jar>
The <security-role-ref> element is defined within a <session> or <message-driven> element.
It has one subelement, <role-name>, which names the role that is being referenced.