Friday Apr 06, 2007

GlassFish uses Java JKS for storing keys and certificates. Out of the box, the keyStore (keystore.jks) and the trustStore (cacerts.jks) reside in $GLASSFISH_HOME/domains/domain1. Even though there are several CA root certificates in cacerts.jks, there is only one private key in keystore.jks.

GlassFish supports the use of multiple private keys in a given domains. For instance, you may have two https listeners having different server private keys. This is a very useful scenario especially when one have EC key. So, in a given domain, we can have one https listener using RSA key for normal browser and one https listener using EC key for PDA.

In this blog, we will discuss the configuration when there are multiple private keys in a given domain of GlassFish. In this case, one needs to specify the private key / certificate to be used for SSL communication. If the information is not specified, then the server will pick up one which may not be desirable. Since one wants to be more precise in security environment, one would like to specify the corresponding certificate nickname in order to pick up the correct key.

There are two kinds of certificate nicknames: inbound, https outbound.

Inbound Certificate Nickname

One needs to specify the inbound cert-nickname for a given listener in domain.xml. For instance, in http listener, it is as follows:

    <http-listener ... security-enabled="true" ... />
      <ssl cert-nickname="s1as" ... />
      ...

Instead of hand-crafting the domain.xml, it would be a good idea to use Admin Console as follows: Configuration > HTTP Services > Http listeners > http-listener-2, and choose SSL tab and enter the valid alias value you want in "Certificate Nickname" textbox. Then one needs to restart the given domain (if there is a change of certificate nickname) in order to activate the change.

Similarly for iiop listeners.

Https Outbound Certificate Nickname

GlassFish also supports the https outbound from server. A private key / certificate is used for https outbound mutual SSL authentication. In this case, we can specify the https outbound certificate nickname as jvm-options in domain.xml:

    -Dcom.sun.enterprise.security.httpsOutboundKeyAlias=YOUR_ALIAS

One can achieve this through Admin Console as follows: Application Server > JVM Settings > JVM Options > Add JVM option, and enter the above jvm option in the new textbox. Then one needs to restart the server in order to activate this change.

Friday Mar 23, 2007

JSR 196, Java Authentication SPI for Containers, defines SPI for providers plugging into containers for message authentication. It is currently under Proposed Final Draft (PFD) and GlassFish v2 (b40 rc or above) has an implementation of PFD of this JSR. On the other hand, AJAX is another new and exciting technology in the Web 2.0 area. In this blog, I will share my experience with you about constructing a web tool to browse 196 AuthConfigProviders registered in GlassFish by using AJAX tree.

I find that it is very helpful to use jMaki plugin in NetBeans 5.5.1. A jMaki widget can be created in a jsp application by simply drag-and-drop. A very good tutorial can be found in jMaki NetBeans 5.5 screencast.

In the following, I will outline steps to create my web application.

  1. Create a "Web Applicatons" project with name listacp using NetBeans as described in above screencast.
  2. Open index.jsp if it is not already open. Then drag and drop a "jMaki Yahoo Tree" from the left Palette to the jsp. And the following code will be generated in the jsp:

      <a:ajax name="yahoo.tree"/>

    This will create a AJAX Tree with the default data.

  3. We would like to construct the tree using data in JSON format from GlassFish server. In our case, the data is coming from acpdata.jsp. We need to modify the above as follows:

      <a:ajax name="yahoo.tree" service="/acpdata.jsp"/>

  4. In acpdata.jsp, we need to get a complete list of AuthConfigProvider. This can achieved by getting a complete list of registration ID first.

      AuthConfigFactory factory = AuthConfigFactory.getFactory();
      if (factory != null) {
        String[] regisIDs = factory.getRegistrationIDs(null);

    And for each registration ID, we can get RegistrationContext and AuthConfigProvider as follows:

      RegistrationContext regContext = factory.getRegistrationContext(regisID);
      if (regContext != null) {
        String layer = regContext.getMessageLayer();
        String appContext = regContext.getAppContext();
        AuthConfigProvider provider = factory.getConfigProvider(layer, appContext, null);

  5. Then we need to output the data in corresponding JSON format. An example of the format from corresponding source of the Yahoo Tree Widget can be found in jMaki Widget Gallery. For instance, in our case, acpdata.jsp outputs the data as

      { root: {
        title: '196 factory: com.sun.enterprise.security.jmac.config.GFAuthConfigFactory',
        expanded: 'true',
        children: [
        {
          title: 'registrationID = __2SOAP',
          expanded: 'false',
          children: [
            { title: 'messageLayer = SOAP'},
            { title: 'appContext = null'},
            { title: 'description = WSIT AuthConfigProvider'},
            { title: 'persistent = false'},
            { title: 'provider = com.sun.xml.wss.provider.wsit.WSITAuthConfigProvider@14a8f44'}
          ]
        }
        ,
      ...

  6. Protect the web application
    Since the list of AuthConfigProviders will reveal what has been deployed in the given GlassFish installation, we would like to protect this web application so that only users of asadmin group of admin-realm can access it. We can achieve this by:

    Adding security setting in web.xml through NetBeans by navigating the Web application on panel of NetBeans: Web Pages > WEB-INF, open web.xml, and click Security, and modifying it as follows:
      Login Configuration: Basic
      Realm Name: admin-realm

      Add Security Roles: admin

      Add Security Constraint
        Resource Name: secure resource
        URL Pattern(s): /*

      Click on "Enable Security Constraint"
        Role Names: admin

    Then, adding the security-role-mapping to sun-web.xml through "Edit As XML" mode:

      <security-role-mapping>
        <role-name>admin</role-name>
        <principal-name>admin</principal-name>
        <group-name>asadmin</group-name>
      </security-role-mapping>

  7. If we package the war file and deploy, then we can access

      http://your_host:your_port/listacp

    Enter your admin username and password. Everything works! The only drawback is the war file size is too big right now. In order to make it smaller, we have to remove unused AJAX libraries manually at this moment. (Try your best effort!) I hope the tool will only put in the required scripts in the future.

One can download my sample AJAX 196 AuthConfigProvider browser here. Note that we need to use a browser supporting AJAX (Firefox, Internet Explorer et al, not Mozilla 1.x) in order to run this example.

Friday Mar 16, 2007

In Java EE 5, one can implement JAXWS Web Services through servlets and Ejb endpoints (JSR 109). GlassFish supports message level security for Web Services. You don't need to write special client and server Java code in order to take advantages of the message level security. What you need to do is specific a corresponding message-level-security element in sun-ejb-jar.xml, sun-web.xml, and sun-application.xml. For instance,

  <webservice-endpoint>
    <port-component-name>PingEjb</port-component-name>
    <endpoint-address-uri>/PingEjbService/PingEjb</endpoint-address-uri>
    <message-security-binding auth-layer="SOAP" provider-id="XWS_ServerProvider">
      <message-security>
        <message/>
        <request-protection auth-source="sender"/>
        <response-protection auth-source="content"/>
      </message-security>
    </message-security-binding>
  </webservice-endpoint>

Or you can turn on the default in domain.xml for server side or sun-acc.xml for appclient.

This blog will highlight some troubleshootings for JAXWS message level security.

Read logs

  1. Look at client and server logs. The server log is located at $GLASSFISH_HOME/domains/your_domain/logs/server.log.
  2. If you want to see more SOAP level debug info, like corresponding SOAP messages, then you can turn on provider's debug.
    For server and embedded client, one can achieve this by navigating from admin console: Configuration > Security > Message Security > SOAP > Providers:
    • For server, choose the provider XWS_ServerProvider, change the debug property to true and save the configuration.
    • For embedded client, choose the provider XWS_ClientProvider, change the debug property to true and save the configuration.
    For appclient, one need to change the debug property to true for the provider XWS_ClientProvider, and log-service level to INFO.

Endpoint info mismatch

For message level security, one need to ensure that the same request-policy and response-policy are applied to both client and server. These info can be specified in sun-*.xml for a given application or domain.xml and sun-acc.xml for default provider configuration (if default is on). If you see com.sun.xml.wss.impl.PolicyViolationException: Expected Signature Element as per receiver requirements or there is no security processing in SOAP message in debug log, then most probably some of the info about endpoint in sun-*.xml is not correct. You may like to double check each port-component-name (defined in JSR 109) and endpoint-address-uri inside message-security-binding in sun-*.xml are correct.

Note:

  • According to JSR 181, we have the following:
    ValueDefault
    @WebService.nameSimple name of the Java class or interface
    @WebService.serviceNameSimple name of the Java class + "Service"

  • In GlassFish, the URL to access WebService and endpoint-address-uri in sun-*.xml are related as follows:
    Endpoint TypeWebService URL
    Servlethttp[s]://host:port/context-root/endpoint-address-uri
    Ejbhttp[s]://host:port/endpoint-address-uri

  • One can also find out the port-component-name by checking the generated webservices.xml in admin console as follows: Web Services > YOUR_WEB_SERVICES > Webservices.xml, and then correct the port-component-name, repackage and redeploy your application if necessary.

Wednesday Mar 14, 2007

In SJSAS 8.x, 9.0 and GlassFish v1, when one tries to access a password protected EJB or Web Service through appclient, it will prompt user name and password if this is not specified in command line or programmatically. By default the prompt will be a GUI dialog box. In remote environment, it may be desirable to have the prompt in text mode. One can achieve this through appclient as follows:

  appclient -client <location of the client jar> -textauth

And username and password will be prompted and user's response will be as follows:

  Enter Username:javaee
  Enter Password:javaee

Note that the password is echoed in the console. This is highly undesirable from security point of view.

In GlassFish v2 with JDK 6 environment, the password is no longer echoed in text password prompt. One can switch the JDK of GlassFish server by editing the AS_JAVA in config/asenv.conf for non-Windows systems and config/asenv.bat for Windows systems. If one reruns the above appclient command, then one will have

  Enter Username:javaee
  Enter Password:

Note that the password is no longer echoed in the console.

One may ask whether one can achieve this without modifying the JDK in whole installation. In GlassFish, one can package the appclient and install it in somewhere else. The command is as follows:

  $GLASSFISH_HOME/bin/package-appclient

This will generate a appclient.jar . Then one can copy this to the desired location and unjar the content. After that, one may need to update the following inside the unjar directories:

  • change appclient script to execution mode if necessary. The command in unix is: chmod u+x appclient.
  • update the content of asenv.conf or asenv.bat, sun-acc.xml, appclient as described in SJSAS package-appclient doc. For instance, if one want to use webservice in client, then one need to update AS_WEBSERVICE_LIB. In our case, one need to update AS_JAVA to point to a JDK 6 installation.
In this case, the GlassFish installation will still use the same JDK as before. Only the JDK of the new appclient has been updated.

Friday Aug 11, 2006

In the Java EE environment, roles are logical privileges which convey/represent permission to operate on some particular set of resources in an application. The Sun Java System Application Server environment consists of several realms, which each contain a complete database of users and groups that identify valid users of an application. When the roles are mapped to users, the users are effectively granted the permissions conveyed/represented by the privilege.

In Sun One Application Server 7.0, you can assign a role to all authenticated users in all realms at the same time, and applications can define authorization for that role. This addresses the following common scenario in the LDAP environment:

  • All authenticated users can access some subset of protected resources within the application. It doesn't matter who you are, only that your identity has been established.
  • The set of user groups is large or dynamic, but not specific to the application.

We wanted an ability to grant permission based on authentication independent of identity, in other words, we wanted a way to grant all authenticated identities to a role, or to define a role that would be understood to be mapped to all authenticated identities, and not to unauthenticated entities.

In Sun Java System Application Server 8.x and GlassFish v1, various RFEs and issues have been filed requesting support of the above scenario. Therefore, this scenario has been addressed in GlassFish v2. In GlassFish v2, the assign-groups property in CertificateRealm has been extended to FileRealm, LDAPRealm, SolarisRealm, and JDBCRealm. With this change, it is possible to configure all realms so that they assign one or more common group principals as a result of successful authentication, and such that every user is effectively made a member of the common groups. Given that this is the case, mapping one or more of the group principals to a role, either explicitly or by default, will allow the role to be used as an ANYONE role, a role that conveys/represents permission to operate on all resources which are accessible to any authenticated user. You can assign additional groups to all authenticated users in a specific realm without having to add those groups to all authenticated users in all realms. This gives us a finer control and allows us to resolve the issues with the above scenario as follows:

  • Set the assign-groups property for a given realm. All authenticated users of the given realm will assign additional groups as specified by the assign-groups property, for instance,
        assign-groups=agroup
  • Map additional groups to desired roles in Sun-specific deployment descriptors. For instance, in sun-applicaton.xml,
    <sun-application>
      <security-role-mapping>
        <role-name>javaee</role-name>
        <principal-name>javaee</principal-name>
      </security-role-mapping>
      <security-role-mapping>
        <role-name>ANYONE</role-name>
        <group-name>agroup</group-name>
      </security-role-mapping>
    </sun-application>

Thursday Jun 15, 2006

原文:JDBCRealm in Glassfish
作者:Shing Wai Chan
译者:Cheng Fang

JDBC realm 在近几个月来颇受瞩目。这篇网志总结了 JDBC realm 在GlassFish 实施中的演变,并解释其最新的实施运作。我要感谢 Jean-Baptiste 和 Richter 对此所作的贡献和评论。开源社区成员的参与也很有帮助。我欢迎大家的反馈和参与, 帮助我们更好地实现这一性能。

GlassFish 一直都支持 realm 插件。以下这篇文章描述了如何在 Sun Java System Application Server EE 8.0 中实现 Custom Realm:Authentication Using Custom Realms in Sun Java System Application Server。S1AS 7.x 也里有一个JDBC realm 的示例。Jean-Baptiste 正式提出要求这一性能, 并为 Glassfish 提供了一个以明文的方式实现的 JDBCRealm。Richter 也提供了另一个实 施方案,因为当时GlassFish 中的 JDBCRealm 与Tomcat 不兼容。

GlassFish 中最新的 JDBCRealm 是基于Jean-Baptiste 的实施,并包含了以下一些改动:

  • 增加 Message Digest 配置
  • 增加对 Digest 的 encoding 配置
  • 增加 charset 配置
  • 增加 realm 中数据库用户和密码配置
  • 解决为 EJB 获取连接的问题

在 GlassFish 中设计、实施 JDBCRealm 的过程中, 我们作出了以下一些决定:

  • 应该不应该支持明文密码? 我们决定支持明文密码,但不作为缺省存贮机制。在正常情况下, 密码不应该被明文地存放。
  • 是不是应该与 Tomcat 和 JBoss 兼容?  我们决定在实施中尽量做到兼容, 但不作为一个要求。

我们想听听你对这两个方面的意见。

GlassFish JDBCRealm

下表概括了 GlassFish JDBCRealm 中可配置的属性:

属性 是否必须 缺省 备注
datasource-jndi
   
user-table
   
user-name-column
  和 Tomcat 一样, 我们假设 user-table 表和 group-table 表有这一栏
password-column
   
group-table
   
group-name-column
   
jaas-context
  jdbcRealm
db-user
沿用连接池配置 如果连接池没有用户名或密码, 在这里定义db-user和db-password。这能够让我们指定一个安 全的资源,realm 可以通过用户名和密码来访问。
db-password
digest-algorithm
MD5 支持 JDK 中所有算法, 和 "none"
encoding
如果有 digest-algorithm, 就用 Hex。如果没有定义 digest, 则不用 encoding。
Hex, Base64, 不指定(没有 encoding)
charset
  针对 digest 的 charset 

GlassFish 中的一个安全性能就是,你可以在 JDBCRealm 中, 而不是在连接池中,指定用户名和密码。这样, 其它应用就无法查找 datasource,得到连接来浏览用户名和密码表。

怎么在JavaEE 应用中使用JDBCRealm ?

  1. 为 JDBCRealm 创建数据库表。
    例如, 如果您使用 Derby, 您会创建如以下示例的数据库表:
    create table usertable(userid varchar(10) not null, password varchar(32) not null, primary key(userid));
    create table grouptable(userid varchar(10) not null, groupid varchar(20) not null, primary key(userid));
    alter table grouptable add constraint FK_USERID foreign key(userid) references usertable(userid);
  2. 通过Admin 控制台创建 JDBCRealm。
    例如, 你可以创建一个有以下属性的 JDBCRealm:
    Property Name Property Value
    datasource-jndi jdbc/security
    user-table usertable
    user-name-column userid
    password-column password
    group-table grouptable
    group-name-column groupid
    jaas-context jdbcRealm
    jdbc/security 是一个可以访问以上表格的 datasource。
  3. 指定 JDBCRealm 是当前应用使用的 realm。这在配置描述器里指明: sun-application.xml (对于 EAR) 或, web.xml (对于 WAR) 或 sun-ejb-jar.xml (对于 EJB Jar) 。
  4. 确认 sun-*.xml 文件里有 <security-role-mapping>。 例如,
      <security-role-mapping>
        <role-name>Employee</role-name>
        <principal-name>Calvin</principal-name>
      </security-role-mapping>
  5. 在数据库中创建一名用户。没有为 JDBCRealm 创造用户的管理工具。以下是一个用来创建 JDBCRealm 用户程序例子:
    ...
    private static final String userSql = "insert into usertable values(?, ?)";
    private static final String groupSql = "insert into grouptable values(?, ?)";

    private static String hashPassword(String password) throws Exception {
    ...
    //compute digest
    ...
    //encode the bytes
    ...
    }

    public static void main(String args[]) throws Exception {
    ...
    Class.forName(driver);
    String hPassword = hashPassword(password);
    Connection conn = DriverManager.getConnection(
    jdbcUrl, dbUser, dbPassword);
    PreparedStatement userStmt = conn.prepareStatement(userSql);
    userStmt.setString(1, user); userStmt.setString(2, hPassword);
    userStmt.executeUpdate();
    userStmt.close();
    ...
    }
      可以在这 里找到这个例子。当运行这一程序时, 要确认 JDBC 驱动在 CLASSPATH 里,例如, $GLASSFISH_HOME/javadb/lib/derbyclient.jar

关于迁移

从 Tomcat 或者 JBoss 迁移到 GlassFish 时,应考虑到以下一些不同的地方:

  • 在 Tomcat 和 JBoss, 没有缺省值。这对应于 GlassFish 中的 digest-algorithm="none"。
  • 在GlassFish 和Tomcat 中, 如果有 digest 被定义,那么 encoding 缺省值就是 Hex。在 JBoss 中, 如果有 digest 被定义,那么 encoding 缺省值就是 Base64。

Thursday Jun 08, 2006

JDBC realm has a lot of attention in recent months. This blog summarizes the evolution of the JDBC realm implementation in GlassFish and explains how the latest implementation works. I would like to thank Jean-Baptiste, and Richter for their contributions and comments. The participation from the open source community definitely helps everyone. I encourage all of you to give feedback, participate, and help evolve this feature further.

GlassFish always had the capability for anyone to plug-in a realm. Implementing a custom realm in the Sun Java System Application Server EE 8.0 is described in the article Authentication Using Custom Realms in Sun Java System Application Server. In S1AS 7.x, there is a JDBC Realm bundled in sample. Jean-Baptiste formally filed an enhancement and provided a clear text version of JDBCRealm for GlassFish. Richter wrote another implementation because the GlassFish JDBCRealm at that time not compatible with Tomcat.

The latest GlassFish implemtation started with the Jean-Baptiste's implementation and includes the following modifications:

  • add message digest configuration
  • add encoding configuration for digest
  • add charset configuration
  • add database user and password configuration in realm
  • fix the issue with acquiring a connection for EJB

For the GlassFish implementation of the JDBCRealm, the following design descisions were made:

  • Should clear text passwords be supported? The decision was made to not to have clear text passwords as default storage mechanism. Under normal circumstances, passwords should not be stored as clear text.
  • Should this implementation be compatible with Tomcat and JBoss? The decision was made to attempt to implement this compatibility, but not require this compatibility.

I would appreciate hearing from you on both of these topics.

GlassFish JDBCRealm

The following table summarizes configurable properties for GlassFish JDBCRealm:

PropertiesMandatoryDefaultRemark
datasource-jndiY  
user-tableY  
user-name-columnY as in Tomcat, we assume that both user-table and group-table has this column
password-columnY  
group-tableY  
group-name-columnY  
jaas-contextY jdbcRealm
db-userNfrom connection pool configurationIf the connection pool doesn't have username or password, define the db-user and db-password here. This allows us to specify a secure resource that is accessible by an realm with user and password specified.
db-password
digest-algorithmNMD5support all algorithms in JDK, and also "none"
encodingNHex if there is a digest-algorithm,
no encoding if digest is not defined
Hex, Base64, not specified (no encoding)
charsetN charset for digest

In GlassFish, a security feature allows you to specify a username and password in the JDBCRealm instead of in the connection pool. By doing this, other applications cannot look up the datasource and get a connection to browse the user-name, password database tables.

How to use JDBCRealm in a JavaEE application?

  1. Create database tables for the JDBCRealm.
    For example, if you are using Derby, you would create database tables as shown in the following code example:
    create table usertable(userid varchar(10) not null, password varchar(32) not null, primary key(userid));
    create table grouptable(userid varchar(10) not null, groupid varchar(20) not null, primary key(userid));
    alter table grouptable add constraint FK_USERID foreign key(userid) references usertable(userid);
    	
  2. Create a JDBCRealm using the Admin Console.
    For instance, one can create a JDBCRealm with the following properties:
    Property NameProperty Value
    datasource-jndijdbc/security
    user-tableusertable
    user-name-columnuserid
    password-columnpassword
    group-tablegrouptable
    group-name-columngroupid
    jaas-contextjdbcRealm
    where jdbc/security is a datasource can access the tables above.
  3. Specify that the JDBCRealm is the realm to be used as the realm for the application. This is specified in the deployment descriptor: sun-application.xml (for EAR) or, web.xml (for WAR) or sun-ejb-jar.xml (for EJB JAR).
  4. Make sure that you have <security-role-mapping> in sun-*.xml. For instance,
      <security-role-mapping>
        <role-name>Employee</role-name>
        <principal-name>Calvin</principal-name>
      </security-role-mapping>
  5. Create a user in database. There is no administration tools for creating users for JDBCRealm. A snapshot of a program that can be used to create users in JDBCRealm is as follows:
        ...
        private static final String userSql = "insert into usertable values(?, ?)";
        private static final String groupSql = "insert into grouptable values(?, ?)";
    
        private static String hashPassword(String password) throws Exception {
            ...
            //compute digest
            ...
            //encode the bytes
    	...
        }
    
        public static void main(String args[]) throws Exception {
            ...
            Class.forName(driver);
            String hPassword = hashPassword(password);
            Connection conn = DriverManager.getConnection(
                jdbcUrl, dbUser, dbPassword);
            PreparedStatement userStmt = conn.prepareStatement(userSql);
            userStmt.setString(1, user); userStmt.setString(2, hPassword);
            userStmt.executeUpdate();
            userStmt.close();
            ...
        }
    
    The sample program can be found in here. When we run the program, please make sure that the JDBC driver is included in CLASSPATH, for instance, $GLASSFISH_HOME/javadb/lib/derbyclient.jar

Notes on Migration

Consider the following differnces when migrating applications from Tomcat and/or JBoss to GlassFish:

  • In Tomcat and JBoss, there is no default. This corresponds to digest-algorithm="none" in GlassFish.
  • In GlassFish and Tomcat, the default encoding is Hex if there is a digest defined. In JBoss, the default encoding is Base64 if there is a digest defined.

Friday May 12, 2006

As computer hardware is getting more and more powerful, there is a corresponding need to increase the encryption strength of the key in cryptographic operations. There are several ways in which this can be accomplished:
  • Increase the length of the encryption key. This may negatively impact performance.
  • Use a different encryption algorithm, for example, Elliptic Curve Cryptography (ECC). In next-generation key technology, RSA will be 2048 bits and ECC will be 224 bits. Note that these two type of keys have the same ecnryption strength.

In this blog, I will summarize the steps needed for using HTTPS with ECC with the following configuration:

The following discussion assumes that GlassFish is installed in c:\export\glassfish, JDK 6 is installed in c:\jdk6 and the NSS binaries are located in c:\nss\lib.
  • Configure your operation environment to run the GlassFish, JDK 6, and NSS.
    • For example in Windows, set the path variabled, as shown here:
        set path=c:\jdk6\bin;c:\nss\lib;c:\export\glassfish\bin;%path%
    • For example, in Unix ksh, export these environment variables:
        export PATH=/jdk6/bin:/export/glassfish/$PATH
        export LD_LIBRARY_PATH=/nss/lib:$LD_LIBRARY_PATH
  • Create a provider configuration for NSS in c:\ecc\nss.cfg as follows:
      name=NSS
      nssLibraryDirectory=c:\\nss\\lib
      nssDbMode=noDb
      attributes=compatibility
  • Add the NSS provider to the JDK 6 configuration by adding the following line in the file c:\jdk6\jre\lib\security\java.security :
      security.provider.10=sun.security.pkcs11.SunPKCS11 c:\\ecc\\nss.cfg
  • Create an ECC key in JKS keystore using keytool, where ${HOST} is hostname of your machine.
      c:
      cd \export\glassfish\domains\domain1\config
      keytool -genkeypair -alias myecc -keyalg EC -keysize 224 -keystore keystore.jks -storepass changeit -dname "CN=${HOST}, OU=ECC Test 224, O=GlassFish" -keypass changeit
  • Update the version of the JDK used by GlassFish by updating the value of AS_JAVA in the file c:\export\glassfish\config\asenv.bat.
  • Start the GlassFish server if necessary.
      asadmin start-domain domain1
  • Update the certificate nickname of the HTTP listenser http-listener-2 to myecc using the Admin Console, which can be accessed by entering the following URL in your browser: http://serverName:4848

  • Stop and then restart the GlassFish server in order for the changes to become effective
      asadmin stop-domain domain1
      asadmin start-domain domain1
  • To access the HTTPS with ECC, install the latest versions of web browsers, as only the latest versions have support for ECC. The latest versions can be found in here.

    If you try access https://serverName:8181 using your existing browser, you will see an error message like this:
      cannot communicate securely because they have no common encryption algorithms.

  • Configure the latest version of the browser to use an ECC algorithm, for example, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, by following these steps:
    • Open your web browser.
    • Enter the following URL in the browser: accessing about:config.
    • In this window, set Filter to security.
    • Select and double click ssl3.ecdh_ecdsa_aes_128_sha

Now, you can access https://serverName:8181, the browser will prompt for accepting the certificate and you can verify that this is the ECC certificate that you just created.

A preliminary benchmark of HTTPS with ECC in GlassFish on the Windows XP platform shows that the performance of ECC is double that of RSA in next generation-key technology.

More details on using JDK 6 with NSS can be found in Andreas's blog: Elliptic Curve Cryptography in Java.

Saturday Apr 08, 2006

Enterprise Java Bean provides a component based architecture for distributed business application. Security is very important in the enterprise environment. SSL/TLS provides security at the transport layer to meet the security requirement in an enterprise environment. In this blog, we discuss how to configure SSL for use with enterprise beans and how to access enterprise bean from a client.

Note

  • In the Java EE 5 SDK, Glassfish and the Sun Java System Application Server (SJSAS), the keystore password and key passwords are the same, and the keystore and truststore passwords are the same for a given domain.
  • The SJSAS EE uses NSS for keystore management. The SJSAS PE uses JKS keystores for keystore management. The application client containers, however, use JKS keystores for keystore management regardless of whether the Application Server is EE or PE.

Running Enterprise Beans over SSL

In SSL/TLS, there are two kinds of authentication: SSL server authentication and SSL mutual authentication. To specify SSL/TLS for an enterprise application, use the <transport-config> subelement of the corresponding <ejb> element in the runtime deployment descriptor, sun-ejb-jar.xml.

The two options are specified in slightly different ways, as shown in the following examples:

  • SSL: Server Authentication

    In this case, the client verifies the identity of the server by checking its certificate in the truststore. When using sever authentication, make sure that the truststore of the client trusts the certificate of the server. To do SSL server authentication, set the integrity element and confidentiality element to required. For instance,
    <sun-ejb-jar>
      <enterprise-beans>
        <ejb>
          <ejb-name>SSLTheConverter</ejb-name>
          <jndi-name>SSLconverter</jndi-name>
          <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>
            <sas-context>
              <caller-propagation>supported</caller-propagation>
            </sas-context>
          </ior-security-config>
        </ejb>
      </enterprise-beans>
    </sun-ejb-jar>

  • SSL Mutual authentication

    In this case, both the client and the server verify the identity of each other by checking certificates in mutual truststores. When using mutual authentication, make sure that the truststore of the client trusts the certificate of the server and the truststore of the server trusts the certificate of the client. To do SSL mutual authentication, set the integrity element, the confidentiality element, and the establish-trust-in-client to required. For instance,
    <sun-ejb-jar>
      <enterprise-beans>
        <ejb>
          <ejb-name>SSLTheConverter</ejb-name>
          <jndi-name>SSLconverter</jndi-name>
          <ior-security-config>
            <transport-config>
              <integrity>required</integrity>
              <confidentiality>required</confidentiality>

              <establish-trust-in-target>supported</establish-trust-in-target>
              <establish-trust-in-client>required</establish-trust-in-client>

            </transport-config>
            <sas-context>
              <caller-propagation>supported</caller-propagation>
            </sas-context>
          </ior-security-config>
        </ejb>
      </enterprise-beans>
    </sun-ejb-jar>

    Using SSL with the Applicaton Client Container

    To use SSL with the Application Client Container (ACC), you need to set VMARGS environment variable.
  • Set environment variable VMARGS in shell.

    For example, in ksh or bash shell the command to set this environment variable would be:
    export VMARGS=" -Djavax.net.ssl.keyStore=${keystore.db.file} -Djavax.net.ssl.trustStore=${truststore.db.file} -Djavax.net.ssl.keyStorePass word=${ssl.password} -Djavax.net.ssl.trustStorePassword=${ssl.password}"

  • Set the env element in the ant script. For instance,
    <target name="runclient">
      <exec executable="${S1AS_HOME}/bin/appclient">
        <env key="VMARGS" value=" -Djavax.net.ssl.keyStore=${keystore.db.file} -Djavax.net.ssl.trustStore=${truststore.db.file} -Djavax.net.ssl.keyStorePasword=${ssl.password} -Djavax.net.ssl.trustStorePassword=${ssl.password}"/>
        <arg value="-client"/>
        <arg value="${appClient.jar}"/>
      </exec>
    </target>

    Using SSL with Standalone Client

    When the application client, the enterprise bean is looked up using the ejb-ref-name element, as shown in the following example sun-application-client.xml:
    <sun-application-client>
      <ejb-ref>
      <ejb-ref-name>ejb/SSLSimpleConverter</ejb-ref-name>
      <jndi-name>SSLconverter</jndi-name>
      </ejb-ref>
    </sun-application-client>

    When using a standalone client, however, we use JNDI name for the lookup. So, in the standalone client class, we have:
        context = new InitialContext();
        obj = context.lookup("SSLConverter");

    To run the standalone client, make sure your classpath contains the following:

    • appserv-rt.jar, this will have an implementation ORB with the implementation of CSIv2
    • j2ee.jar in SJSAS 8.x or javaee.jar in Glassfish
    • the interfaces class of the corresponding EJBs and other library classes needed

    The following ant target provides an example of how to configure an ant target for running over SSL:
    <target name="run-standalone-client">
      <java classname="${test.client}"
          classpath="${test.classpath} failonerror="true" fork="true">
        <jvmarg value="-Dorg.omg.CORBA.ORBInitialHost=${orb.host}"/>
        <jvmarg value="-Dorg.omg.CORBA.ORBInitialPort=${orb.port}"/>
        <jvmarg value="-Djavax.net.ssl.keyStore=${keystore.db.file}"/>
        <jvmarg value="-Djavax.net.ssl.keyStorePassword=${ssl.password}"/>
        <jvmarg value="-Djavax.net.ssl.trustStore=${truststore.db.file}"/>
        <jvmarg value="-Djavax.net.ssl.trustStorePassword=${ssl.password}"/>
      </java>
    </target>

    Debugging SSL Communication

    To enable debug messages for SSL communication, pass the jvm option -Djavax.net.debug=all, which will show all the information during SSL communications.
  • Monday Jan 23, 2006

    In Java EE 5, there are many new and exciting features. For example, developers can specify annotations in Java files instead of putting metadata in deployment descriptors. In some cases, applications can be completely free of deployment descriptors. This simplifies the development of Jave EE applications. This blog describes two common troubleshooting scenarios for deployment in GlassFish.

    1. Runtime error due to annotations not correctly processed (if at all) during deployment.
      In this case, even though one may go through deployment, there will be a runtime error. For instance, suppose you have the following resource injection
          private @Resource(name="jdbc/__default") DataSource ds;
      then, you will have a NullPointerException when you try to access the ds. Verify that the annotation is not processed by doing the following:

      • turn on deployment log to FINE in the domain during deployment time
        In this case, you will see a FINE message in server.log as follows:

            Annotation is not processed for this archive.

      Solution:

      • Make sure that standard deployment descriptor files, such as ejb-jar.xml, web.xml, application-client.xml refer to the correct version of the XML schemas in the ear/war/jar files before deployment as the Java EE platform spec requires that annotations are only processed if the deployment descriptor uses the latest schema.
        Deployment DescriptorVersion of XSD
        ejb-jar.xml ejb-jar_3_0.xsd
        web.xml web-app_2_5.xsd
        application-client.xml application-client_5.xsd

      • If the descriptors mentioned above refer to the correct schema versions, then please make sure that the full attribute is "false" or not specified there as the Java EE platform spec indicates that annotations are only processed if the deployment descriptors using the latest schema have the full attribute either specified as "false" or not specified. For instance,

        <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" full="false" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">

        <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">


      • If the above are correct and the annotation in application client is still not processed, then please make sure that the application client jar file has a MANIFEST.MF containing a Main-Class entry pointing to the fully qualified name of the app client main class. Note that, in general, one can specify the application client main class as an appclient command line argument. But in cases with annotation, one needs to have MANIFEST.MF with Main-Class entry.

    2. A library jar file is incorrectly treated as app client jar in a deployment descriptor free application. This is due to the fact that the given library jar file has a Main-Class entry in MANIFEST.MF file. Note that even though the application may be able to deploy, it may not be as you desired. For instance, if the given ear does not have an app client jar, deployment may interpret a library jar as an app client jar. One can verify this in admin GUI.

      Solution:

      • Include application.xml and defined each module explicitly. In this case, the library jar is not mentioned in application.xml.
        For instance,
        <?xml version="1.0" encoding="UTF-8"?>
        <application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd>
          <display-name>deployment-ejb30-ear-securityApp</display-name>
          <module>
            <ejb>deployment-ejb30-ear-security-ejb.jar</ejb>
          </module>
          <module>
            <web>
              <web-uri>deployment-ejb30-ear-security-web.war</web-uri>
              <context-root>deployment-ejb30-ear-security</context-root>
            </web>
            </module>
          <module>
            <java>deployment-ejb30-ear-security-client.jar</java>
          </module>
        </application>
      • Or remove the Main-Class entry in MANIFEST.MF if it is unnecessary for the library function properly.

    Friday Dec 16, 2005

    This blog describes the steps needed to use Verisign certificates in GlassFish which can be downloaded from http://glassfish.dev.java.net/public/downloadsindex.html. These steps will also work with the SJSAS 8.x products. You will need to go to the Verisign website to get a certificate if you don't already have one. In the following, we will outline steps on how to use Verisign certificate in Sun Java System Application Server (SJSAS) 8.x PE and Glassfish.

    Steps On Using Verisign Certificate

    1. Generate a private key in keystore resided in domains/your_domain/config/keystore.jks.
      keytool -genkey -alias myservkey -keysize 1024 -keyalg RSA -keystore keystore.jks -dname "CN=test.glassfish.com,OU=Testing,O=Java,L=Santa Clara,S=California,C=US"
      Note that
      • there cannot be a space in the CN name. Verisign can only accept RSA at this time, DSA algorithm is not supported.
      • the password for keystore and the key must be the same
      • the password for keystore.jks in default installation is changeit
    2. Create a certificate request.
      keytool -certreq -alias myservkey -sigalg SHA1WithRSA -keystore keystore.jks -file myservkey.csr
    3. Backup your keystore. This is very important as no one can recover the private key if it is lost.
    4. Go to Verisign website http://www.verisign.com to process the certificate.
    5. Once the certificate is processed, Verisign will send an email to you with certificate inside the email. Please cut and paste the certificate and save it to a file, say, myservkeyveri.cer. Please make sure there is no extra whitespace in the file.
    6. Make sure root CA certificate is in
      • domains/your_domain/config/keystore.jks
      • domains/your_domain/config/cacerts.jks
      • in your browser if it is used as SSL client.
      If you are using a Verisign certificate, then root CA has already been there. But if you are using Verisign testing certificate, then you need to import the Verisign testing root CA certificate which can be found in hyperlink of email from Verisign.

      The commands for importing CA root certificate is as follows:
      keytool -import -v -trustcacerts -alias verisigntestroot -file vertestrootca.cer -keystore keystore.jks
      keytool -import -v -trustcacerts -alias verisigntestroot -file vertestrootca.cer -keystore cacerts.jks
    7. Import the certificate to keystore.
      keytool -import -v -alias myservkey -file myservkeyveri.cer -keystore keystore.jks
    8. Verify that the certificate is imported correctly.
      keytool -list -v -alias myservkey -keystore keystore.jks
    9. Update the certificate alias from admin GUI:
      For https certificate alias:
      Configuration > HTTP Service > HTTP Listeners > http-listener-2
          Input certificate alias name in Certificate NickName text box.
          Enable SSL3, TLS, cipher suites if necessary

      For iiop certificate alias:
      Configuration > IIOP Listeners > SSL / SSL_MUTUALAUTH
          Input certificate alias name in Certificate NickName text box.
          Enable SSL3, TLS, cipher suites if necessary

    10. Restart the server by using asadmin.
    11. Verify the server is using the certificate. If you are setting https as above, then you can use browser to access https://your_host:8181 and it will prompt to you to accept the certificate you have just imported.

    Troubleshooting

    1. keytool -import -keystore keystore.jks -alias myservkey -file myservkeyveri.cer
          Enter keystore password:
          keytool error: java.security.cert.CertificateException: java.io.EOFException
      Please double check there is no extra whitespace in the file.
    2. keytool -import -v -alias myservkey -keystore keystore.jks -file myservkeyveri.cer
          Enter keystore password:
          keytool error: java.lang.Exception: Public keys in reply and keystore don't match
      The certificate reply does not match with the key in your keystore. You may need to check whether alias name is correct or get backup keystore having the private key.

    Remark

    The same procedure work for SJSAS EE by using certutil instead of keytool:
    • use certutil -S to generate a key
    • use certutil -R to import a certificate
    • use certutil -A to import a certificate
    • use certutil -L to list a certificate
    More information on how to use certutil in SJSAS can be found in Key Management and PKCS#11 Tokens in Sun Java System Application Server 8.1, May 19, 2005.