Java 2 Bible Enterprise Edition phần 7 pot

71 293 0
Java 2 Bible Enterprise Edition phần 7 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Tip You can't control bean−security issues through the policy files used by J2SE. These policy files only control functions of a particular API, such as file I/O or threading, and they won't work because they must be available across all clients and servers. In addition, the environment (for example Java code embedded in an Oracle database as a trigger) may not support them. The assignment of a set of access restrictions is known as a role in EJB terminology. A role acts as a grouping mechanism. You don't use it to predefine access capabilities or users who wish to attempt certain tasks; rather it acts as a means of collecting like−minded methods together after you have written them. A particular user of the system is known as a security principal. When your servlet code needs to access an EJB, it has an identity, which is the principal's name. The name represents the user attempting to perform the task. The role information forms the other half of the request. At some point during the deployment, the person responsible for deploying beans will pull up the administration tool and provide a mapping of principal names to roles. Consider it a many−to−many mapping where a single principal may be allocated a number of roles, but a role may be assigned to many principal names. How the roles and principles are arranged depends on your application requirements. Determining who is calling As we alluded to earlier, some programmatic ways of accessing security information exist. The two methods provided enable you to determine the identity of the principal calling you and to check the role of the caller. Caution The J2EE specification explicitly warns against using these methods as means of controlling secure access to your code. They should be treated as purely informational, because if your method has been called, the assumption is that the EJB container has already performed all the necessary checks. Finding out the identity of the principal calling your code is the job of the getSecurityPrincipal() method of the EJBContext. The return value of the method is java.security.Principal, which represents the underlying authorization mechanism (for example, Keberos or NIS). You can then obtain the name of the user as a String with the getName() method. So why would you want to know the name of the user calling you? Let's say you are running an application that is a data−entry terminal, such as a terminal in the dispatch warehouse. The user logs on and then starts processing orders. The terminal brings up the next order pending. Off goes the storeman to acquire the items, parcel them up, and call the courier. Before the storeman can move on to the next item, the order is marked as being processed, and the next order comes up. As far as he or she is concerned, "Order completed" is the only button on the screen. Down the back, on the EJB server, the database requires a record of who actually processed the order. Instead of having to ask the storeman to enter his or her name each time, you can use the getSecurityPrincipal() method to access the login name and assign it to your database record. For example, you might find the following business method in the Order bean (ignoring exception handling): public void orderCompleted() { Principal operator = ejbContext.getSecurityPrincipal(); String op_name = operator.getName(); InitialContext ctx = new InitialContext(); Object home_ref = ctx.lookup("ejb/EmployeeLocalHome"); EmployeeLocalHome home = (EmployeeLocalHome)home_ref; Employee emp = home.findByPrimaryKey(op_name); Chapter 17: Using Advanced EJB Techniques 418 // now assign the reference to the employee bean here as we // are assuming a CMR field setEmployee(emp); } Notice that the code uses the operator's login name as the primary key for the employee bean. The assumption here is that the login name is always unique and therefore valid for a unique identifier for a bean. To access the real details of the employee, you can then look up the bean or one of the other server−administration tools. Using the operator details, the code then looks up the representative bean and assigns it to this order−bean instance so that the relationship is established and then maintained by the EJB container using container−managed relationship capabilities. On the odd occasion when the deployment−descriptor handling of role−based information is not sufficient, you can enforce tighter rules using the isCallerInRole() method from EJBContext. For example, the bean might impose a maximum number of simultaneous requests for a particular role, backed by information in a database. The isCallerInRole() method takes a single argument of a String, representing the name of the desired role to check against. In return you are given a Boolean value indicating whether the caller is using the nominated role. For example, if you want to check that the user about to process an order as complete is actually the storeman, then the following code becomes useful: public void orderCompleted() { if(!ejbContext.isCallerInRole("stores")) throw new SecurityException("The caller is not " + "authorized to complete an order"); } It is important to understand that the role information that is checked is what the caller is acting as, not what your bean code is currently acting as. These may well be two separate things — you could allow four roles to access your code, but be described by a completely different role. Profiling the user for access capabilities Now we get into the specifics of applying role and security information to individual bean instances. All the information in this section is described in the deployment descriptor. As you will see, it is quite verbose as a process and will usually be easier to set up in the tool provided by your EJB server vendor. However, read on, as you will need to understand the terminology used in all those wizard dialog boxes. Security information is defined in so many places in a deployment descriptor that deciding where to start can be a daunting exercise. In order to make the following sections more understandable, we're going to introduce the ideas in the order in which you might consider security issues from the deployment perspective. Unfortunately, that means that we'll be jumping all over the deployment descriptor to insert the new information provided in each step. We hope not to confuse you too much! The Role Chain of Execution In all but the simplest systems, your particular bean may be at the end of a long series of method calls. In order to reach your code, a request may have passed through a servlet or two, a JMS message queue, and then a few layers of beans. By the time you receive a request, how do you know whether the original caller was Chapter 17: Using Advanced EJB Techniques 419 actually allowed to access the information? Roles have the interesting ability to form a chain. The original caller sets the role, and then all subsequent method calls maintain that role. So even if you are buried under 10 levels of method calls and beans, you will still maintain the original caller's role. In this way, you can determine whether the original caller was a servlet, message queue, or any other type of bean. For example, if you have a servlet and you set its role to be customer_servlet, then your order bean's ejbCreate() method will return isCallerInRole("customer_servlet") as true. However, if the order was placed as a telephone operator using a kiosk application, the method will return false. Even if you are called by other beans between the servlet and your code, the role is not changed by any of the intermediaries. The only time you have a chance of influencing the role used is when your bean is directly accessed by application code. For example, a kiosk application accesses your bean directly. The application does not have a role associated with it, so the EJB container will take the role assigned to your bean as the originating role. Declaring role information The first task in building security information is deciding on the various roles that will be assumed by the beans and the bean clients. Ideally you will decide in a very early stage of the project's analysis and design, not right at the end when you have finished testing. You start the process by declaring all the roles to be used by the beans. Role declarations take place in the security−role element, which is in turn held in the hitherto−unseen assembly−descriptor element. You declare assembly−descriptor as the last child of the ejb−jar element — after the enterprise−beans element in which you have so far been placing all your information: <ejb−jar> <enterprise−beans> </enterprise−beans> <assembly−descriptor> </assembly−descriptor> </ejb−jar> The assembly−descriptor element starts by listing all the security−role elements. Each declaration of the security−role covers exactly one role in the bean. So, if you need 20 roles, 20 declarations of security−role will exist. Tip The security roles defined by the security−role elements are scoped to the ejb−jar file level, and apply to all the enterprise beans in the ejb−jar file. If you have two JAR files that nominate the same roles, they are treated as independent entities as far as the container is concerned. Inside the security−role element is only one required tag — the name of the role being declared: <assembly−descriptor> <security−role> <role−name>customer_servlet</role−name> </security−role> Chapter 17: Using Advanced EJB Techniques 420 </assembly−descriptor> Tip You can add a description string with each role's name, just as you can with most other items in the deployment descriptor. Declaring role names is just the first step. It is a declaration of who might want to use the system for the deployment tool to look at in order to start putting things in order. The next step is to assign a role to an individual bean to be used when no other information is known about the caller (that is, when no role information is present yet). Forcing a bean to run as a particular user To define information about the default security information for a bean, we now jump back to the deployment−descriptor declarations dealing with a specific bean instance (such as entity or session elements). When declaring user information for a bean, you have two options: provide a specific role name to run under every time, or always use whatever the caller provides. The choice here is binary — you can't provide both paths. In either case, you start by specifying the security−identity element. The new element is placed between the primkey−field and query elements if you are using an entity bean, and after the transaction−type element if you are using a session bean, as shown in the following example: <enterprise−beans> <entity> <primkey−field>OrderID</primkey−field> <security−identity> ??? </security−identity> <query> </query> </entity> <session> <transaction−type>Container</transaction−type> <security−identity> ??? </security−identity> </session> </enterprise−beans> security−identity has one of two children elements: run−as or use−caller−identity. As the names suggest, these control either a role name to be used by the bean, or a direction in which to use the caller's identity information. For the former case, you provide a role−name element as the child that declares the role that should be used. The name here must be one of the names that you have just declared in the security−role section: <security−identity> <run−as> <role−name>servlet_customer</role−name> </run−as> </security−identity> In order to use caller identity, you need only the empty element declaration. The rest is assumed from the runtime context. Chapter 17: Using Advanced EJB Techniques 421 <security−identity> <use−caller−identity/> </security−identity> Note Message−driven beans do not permit the use of use−caller−identity semantics. The deployment tool should flag an error if you declare them. Nominating security information Earlier you saw the use of the programmatic methods for checking the caller−role information. When you do this, you need to let the container know that you are going to be performing these checks, and exactly what you will be checking for. The effect of these checks is to imply the roles the bean code wants to check for as part of the deployment process. References to roles declared in code are contained in the security−role−ref element. This element is placed just before the security−identity element if you declared it earlier. In the role declaration, you place the name of one role that you have declared in code and an optional element that provides a link between the code declaration and one of your defined declarations in the security−role section. If more than one role is being checked in the bean's code, you just declare more security−role−ref elements. <entity> <primkey−field>OrderID</primkey−field> <security−role−ref> <role−name>stores</rolename> </security−role−ref> <security−identity> </security−identity> </entity> Tip Security−role nomination is not available to message−driven beans. You use link information when you wish to map the code's role declarations to your own preferred declarations. For example, a third−party bean declares a name that conflicts with one of your names, so you want to map it to something else or to a broader category: <security−role−ref> <role−name>stores</role−name> <role−link>warehouse_staff</role−link> </security−role−ref> Whatever you declare in the role−link element must have been previously declared in the security−role section. Getting picky with per−method security Once you have defined the larger perspective of security, you can become much more detailed in your requirements. Should you require it, you can become as detailed as individual method calls when singling out who can access what functionality. In each of the following pieces of functionality, the method is always described by a single structure: the method element. Different behaviors are then wrapped around this structure. The purpose of the method Chapter 17: Using Advanced EJB Techniques 422 element is to describe, in as much detail as necessary, the method signature. So you start with the bean affected: <method> <ejb−name>Product</ejb−name> </method> Next you need to declare which methods in the bean are affected. If you want to use all methods (the most typical case), you can use the special wildcard character, the asterisk (*), in the method−name element, as follows: <method> <ejb−name>Product</ejb−name> <method−name>*</method−name> </method> If you wish to have different permissions on each method, then you provide the name of the method in the method−name element. Because we are dealing with security information, this method name is always the name used in the home or remote/local interface, not the bean implementation: That is you should never see a method starting with ejb. For example, here we declare a finder method: <method> <ejb−name>Product</ejb−name> <method−name>findByCategory</method−name> </method> Mapping the Bean's View to the Real World From your perspective, the security net starts with the deployment descriptor. In the deployment descriptor, you describe the access requirements of the various pieces of code in terms of roles. In order for these definitions to take effect, they must mean something in the greater scope of the entire system. Roles don't have any meaning in the real world of the server's operating system. They are not required to, either. Roles are only a construct of the EJB server software. If the roles do have any relationship to user details on the underlying system, it is purely due to the server administrator's creating matching information. However, roles are much smaller in scope than a standard user login, so it would be unusual to see a direct mapping of EJB roles to system users. A role may only encompass a single method call out of thousands of beans. If your system consisted of hundreds or thousands of beans, the management issues would become a nightmare as you tried to keep the EJB parts synchronized with the servers. When you have only one of this method in the class, you can stop here. However, when you have overloaded methods, such as create(), you might want to single a specific method out for separate treatment by providing the method arguments. To specify a particular method based on the argument list, use the method−params element, which looks and works identically to the examples you saw earlier with EJB QL: <method> <ejb−name>Product</ejb−name> <method−name>findByCategory</method−name> <method−params> Chapter 17: Using Advanced EJB Techniques 423 <method−param>java.lang.String</method−param> <method−param>java.lang.String</method−param> </method−params> </method> Finally, you have one more way to provide restrictions — some classes have both remote and local interfaces declared for accessing a particular bean. The most common restriction here is to prevent the caller from accessing some methods that are available in both the remote and local interfaces. For example, a setter method may be available to all local users, but only to remote users of a specific role. Declaring whether a method belongs to a remote or local interface declaration is the job of the method−intf element. This element is inserted between the ejb−name and method−name elements. There are four valid values: Local, Remote, Home, and LocalHome. <method> <ejb−name>Product</ejb−name> <method−intf>Remote</method−intf> <method−name>findByCategory</method−name> Now that you know how to declare methods, it's time to use them in something. You can declare methods to be completely off−limits, or you can create a free−for−all. At the tightest end of the spectrum is the list of methods that cannot be called at all. These methods are listed in the exclude−list element. exclude−list is placed as the last element of the assembly−descriptor (before the exclude−list are a couple of elements that we'll be covering shortly). Inside exclude−list you list all the methods that should not be accessed: <assembly−descriptor> <exclude−list> <method> <ejb−name>Product</ejb−name> <method−name>setProductID</method−name> </method> <method> <ejb−name>UnusedBean</ejb−name> <method−name>*</method−name> </method> </exclude−list> </assembly−descriptor> Lightening up the heavy−handed restrictions is the job of the method−permission element, which can be found just ahead of the exclude−list. In this element, you place the list of methods and the roles that are allowed access. Inside the method−permission element, you find a collection of individual methods and the role(s) that are allowed to access them. Each permission declaration starts with the list of acceptable role names, followed by the method declarations of all the methods affected by these permissions: <assembly−descriptor> <method−permission> <role−name>stores</role−name> <role−name>call−center</role−name> <method> <ejb−name>Product</ejb−name> <method−name>getProductID</method−name> </method> Chapter 17: Using Advanced EJB Techniques 424 <method> <ejb−name>Order</ejb−name> <method−name>*</method−name> </method> </method−permission> <method−permission> <role−name>customer−servlet</role−name> <method> <ejb−name>Customer</ejb−name> <method−name>*</method−name> </method> </method−permission> <exclude−list> </exclude−list> </assembly−descriptor> Caution The EJB 2.0 specification does not mention the order of priorities when declarations conflict with each other. It is best to double−check everything you provide to make sure no conflicts exist. If you would like to go all the way and let any user call a method, you can substitute the empty element unchecked for the list of role−name in the method−permission. The result is that the server always lets requests to these methods go through: <method−permission> <unchecked/> <method> <ejb−name>Customer</ejb−name> <method−name>*</method−name> </method> </method−permission> Note If you don't declare a method in any of the permissions, then the bean container must assume that you want unchecked semantics. This completes the introduction to setting up security for EJB systems. As we mentioned before, security is more than just a few lines in a configuration file. In order for it to be effective, you need to involve everyone in the requirements and implementation. Dealing with Bean−Configuration Issues The last topic that we wish to cover with regard to beans is dealing with configuration issues. You've been inundated with one aspect of configuration already: specifying deployment information with the deployment descriptor. What we have not covered so far are all the small details, like environmental properties — items that you have traditionally used Java properties files and the java.util.Properties class to deal with. New Feature The J2SE 1.4 API introduces a standardized preferences API for the first time in the java.util.prefs package. J2EE 1.3 requires only J2SE 1.3, and so you may or may not have access to these capabilities. Under the EJB specification, providing property information to configure your beans is just as important as before. Although beans like stateless session beans are not supposed to be individually configured, plenty of areas still exist in which you can provide configuration information for business logic. These include areas in which you might need a constant defined, such as maximum and minimum values of a range check. Chapter 17: Using Advanced EJB Techniques 425 Summary of existing configuration techniques Before venturing into the approved method of providing configuration information to beans, let's quickly go back over the previously existing options and where they fail in the EJB worldview. Properties files Until the release of J2SE 1.4, no standard system for storing and loading user preferences existed. If a programmer wanted to create a portable application that was configurable, the only option, apart from creating a custom system, was to use text−properties files and use the Properties class to load and save the information. J2EE requires a heavy restriction on the use of file I/O. The use of the java.io.File class is not permitted within a bean implementation. This leaves you rather handicapped because you have no real way of reading, and more importantly no way of saving again, a properties file. There is a potential alternative method to locate and open the file using ClassLoader's getSystemResourceAsStream() method and storing the property file in the EJB−JAR file. This tactic is thwarted by the rule that bean implementations are not permitted to access the current class loader that the method call relies on. JNDI driver registration Throughout this book you have been seeing examples of how configuration and storage information is maintained. For example, JDBC drivers are registered by the system, and you access the current driver through JNDI. Each of these drivers is externally configured as part of the J2EE middleware−vendor's software. Because no standard configuration mechanism exists for low−level drivers, this lack of a standard system does not make the idea of portable environment variables particularly appealing. Each time you move to a new system, you need to build a new set of configuration files. If you are providing a bean library for others to use, the requirement that each customer build his or her own set of configuration files can be a major headache. Providing system−agnostic configuration properties Providing property information falls to the pairing of JNDI and the deployment descriptor. Once again, the deployment descriptor holds the values to be used during runtime, while your bean−implementation code accesses values through JNDI. Accessing properties in code In your bean−implementation code, accessing environment properties starts with creating a JNDI InitialContext instance. Accessing property values starts with you performing a lookup() operation on the name of the variable (just like you've done before with JDBC data sources and bean home interfaces). This obviously requires you to know what those property names are beforehand. The root name to use in the JNDI context is the same as that of all other J2EE items: java:comp/env. Below this, you provide the name of the property that you are after. For example: InitialContext i_ctx = new InitialContext(); Context env = i_ctx.createSubcontext("java:comp/env"); Object prop = env.lookup("MyProperty"); Chapter 17: Using Advanced EJB Techniques 426 Tip The J2EE specification makes no recommendations for naming conventions for properties, unlike for JDBC drivers or EJBs. Properties are only visible to their particular beans, so there is no need to come up with really long, convoluted names. Property values are restricted to using only the primitive types available in Java. Effectively, that means strings, integers, and floating−point values. When you access a value through the lookup() method you will then need to cast the return value to the appropriate class type, as follows: Integer max_int = (Integer)env.lookup("MaxRange"); Integer min_int = (Integer)env.lookup("MinRange"); int max_value = max_int.intValue(); int min_value = min_int.intValue(); That's all there is to using properties in your bean code. The next step is to declare the property values. Declaring property values Completing the task of using property values requires us to wander back to our old friend, the deployment descriptor. Properties are defined with the bean in which they are used, rather than as a global setting. Therefore you can have properties with the same name in different beans that use different datatypes and values! We really don't recommend it, though, and always suggest using clear, meaningful names for each property. Property values are contained in the env−entry element, which you can find just after the primkey−field of entity beans, and in the transaction−type element of session and message−driven beans. You must declare one env−entry per property. Within env−entry, you then provide a name, the Java class type that it must use, and the value, in that order. For example, to declare the MaxRange value we used in the preceding code snippet, you need to declare the following in the deployment descriptor: <env−entry> <env−entry−name>MaxRange</env−entry−name> <env−entry−type>java.lang.Integer</env−entry−type> <env−entry−value>20</env−entry−value> </env−entry> Tip The name declaration will have the java:comp/env prefix added to it by the container at deployment time. This is fairly straightforward as far as the deployment descriptor is concerned. The only mildly interesting part is that the entry type must be the fully qualified Java class type rather than just the class name. If you need more than one property defined, then just use more env−entry elements. For example: <entity> <ejb−name>MyBean</ejb−name> <env−entry> <env−entry−name>MaxRange</env−entry−name> <env−entry−type>java.lang.Integer</env−entry−type> <env−entry−value>20</env−entry−value> </env−entry> <env−entry> <env−entry−name>MinRange</env−entry−name> <env−entry−type>java.lang.Integer</env−entry−type> <env−entry−value>−5</env−entry−value> </env−entry> Chapter 17: Using Advanced EJB Techniques 427 [...]... particular IDL file: • Sample .java • SampleHelper .java • SampleHolder .java • _SampleImplBase .java • _SampleStub .java Sample .java is the file that contains the mapping of the IDL interface in Java As the name indicates, SampleStub .java is the client stub, and SampleImplBase .java the IDL skeleton created by the IDL compiler This leaves SampleHelper .java and SampleHolder .java The Helper classes allow... just like Java interfaces Any derived interface can have its own attributes and methods, in addition to inherited interface definitions Inheritance from multiple interfaces is also possible The idltojava compiler The idltojava compiler is the tool used to create the Java mapping for the OMG IDL You can download it from the http://www .java. sun.com/ The idltojava compiler is not included in JDK 1 .2, and... in Java Step 2: Compiling the IDL file The steps involved in compiling the IDL file are as follows: 1 Go to the command prompt 2 Open the folder that holds the Interest.idl file 3 At the command prompt, run the following command: idltojava Interest.idl This will create Java equivalent files under the directory named InterestApp, which will have five files under it: • Interest .java: This is the Java equivalent... equivalent Java definition for the enum data type is mapped as a final static class in Java — that is, the java file will not contain any definition This class will instead be generated in a sub−package called SamplePackage under the SampleApp package Holder and Helper classes are also created for the enum data types The definition for the Java equivalent to the preceding IDL definition is as follows: Java. .. command prompt: C:\> idltojava Interest.idl This code will create an equivalent Java file in which: • The module statement in the IDL file will correspond to the package name in the Java file, and the interface will correspond to the interface statement in Java (the server will implement this interface) • The IDL statement attribute will correspond to the public members defined in Java • The IDL operation... score1; attribute float score2; string calculateResult(in float score1,in float score2,out char grade); }; }; The equivalent code in Java looks is as follows: package SampleApp; public interface Sample extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity { String name(); void name(String arg); float score1(); void score1(float arg); float score2(); void score2(float arg); boolean calculateResult(float... the Java code 451 Chapter 18: Introducing CORBA • InterestHelper .java: The Helper class converts the generic CORBA object reference to the "Interest" object reference with the help of the narrow() method present in the Helper class • InterestHolder .java: The Holder class resolves the inout parameters • _InterestImplBase .java: This is the IDL skeleton, which will be used on the server • _InterestStub .java: ... corresponds to the package statement in Java If this IDL file is actually compiled for Java mapping, it would have generated a package with the name SampleApp • The second statement, namely the interface statement, is similar to the interface definition in Java • The third statement specifies an operation in IDL This is an operation that must be performed by the interface In Java, this operation would correspond... deadlines, testing requirements, hardware and more Summary Writing and deploying Enterprise JavaBeans is a huge part of any enterprise level application As they have gained more acceptance, the specification has grown to include new uses for them This chapter has covered most of the new functionality included in the EJB 2. 0 specification As you can see, it is a big chapter already, without covering... indicates how basic datatypes are mapped All datatypes in IDL are shown with their equivalents in Java Note that the int and Long datatypes are not interchangeable; take care when defining datatypes as one or the other Table 18−1: IDL Datatypes IDL Datatype Java Datatype Boolean boolean Char char string java. lang.String short short Long int long long long Float float double double The following is the . <method−name>findByCategory</method−name> <method−params> Chapter 17: Using Advanced EJB Techniques 423 <method−param> ;java. lang.String</method−param> <method−param> ;java. lang.String</method−param> . traditionally used Java properties files and the java. util.Properties class to deal with. New Feature The J2SE 1.4 API introduces a standardized preferences API for the first time in the java. util.prefs. env = i_ctx.createSubcontext(" ;java: comp/env"); Object prop = env.lookup("MyProperty"); Chapter 17: Using Advanced EJB Techniques 426 Tip The J2EE specification makes no recommendations

Ngày đăng: 12/08/2014, 19:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan