Application security

So far we have seen how to create security realms in Geronimo that can authenticate users based on credentials stored in a variety of data stores. We will now see how these security realms can be used to secure web, EJB, and EAR applications running in Geronimo.

Configuring web application security

A web application's security is configured by creating security roles and security constraints in its Java EE specific deployment descriptor web.xml file. These security roles are mapped to principals in a server-specific deployment plan, geronimo-web.xml in the case of Geronimo, at application deployment time. The sample application used in this section consists of three JSPs &mdash one with unrestricted access, one accessible by the admin role, and another accessible by the user role. The deployment descriptor web.xml for this application is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="MyWebApp" version="2.5" ... >
<display-name>MyWebApp</display-name>
<login-config>
<auth-method>BASIC</auth-method>
<!-- For 'BASIC', realm-name will be shown in the prompt -->
<realm-name>packt-properties-realm</realm-name>
</login-config>
<!-- Security roles used in the application -->
<security-role><role-name>admin</role-name></security-role>
<security-role><role-name>user</role-name></security-role>
<!-- Configure authorization for Admin pages -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<!-- Configure authorization for User pages -->
<security-constraint>
<web-resource-collection>
<web-resource-name>User</web-resource-name>
<url-pattern>/user/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
</web-app>

Important points to observe in the web.xml file are as follows:

  • The <login-config> tag specifies the method used to authenticate the users and any additional required configuration. In this example, the value BASIC for auth-method means that the login will use a dialog box displayed by the browser. For this auth-method, you can optionally specify a value for realm-name that will be displayed in the dialog box for login.

  • The <security-role> tag declares the security roles that you want to use in this application. There can be zero or more security roles in an application. In this example, two security roles, namely, admin and user are used.

  • The <security-constraint> tag declares the authorization constraints for resources and the <url-pattern> tag specifies the URL pattern to which the constraint should apply. In this example, /admin/* means that all URLs starting with "/admin/" will be subject to this security constraint. Assuming that the application is available at http://localhost:8080/mywebapp, some of the URLs would be http://localhost:8080/mywebapp/admin/admin.jsp, http://localhost:8080/mywebapp/admin/another.jsp, and so on. The <auth-constraint> tag specifies the security roles that have access to the URL pattern.

The <auth-method> tag in login-config inside the application deployment descriptor enables you to specify the authentication method to be used by the web application. Valid values are BASIC, DIGEST, FORM, and CLIENT-CERT. These options are explained as follows:

  • When BASIC or DIGEST is specified, the login happens using a browser-specific dialog box. The BASIC auth-method is used in some of the sample applications used in this book.

  • For FORM auth-method, the login happens using a login page configured using form-login-config. The following is an example of a web application deployment descriptor that configures FORM authentication:

    <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Not required for FORM auth</realm-name>
    <form-login-config>
    <form-login-page>/login/login.jsp</form-login-page>
    <form-error-page>/login/loginerror.jsp</form-error-page>
    </form-login-config>
    </login-config>
    

    An example of how the form should be coded into the HTML page is as follows:

    <form method="POST" action="j_security_check">
    <input type="text" name="j_username">
    <input type="text" name="j_password">
    </form>
    

    The action of the login form must always be j_security_check. The j_username input field should be used to get the username, and the j_password input field should be used to get the user's password.

  • CLIENT-CERT is used if the application uses digital certificates for client authentication.

The deployment plan for this application in geronimo-web.xml, is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-2.0">
<dep:environment xmlns:dep="http://geronimo.apache.org/xml/ns/ deployment-1.2">
<dep:moduleId>
<dep:groupId>packt-samples</dep:groupId>
<dep:artifactId>MyWebApp</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>war</dep:type>
</dep:moduleId>
<dep:dependencies>
<dep:dependency>
<dep:groupId>console.realm</dep:groupId>
<dep:artifactId>packt-properties-realm </dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>car</dep:type>
</dep:dependency>
</dep:dependencies>
</dep:environment>
<context-root>mywebapp</context-root>
<security-realm-name>packt-properties-realm</security-realm-name>
<security>
<role-mappings>
<role role-name="admin">
<principal name="Admin" class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"/>
</role>
<role role-name="user">
<principal name="User" class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"/>
<principal name="vamsi" class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"/>
</role>
</role-mappings>
</security>
</web-app>

Important points to note in the geronimo-web.xml file are as follows:

  • The module has a dependency on console.realm/packt-properties-realm/1.0/car, which is defined in the <environment> element. This dependency is added to make sure that the security realm is started before starting the application. See Appendix A, Deployment Plans, for details on the <environment> element.

  • The <security-realm-name> tag specifies the name of the security realm against which this application should authenticate. Recall that packt-properties-realm is the name used for the properties file realm that you created earlier.

  • The <role> tag under <role-mappings> lets you configure the principals that should be mapped to each role. The role-name attribute is used to specify the role to which the principal elements inside the role tag are to be mapped. Here, the admin role is mapped to a GeronimoGroupPrincipal with a name of Admin, and the user role is mapped to two principals—a GeronimoGroupPrincipal with the name User and a GeronimoUserPrincipal with the name vamsi. Recall that when a user logs into packt-properties-realm, the subject is populated with a GeronimoUserPrincipal with the username and zero or more GeronimoGroupPrincipals with the names of all of the groups that the user belongs to.

If you have configured principal wrapping in your security realm, then you can use the realm-principal and login-domain-principal elements in principal to role mapping in the security configuration of your application's deployment plan. The following is an example of security configuration using realm-principal and login-domain-principal:

<security>
<role-mappings>
<role role-name="admin">
<realm-principal name="packtadmin" domain-name="packt-properties-realm" realm-name="packt-properties-realm" class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"/>
<login-domain-principal name="packtuser1" domain-name="packt-properties-realm" class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"/>
</role>
</role-mappings>
</security>

The login domain name is specified by using the domain-name attribute of the realm-principal and login-domain-principal elements. The security realm name is specified by using the realm-name attribute of the realm-principal element.

Running the sample web application

To run the sample web application, deploy mywebapp-1.0.war provided under the samples. Access the application at http://localhost:8080/mywebapp. Click on the Admin link on the home page, and log in using the userid/password packtadmin/admin. The page will display the details of the user logged in, the roles to which the user belongs, and the principals and credentials in the JAAS subject.

Configuring EJB application security

EJB applications use role-based security for bean-level and method-level security. Authentication and authorization under which each method executes is configured in the Java EE specific deployment descriptor file, ejb-jar.xml. The security roles are mapped to principals in Geronimo-specific deployment plans. We will now see how to define security roles and configure method permissions for EJBs.

Defining security roles in the deployment descriptor

Security roles are defined in the deployment descriptor file ejb-jar.xml by using the security-role element in the assembly descriptor. The role-name child element specifies the name of the security role. The following deployment descriptor defines two roles, namely, ejbuser and ejbadmin:

<ejb-jar>
<enterprise-beans>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<description>Normal User role</description>
<role-name>ejbuser</role-name>
</security-role>
<security-role>
<description>Administrator role</description>
<role-name>ejbadmin</role-name>
</security-role>
</assembly-descriptor>
</ejb-jar>


Declaring method permissions in the deployment descriptor

To configure the security identity to invoke the methods in an EJB, we use the security-identity element in the bean definitions under the enterprise-beans element in ejb-jar.xml. We configure the bean method permissions by using the method-permission element under assembly-descriptor. An XML fragment of the EJB application deployment descriptor used to configure the method permissions for MySessionBean in our sample application is as follows:

<ejb-jar id="MyEjbApp">
<enterprise-beans>
<session>
...
<ejb-name>MySessionBean</ejb-name>
...
<security-identity>
<use-caller-identity />
</security-identity>
</session>
...
</enterprise-beans>
<assembly-descriptor>
<security-role>
</security-role>
...
<method-permission>
<role-name>ejbuser</role-name>
<method>
<ejb-name>MySessionBean</ejb-name>
<method-name>userMethod</method-name>
</method>
</method-permission>
<method-permission>
<role-name>ejbadmin</role-name>
<method>
<ejb-name>MySessionBean</ejb-name>
<method-name>adminMethod</method-name>
</method>
</method-permission>
<method-permission>
<unchecked/>
<method>
<ejb-name>MySessionBean</ejb-name>
<method-name>commonMethod</method-name>
</method>
</method-permission>
<method-permission>
<role-name/>
<method>
<ejb-name>MySessionBean</ejb-name>
<method-name>noaccessMethod</method-name>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>

Let's take a peek at the various XML elements used in this example:

  • The security-identity element specifies the security identity to be used to invoke methods in MySessionBean.

  • The use-caller-identity element specifies that the caller's security identity be used as the security identity for the execution of methods of the enterprise bean. Another option is to use a run-as element to specify that a run-as identity can be used to invoke the bean's methods, as we will show later.

  • The method element of method-permission specifies the security permissions for one or more methods in a bean.

  • You can specify permissions using one or more role-name elements—one for each role that is allowed to access the method. A single empty role-name element means that the role has no access to the method. You specify unrestricted access permission by using an unchecked element.

  • The method's ejb-name element specifies the name of the EJB. The method-name element specifies the name of the method. A value of * for method-name corresponds to all methods in the EJB.

  • A specific method-name corresponds to all methods of that name, including any overloaded methods. To specify a particular method from overloaded methods, use the method-params element.

  • You can configure method-permission for methods in the bean's Home, Remote, Local, and LocalHome interfaces. To specify the permission for a method in a particular interface, use the method-intf element under method with the corresponding value.

In the given example of the MySessionBean, we have configured:

  • userMethod to be accessible by ejbuser role

  • adminMethod to be accessible by ejbadmin role

  • commonMethod to have unrestricted access

  • noaccessMethod to be inaccessible by any role

Using annotations to define roles and permissions

In EJB3 enterprise beans, you can configure the bean-level and method-level security by using security annotations. In this section, we discuss the various security annotations (@DeclareRoles, @DenyAll, @PermitAll, and @RolesAllowed) and how they affect the security configuration. Note that we'll discuss the @RunAs annotation later in this chapter.

Defining security roles

You define security roles by using a @DeclareRoles annotation on a bean class, as shown below:

@Stateless
@DeclareRoles({"ejb3user", "ejb3admin"})
public class MyEjb3ServiceBean implements MyEjb3Service {
...
}

In this example, MyEjb3ServiceBean defines two security roles, namely ejb3user and ejb3admin.

Configuring method permissions

You configure permissions for enterprise beans methods by using the @DenyAll, @PermitAll, and @RolesAllowed annotations. The @PermitAll and @RolesAllowed annotations can be applied to the bean class as well as to bean methods, whereas the @DenyAll annotation can be applied only on bean methods. An annotation applied to a class is applicable to all of the methods in the class. An annotation applied to a method overrides any annotation applied to the class. The MyEjb3ServiceBean class is shown as follows:

@Stateless
@DeclareRoles({"ejb3user", "ejb3admin"})
public class MyEjb3ServiceBean implements MyEjb3Service {
@Resource
private SessionContext ctx;
@PermitAll
public String commonMethod() {
return logCall("commonMethod");
}
@RolesAllowed({"ejb3user"})
public String userMethod() {
return logCall("userMethod");
}
@RolesAllowed({"ejb3admin"})
public String adminMethod() {
return logCall("adminMethod");
}
@DenyAll
public String noaccessMethod() {
return logCall("noaccessMethod");
}
private String logCall(String method) {
...
return msg;
}
}

This example defines the following access configuration:

  • commonMethod has unrestricted access

  • userMethod is accessible by the ejb3user role

  • adminMethod is accessible by the ejb3admin role

  • noaccessMethod is not accessible by any role

Mapping principals to roles in the EJB deployment plan

The security roles defined in the EJB deployment descriptor and the roles defined by using the @DeclareRoles annotation are mapped to principals in the EJB deployment plan openejb-jar.xml. The following code snippet shows an example of a principal to role mapping in the EJB deployment plan:

<security>
<role-mappings>
<role role-name="ejbuser">
<principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" name="User"/>
</role>
<role role-name="ejbadmin">
<principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" name="Admin"/>
</role>
<role role-name="ejb3user">
<principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" name="User"/>
</role>
<role role-name="ejb3admin">
<principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" name="Admin"/>
<principal class="o.a.g.s.r.providers.GeronimoUserPrincipal" name="packtuser3"/>
</role>
</role-mappings>
</security>

Notice that the security roles in the ejb-jar.xml file and security roles in the @DeclareRoles annotation are mapped to principals as follows:

  • The ejbuser role is mapped to a GeronimoGroupPrincipal with the name User

  • The ejbadmin role is mapped to a GeronimoGroupPrincipal with the name Admin

  • The ejb3user role is mapped to a GeronimoGroupPrincipal with the name User

  • The ejb3admin role is mapped to a GeronimoGroupPrincipal with the name Admin and a GeronimoUserPrincipal with the name packtuser3

Running the EJB sample application

To access the EJBs in the EJB sample application, we have created a web application. Follow the steps, as shown, to deploy and run the EJB sample application and the web application:

  1. Deploy the myejbapp-1.0.jar application by using a command-line deployer or the Deploy New portlet.

  2. Deploy the myejbwebapp-1.0.war application by using a command-line deployer or the Deploy New portlet.

  3. Access http://localhost:8080/myejbwebapp.

    Because the user has not logged into the application, only commonMethod in MySessionBean, and MyEjb3ServiceBean, which has unrestricted access, can be invoked from the home page. All of the other method invocations will result in AccessException or an EJBAccessException, as the principal is not authorized.


  4. Access http://localhost:8080/myejbwebapp/bank/. Log in with the username packtadmin and the password admin.

  5. Because the user is now logged in as packtadmin, the JAAS subject contains GeronimoUserPrincipal with the name packtadmin and GeronimoGroupPrincipal with the name Admin. The user maps to the ejbadmin and ejb3admin roles, as per the role mapping. Hence, the user can access commonMethod, which has unrestricted access, and adminMethod, which is accessible by the ejbadmin role for MySessionBean, and the ejb3admin role for MyEjb3ServiceBean. The userMethod and noaccessMethod will result in an AccessException or an EJBAccessException upon invocation. userMethod is accessible by the ejbuser role ( ejb3user role for MyEjb3ServiceBean), and noaccessMethod is not accessible by any role.

  6. Open a new browser window and access http://localhost:8080/myejbwebapp/customer/. Log in with the name packtuser3 and the password user3.

Because the user is now logged in as packtuser3, the JAAS subject contains GeronimoUserPrincipal with the name packtuser3 and GeronimoGroupPrincipal with the name User. The user maps to the ejbuser, ejb3user, and ejb3admin roles, as per the role mapping. In MySessionBean, the user can access commonMethod, which has unrestricted access, and the userMethod, which is accessible by the ejbuser role. In MyEjb3ServiceBean, the user can access commonMethod, which has unrestricted access, the userMethod that is accessible by the ejb3user role, and adminMethod, which is accessible by the ejb3admin role. All other methods will result in an AccessException or an EJBAccessException upon invocation.

Configuring entity bean security

You can configure entity bean security by using the deployment-descriptor and security annotations in the same way as we did for session bean security. The following code snippet shows the assembly-descriptor from a sample EJB application with an entity bean.

<assembly-descriptor>
<security-role>
<description>Bank Manager</description>
<role-name>manager</role-name>
</security-role>
<method-permission>
<role-name>manager</role-name>
<method>
<ejb-name>MyBank</ejb-name>
<method-name>create</method-name>
</method>
</method-permission>
</assembly-descriptor>

In this example, we configured the create method on the home interface of the MyBank entity bean to be accessible only by the manager role.

Run-as and default subjects

In addition to configuring method permissions for a bean's methods, you can configure a run-as role for the bean, in order to specify the security identity with which the bean invokes other beans. This configuration is useful when a bean's method needs to invoke other beans with a different security identity than the security identity with which it is invoked. An example of this would be where a message-driven bean method that is invoked with no security identity invokes a secured session-bean method. You configure the security credentials that constitute the subject for run-as role security in the deployment plan.

In Geronimo releases prior to 2.0, security configuration for run-as and default subjects were constructed by using the principals and credentials specified using the default-principal tag and the designated-run-as attribute of principal. Starting with Geronimo 2.0, all security flows from subjects are created by logging into a security realm. To use these subjects, you need to supply login information for every such subject. This login information is captured in a credential store.

Credential store

Geronimo provides an implementation of credential store, namely SimpleCredentialStoreImpl, that allows the configuration of a credential store by using XML in the deployment plans. The following code snippet shows the credential store we use in the sample applications:

<gbean name="SampleCredentialStore" class="o.a.g.s.credentialstore.SimpleCredentialStoreImpl>
<xml-attribute name="credentialStore">
<credential-store xmlns="http://geronimo.apache.org/xml/ns/credentialstore-1.0">
<realm name="packt-properties-realm">
<subject>
<id>packtuser1-subject</id>
<credential>
<type>o.a.g.s.credentialstore.NameCallbackHandler</type>
<value>packtuser1</value>
</credential>
<credential>
<type>o.a.g.s.credentialstore.PasswordCallbackHandler</type>
<value>user1</value>
</credential>
</subject>
<subject>
<id>packtuser2-subject</id>
...
</subject>
<subject>
<id>packtuser3-subject</id>
...
</subject>
<subject>
<id>packtadmin-subject</id>
...
</subject>
</realm>
<realm name="AnotherRealm">
<subject>
...
</subject>
...
</realm>
</credential-store>
</xml-attribute>
</gbean>

Here, the name attribute of the realm element specifies the name of the security-realm that you use to create the subject. The id child element under the subject element specifies an ID for the subject that can be used in combination with the security-realm name when configuring run-as and default subjects, as we will show later.

You use the credential child element under the subject element to configure the login information for the security-realm. In this example, we obtain packtuser1-subject by logging into the packt-properties-realm using the username packtuser1 and the password user1. Geronimo provides callback handlers for the name and the password that are sufficient for using security realms that need a name and a password to authenticate. For using other security realms with the credential store, for example ones that use digital certificates, you need to implement the required callback handlers. Moreover, the credential stores can be defined per application, or you can have one credential store that is used by all applications.

Configuring an application to use a credential store

You specify the credential store to be used by an application in the security configuration in the application's deployment plan. The following code snippet shows the security configuration of one of the sample applications:

<security>
<credential-store-ref>
<name xmlns="http://geronimo.apache.org/xml/ns/deployment- 1.2">
SampleCredentialStore</name>
</credential-store-ref>
...
</security>

In this example, the name child element under credential-store-ref specifies the credential store to be used by the application. Note that this value matches the name attribute of the credential store in the GBean shown earlier.

Configuring run-as and default subjects

You specify the run-as and default subjects for the application in the security configuration in the application's deployment plan. If a run-as subject is not configured for any role, then the configured default-subject will be used instead. The following shows the run-as and default-subject configuration for one of the sample applications that we use in this book:

<security>
...
<default-subject>
<realm>packt-properties-realm</realm>
<id>packtuser1-subject</id>
</default-subject>
<role-mappings>
<role role-name="ejb3user">
<run-as-subject>
<realm>packt-properties-realm</realm>
<id>packtuser3-subject</id>
</run-as-subject>
<principal class="o.a.g.s.r.providers. GeronimoGroupPrincipal" name="User"/>
</role>
<role role-name="another">
...
</role>
...
</role-mappings>
</security>

The default-subject child element under the security element configures the default subject used by the application. The realm child element under default-subject specifies the security-realm, and the id child element specifies the ID of the subject, as configured in the credential store. Notice that the value specified for the realm under default-subject matches the name attribute of the realm element in SampleCredentialStore. Moreover, note that the value specified for the id under default-subject matches one of the subject's ID in SampleCredentialStore.

The run-as-subject child element in the role element under role-mappings configures the run-as subject for that role. The given code fragment shows run-as-subject configured for the ejb3user role. Notice that the value specified for realm under run-as-subject matches the name attribute of the realm element in SampleCredentialStore. Moreover, note that the value specified for id under run-as-subject matches one of the subject's ID in SampleCredentialStore.

Running a sample EJB application with run-as

We have added two more session beans, MyEjb3ServiceBean2 and MyEjb3SeviceBean3, that in turn invoke the corresponding methods in MyEjb3ServiceBean. We configured MyEjb3ServiceBean2 to run as an ejb3user role. MyEjb3ServiceBean3 is not configured with a run-as role. The following code snippet shows the MyEjb3ServiceBean2 bean class:

@Stateless
@DeclareRoles(value = {"ejb3user", "ejb3admin"})
@RunAs("ejb3user")
public class MyEjb3ServiceBean2 implements MyEjb3Service2 {
@EJB
private MyEjb3Service myejb3service; // MyEjb3Service injected here
@PermitAll
public String commonMethod() {
Object temp;
try {
temp = myejb3service.commonMethod();
} catch(Throwable t) {
temp = t;
}
return logCall("commonMethod") + "::" + temp;
}
@RolesAllowed({"ejb3user"})
public String userMethod() {
...
}
@RolesAllowed({"ejb3admin"})
public String adminMethod() {
...
}
@DenyAll
public String noaccessMethod() {
...
}
private String logCall(String method) {
...
}
}

In this example, we used the @RunAs annotation with the ejb3user role to configure the run-as role for MyEjb3ServiceBean2. With this configuration, the invocation of methods on MyEjb3Service uses the run-as-subject, as specified in the deployment plan. Note that the run-as-subject for the ejb3user role is specified as packtuser3-subject. To run the EJB sample with default and run-as subjects, redeploy myejbapp-1.0.jar along with the deployment plan myejbapp-w-runas.xml provided in the samples. Once done, restart the myejbwebapp web application, and access the application at http://localhost:8080/myejbwebapp.

Configuring message-driven bean security

Unlike session and entity beans, message-driven beans are not invoked by other beans or client applications. They are invoked by a JMS listener when a message arrives on the input destination that the listener is monitoring. Message-driven beans can invoke other session and entity beans. To invoke secure EJBs from a message-driven bean, the message-driven bean needs to be configured with a run-as role. For an EJB2.1 message-driven bean, you can configure the run-as role by using the security-identity element in the deployment descriptor. For an EJB3 message-driven bean, you configure run-as role using a @RunAs annotation.

Configuring EAR application security

So far, we have seen the security configuration for Web and EJB applications. Recall that the principal to role mapping is done in the deployment plan for each application. With an EAR application, the principal to role mapping can be done at the EAR level and is common to all web and EJB modules in the EAR. The deployment plan for web modules only need to specify the security realm against which the application will authenticate.

Application-scoped security realms

Recall that the security realm deployment plan defines a GenericSecurityRealm GBean that runs in its own configuration. This GBean definition could be added to the deployment plan of a web or an EAR application so that the application does not require a dependency on the configuration that is running the security realm. In this case, the security realm GBean runs within the configuration of the application using the realm. Therefore, the realm gets stopped and starts along with the application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset