Friday Sep 17, 2010

A Simple Secure Embedded Web Test Client in GlassFish v3.1

Following the posts (i), (ii) , (iii) related to deploying secure ejb applications in the Glassfish embedded mode, this post is about deploying a secure web-application in GlassFish in the embedded mode. Similar to the EmbeddedEjbContainer API, the EmbeddedWebContainer API in glassfish v3.1 can be used to deploy webapps. The deployed web-app could either be accessed using a URLConnection in the same EmbeddedTest Client or from a browser (provided the Embedded server with the Container is still running).In this post, we look at deploying a secure webapp (web-app protected by a user-data constraint)

Consider a simple webapp that is protected by a user-data constraint.

        <user-data-constraint>
            <description/>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>

To test this war file, one could write a simple Embedded Web Test Client that uses the EmbeddedWebContainer API to deploy this app.As can be observed from this test client, the server containing the embeddable webcontainer is not stopped immediately on program exit. So the deployed web-app can be accessed from a browser (http://localhost:8080/simpleweb). Since this app is protected by a user-data constraint, the redirection to https and the secure port (8181) can be observed.


Monday Mar 29, 2010

Accessing ORB service securely in GlassFish v3

Transport Security in EJB is indicated by the IOR  (Interoperable Object Reference ) security representation of the ORB (Object Request Broker) layer. In Glassfish, the security-configuration information for the ORB is specified using the <ior-security-config> element of the sun-ejb-jar.xml.  The <transport-config> is a child element of the <ior-security-config> and is the root element for security between the end points.

<!ELEMENT transport-config ( integrity, confidentiality, establish-trust-in-target, establish-trust-in-client )>

The integrity and confidentiality child elements indicate if the target requires/supports integrity-protected or privacy-protected messages. The valid values are NONE, SUPPORTED or REQUIRED.

<!ELEMENT integrity ( #PCDATA)>
<!ELEMENT confidentiality ( #PCDATA)>

The establish-trust-in-target and establish-trust-in-client elements indicate if the target (server) is capable of authenticating to a client.

The transport between the client and the server can be secured with an <ior-security-config> element that is similar to :

 <ior-security-config>
                <transport-config>
                        <integrity>
                               REQUIRED
                        </integrity>
                        <confidentiality>
                              REQUIRED
                       </confidentiality>
                      <establish-trust-in-target>SUPPORTED</establish-trust-in-target>
                      <establish-trust-in-client>SUPPORTED</establish-trust-in-client>
               </transport-config>

<ior-security-config>

However with the above IOR configuration, the client is not guaranteed to contact the name service securely (the service that is invoked by a call to InitialContext.lookup() ). This service usually runs on port 3700 non-securely and on port 3820 securely in Glassfish. By default, the client contacts the name service of the application server non-securely on port 3700 . To secure this connection in GlassFish v3, the following techniques could be used:

1. When using an application client, the sun-acc.xml in <domain-dir>/config should be modified to include a security element inside the target-server parent element:

<target-server name="localhost" address="localhost" port="3820">
       <security>
               <ssl/>
       </security>

 </target-server>

This indicates to the server that the client demands a secure ORB connection. While running the appclient, the following system properties are passed:

-Djavax.net.ssl.trustStore=<domain-dir>/config/cacerts.jks

-Djavax.net.ssl.keyStore=<domain-dir>/config/keystore.jks

-Djavax.net.ssl.trustStorePassword=<password>

-Djavax.net.ssl.keyStorePassword=<password>

-Dorg.omg.CORBA.ORBInitialPort=3820 (This forces the client to contact the secure ORB service provided by the application server.

Now, on running the appclient with the above system properties, the name service connection is also secured along with the other transport.

2. When using a standalone POJO client, in addition to setting the above system properties , an additional property for indicating the client's preference for secure ORB connection is to be set:

-Dcom.sun.CSIV2.ssl.standalone.client.required=true

With this, the client can contact the name service of the server securely. This feature is available in the latest trunk builds of GlassFish v3.

Wednesday Mar 17, 2010

Running a secure application in Glassfish Embedded Server - Part II

Following the previous post illustrating how to run a secure ejb application on GlassFish embedded server, this post aims to focus on running a secure web application using GlassFish embedded server. Here is a sample web-app (with context-root - simpleweb) and restricts access to file users of group "tester". (Please examine the web.xml and sun-web.xml for details). It has been configured for BASIC auth using file-realm. To test this web-app, an embedded server could be configured to use an existing non-embedded GlassFish instance's filesystem. The web-app could then be deployed on this embedded server.

        Server.Builder builder = new Server.Builder("web-test");
        EmbeddedFileSystem.Builder efsBuilder = new EmbeddedFileSystem.Builder();
        efsBuilder.instanceRoot(new File(instanceRoot));
        builder.embeddedFileSystem(efsBuilder.build());
        Server server = builder.build();

        server.addContainer(ContainerBuilder.Type.web);
        server.start();
        EmbeddedDeployer deployer = server.getDeployer();
        String appName = deployer.deploy(new File(testWarDir, testWar), null);
        System.out.println("Deployed " + appName);

The non-embedded GlassFish instance should be configured to contain file users of group tester (that has been configured in sun-web.xml of the web-app).

./asadmin create-file-user --groups tester testuser

Now, the web-app can be accessed from the browser. (http://localhost:8080/simpleweb). In response to the challenge, the username (testuser) and password are provided to access the protected page. Here is the complete test file.

PS - The Embedded API in GlassFish 3.1 has undergone some changes (from the API used in this blog post. Please refer to this link for the latest Embedded API)

Thursday Feb 18, 2010

Running a secure application in Glassfish Embedded Server

The embedded server and the embedded API are a key new feature offered by the Glassfish v3 server. Among many advantages, it offers the ability to deploy and test web/ejb applications using an embedded server that can be run on the same VM as the test application. This document provides details on the embedded server, deploying and running applications and discusses the embedded API. If a user wants to deploy a secure application with protected methods, the user has to provide authentication credentials to the embedded server before invoking the protected methods. This post discusses how this could be done.

Lets consider a secure EJB, whose methods are protected by the RolesAllowed annotation - allowing access to users with role 'admin'. Let's assume that this role is mapped to the group admin using the sun-ejb-jar.xml. If not, the default principal-role-mapping could be enabled in the embedded server. To run the application, the ProgrammaticLogin API could be used to provide auth credentials. There are two ways to do access the file realm users: (i) Use an existing non-embedded instance of glassfish with existing file users and set it as the embedded server's file system. (ii) Use the asadmin command to create file users in the default embedded server.

Approach I - Using an existing instance of glassfish:

1. Create a file user (embedtester) belonging to the specified group (admin) in an existing non-embedded glassfish server instance using the admin console or the CLI.

2. If required, turn on the default principal-role mapping for the instance (through the admin-console or CLI) - when no principal-role mapping is provided in the application's sun-ejb-jar.xml

3. Using the following code snippet, use the instance to be set as the embedded server's instance root:

        EmbeddedFileSystem.Builder efsBuilder = new EmbeddedFileSystem.Builder();       
        efsBuilder.instanceRoot(new File(
<path to glassfish instance domain directory>));
        efsBuilder.configurationFile(new File(
<path to glassfish instance domain.xml>));
        Server.Builder builder = new Server.Builder("test");
        builder.embeddedFileSystem(efsBuilder.build());
        Server server = builder.build();

4. After deploying the embedded ejb (refer the document for more details ) , before invoking the protected method on the Ejb, call the ProgrammaticLogin's login method to authenticate the user:

            ProgrammaticLogin pgLogin = new ProgrammaticLogin();
            pgLogin.login("embedtester", "abc12345", "file", true);

Approach II - Creating file users using the asadmin command in the embedded server:

If the default embedded server has to be used without setting an existing configuration or instanceRoot, file users could be created in the embedded server using the asadmin command.

1. Create the embedded server and start it.

2. Run the asadmin create-file-user command :

        String command = "create-file-user";
        ParameterMap params = new ParameterMap();
        params.add("userpassword", "abc12345" );
        params.add("groups", "admin");
        params.add("username", "embedtester");
        CommandRunner runner = server.getHabitat().getComponent(CommandRunner.class);
        ActionReport report = server.getHabitat().getComponent(ActionReport.class);
        runner.getCommandInvocation(command, report).parameters(params).execute();

2. Deploy the application and invoke ProgrammaticLogin.login() before calling the protected method.

            ProgrammaticLogin pgLogin = new ProgrammaticLogin();
            pgLogin.login("embedtester", "abc12345", "file", true);

The ProgrammaticLogin API (com.sun.appserv.security.ProgrammaticLogin) is available as a part of security.jar in <GF-DOMAIN-DIR>/modules directory. Here is a sample test client (and the ejb) that invokes a protected method of the ejb (HelloWorldBean).

PS - The Embedded API in GlassFish 3.1 has undergone some changes (from the API used in this blog post. Please refer to this link for the latest Embedded API)


Friday Feb 05, 2010

New Security Features in Glassfish v3 (Java EE 6) - Part III

The login() method 

In continuation of the previous articles discussing the new security features in Servlet 3.0 in GlassFish v3, this post aims to discuss about the other programmatic way to login to a web application - the login method of the HttpServletRequest API. -

  HttpServletRequest.login(String username, String password) throws ServletException

Similar to the authenticate() method, the login() method serves to authenticate a given username and password programatically. As mentioned in this blog post, this method throws a ServletException when the validation of username, password provided fails or if the caller identity has been already established before a call to this method or if the configured login mechanism (in web.xml) is does not support username, password validation.

A recent fix was made to have the authentication state in the existing session after a successful login. The session is created if it does not exist at this time to store the auth state. In the orthogonal HttpServletRequest.logout() method, this authentication state is cleared from the session. This change is available in the GlassFish v3 trunk and in the upcoming releases of GlassFish.


Thursday Dec 24, 2009

New Security Features in Glassfish v3 (Java EE 6) - Part II

The authenticate() method

In continuation of the post on the new security features in Java EE 6  that focused on http-method-omissions, this post aims to elucidate yet another feature in servlet security introduced in Java EE 6 (and implemented in Glassfish v3) - the authenticate() method.

This method is provided in the javax.servlet.http.HttpServletRequest  interface. The method signature is as follows:

 public boolean authenticate(HttpServletResponse response) throws IOException,ServletException

This method is one of the  examples of programmatic security (login, in particular) in Java EE 6. It can be used as an alternative to the <auth-constraint>. When used in a servlet or a JSP, it forces authentication, using the login-mechanism specified in web.xml, even if no security-constraint element is specified in the web.xml.

After a call to authenticate succeeds, the user credentials are validated and the following methods provide the expected results:

(i) getRemoteUser() - the name of the remote user associated with the request,

(ii) isUserInRole() - determines if the remote user (that is, the caller) associated with the request is in a specified security role - returns true after a successful authenticate, provided the role is specified.

(iii) getUserPrincipal()  - method determines the principal name of the remote user (that is, the caller) and returns a java.security.Principal object corresponding to the remote user.

The advantage of using the authenticate method is that it provides the flexibility to login in dynamically combined with the ability to be used with the configured  login-mechanism like BASIC. Here is a sample application that illustrates the authenticate method. On deploying the war file and accessing the servlet (http://<server-name>:<port-number>/testsam/test , BASIC authentication is forced by the  container, since the call to authenticate() is made in the service method of the servlet.

New Security Features in Glassfish v3 (Java EE 6) - Part I

The http-method-omission element

Now that Java EE 6 has been officially released and Glassfish v3 (the first application server that supports Java EE 6) is shipped along with it,  it might be beneficial to see what are the new features (in security) that are added to Java EE 6 and are implemented in Glassfish v3. The servlet 3.0 specification brings in many new features of security. This post illustrates one feature - the new http-method-omission element.

As many developers working in web security would know, currently, to protect a set of resources with an auth-constraint, the security-constraint element is added to the portable deployment descriptor (the web.xml). 

For instance in Java EE 5,

   <security-constraint>
        <display-name>WebConstraint</display-name>
        <web-resource-collection>
            <web-resource-name>test</web-resource-name>
            <description/>
            <url-pattern>/test.jsp</url-pattern>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>

        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>dev</role-name>
         </auth-constraint>
   </security-constraint>

the above element indicates that the  resource referenced by the url pattern /test.jsp, when accessed by all the http-methods except GET  , should be constrained to be viewed only by authenticated users belonging to the role dev. Please note that the security constraint does not apply for  the http-method GET, but only for the other methods (POST, HEAD, PUT, etc).

In Java EE 6, there is an additional facility - http-method-omission, by which one could specify the methods that are omitted from the constraint.

For instance, the above security-constraint element could be re-written as :

<security-constraint>
        <display-name>WebConstraint</display-name>
        <web-resource-collection>
            <web-resource-name>test</web-resource-name>
            <description/>
            <url-pattern>/test.jsp</url-pattern>
            <http-method-omission>GET</http-method-omission>

        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>dev</role-name>
         </auth-constraint>
   </security-constraint>

which means that the auth-constraint for the resource accessible by the url-pattern /test.jsp is applicable for all methods except GET. This is a simpler alternative of providing the constraint methods.

Here is another example web-application that uses the  http-method-omission element. As can be observed in the web.xml, there are two security-constraint elements. In the first one, all the methods except POST are precluded from  accessing the resource. In the second constraint, only GET and POST are allowed conditional access to the same resource. The combined effect of the constraints is that, only POST is allowed conditional access to the resource.

A single web-resource-collection element cannot have both http-method and http-method-omission elements. In those cases,  distinct   web-resource-collection elements under distinct security-constraint elements must be provided. Whether or not a given  http-method is applicable for an auth-constraint is  obtained as per the algorithm defined in the spec:

"...an HTTP method is said to occur within a web- resource-collection when no HTTP methods are named in the collection, or the collection specifically names the HTTP method in a contained http-method element, or the collection contains one or more http-method-omission elements, none of which names the HTTP method...."

Please refer to Chapter 13, Sec 8.1 of the Servlet 3.0 spec for more details on the rules for combined security-constraints.


Thursday Jan 08, 2009

Modularized OSGi Custom Realms in Glassfish v3

The Open Services Gateway Initiative (OSGi) defines an architecture for developing and deploying modular applications and libraries. Since Glassfish v3 is a modular, embeddable and an OSGi compliant  server, custom realms that are built based on the OSGi framework can be easily integrated and configured with GF v3.This facilitates the creation and configuration of a custom realm without any server restart.

 To be recognized as a valid custom realm  OSGi module, in addition to the OSGi mandated structure, the custom realm  should include the following:

i)The Realm class should include the @Service annotation, with the name attribute referring to the name of the custom realm to be configured:

@Service(name="SampleRealm")

where @Service is a hk2-specific annotation.

ii) There should be a file named javax.security.auth.spi.LoginModule  inside META-INF/services directory of the module archive file. The file should specify the fully qualified name of the Custom Login Module class as in:

com.samplerealm.SampleLoginModule

A sample OSGi custom realm module can be downloaded from here. On dropping this file in <GF-HOME>/autodeploy-bundles directory, the module should be loaded. Do make sure   that the <GF-HOME>/<DOMAIN-DIR>/login.conf file has an entry for the jaas-context value, referring to the Module implementation class. This entry can be dynamically added to login.conf(before creating the realm). (This post provides a detailed description on creating a custom realm for GF.)

The realm can now be created from the admin console (name matching the service name specified in the Realm class). This should initialize the realm. No server restart required. On deploying and accessing an application utilizing this realm, the Login module should be initialized as well.This feature works with the latest GF v3 trunk installation.



Monday Dec 29, 2008

Custom Realms and Groups in Glassfish

Glassfish  provides support for Custom Realms and Custom Login Modules that are based on the JAAS framework. This post explains how to write a simple Realm class and its corresponding LoginModule, configure them with an illustration of a simple web application that uses this realm.

Custom Realm

The Custom Realm should extend com.sun.appserv.security.AppservRealm. The Realm class is basically meant to provide user and group-related information. The methods to be implemented are

i) public void init(Properties properties )throws BadRealmException, NoSuchRealmException

This method is invoked during server startup when the realm is initially loaded.  The realm can do any initialization it needs in this method. The Properties is a set of key-value pairs configured while creating the Realm and are present in domain.xml. Among the other custom properties, there is a property jaas-context (which is explained later in this post). This property should be set using the call setProperty method implemented in the parent class. If the method returns without throwing an exception, the Enterprise Server assumes that the realm is ready to service authentication requests. If an exception is thrown, the realm is disabled.

ii) public String getAuthType() - This method returns a descriptive string representing the type of authentication done by this realm.

iii) public Enumeration getGroupNames(String user) throws InvalidOperationException, NoSuchUserException -
This method returns the group names the user belongs to as an Enumeration of Strings.

Custom LoginModule

The Custom LoginModule should extend com.sun.appserv.security.AppservPasswordLoginModule. This class should override the method

abstract protected void authenticateUser() throws LoginException

This method performs the actual custom authentication, by either using a database, or LDAP or a file or even a simple Hashtable as illustrated in the attached sample code. The custom login module must not implement any of the other methods, such as login(), logout(), abort(), commit(), or initialize(). Default implementations are provided in AppservPasswordLoginModule which hook into the Enterprise Server infrastructure.

The custom login module can access the following protected object fields, which it inherits from AppservPasswordLoginModule. These contain the user name, password of the user to be authenticated and the currentRealm class.

protected String _username;

protected String _password;

protected com.sun.enterprise.security.auth.realm.Realm  _currentRealm;

The authenticateUser() method should end with a call to the commitUserAuthentication(String[] authenticatedGroupList) method where the authenticatedGroupList is the list of groups the user belongs to.

As can be observed, the realm class is isolated from the LoginModule. The Realm is capable of capturing arbitrary configuration information and can help in obtaining the Group information. The Group information from the Realm can be  populated into the authenticated JAAS subject during commit() phase following a  successful LoginContext.login() call on the  authentication module. This populated group information is then used by the container in its authorization policy decisions.

Attached here is the source code of a simple sample realm class and the custom module. In this example, the Realm class stores the user-group information in a hashtable. The LoginModule class stores the user-password information in a hashtable and performs authentication. It obtains the authenticatedGroupList from the Realm class' getGroups(username) method.

To test this sample(it works with both GF v2 and v3), download and install Glassfish v3 from here, drop the binaries of this realm and custom module in <GF-ROOT>/domains/domain1/lib/, start the server and create the realm using the Admin console. The realm classname should be specified as com.samplerealm.SampleRealm.

An additional realm property jaas-context should be specified to say sampleRealm. This value should refer to the SampleLoginModule class in the

<GF-ROOT>/domains/domain1/config/login.conf

file as follows:

sampleRealm {
       com.samplerealm.SampleLoginModule required;
};

where sampleRealm refers to the value defined in the jaas-context property.

As can be seen from the source files, the users configured in this realm are userA, userB whose corresponding passwords are abc123, xyz123. userA has been configured in the group devGroup, while userB belongs to testGroup. To test this realm, this web-application can be used.

Observe that the web.xml of the web-app contains the following :

<login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>SampleRealm</realm-name>
     </login-config>

where  SampleRealm in the <login-conf><realm-name> element points to the name of the configured Realm as can be seen in the server's domain.xml

        <auth-realm classname="com.samplerealm.SampleRealm" name="SampleRealm">
          <property name="jaas-context" value="sampleRealm"></property>
        </auth-realm>

To access the web-app using the group names of the user, the following mapping between the role and group is required in sun-web.xml:

  <security-role-mapping>
    <role-name>tester</role-name>
    <group-name>devgroup</group-name>
  </security-role-mapping>

where the role-name matches the configured role in the auth-constraint of web.xml

        <auth-constraint>
            <description/>
            <role-name>tester</role-name>
         </auth-constraint>

and group-name is the corresponding group the user belongs to as defined in the custom realm class. So if the application is accessed using the user/password: userA/abc123, the user is authorized to view the pages, since he belongs to the devGroup, but not userB/xyz123 (who belongs to testGroup).


About

nitkal

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks