Sunday, 19 October 2014

Glassfish Security Realms

The JDBCRealm

In the Glassfish Administration Console, go to Configurations -> server-config -> Security -> Realms -> and select "New".

We're going to choose com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm.

The jaas.context name of the new realm is "jdbcRealm".

A jdbcRealm needs both a user table and a group table. The group table should store both userids as well as groupids. In other words,
  • the group table doesn't only contain groups, and
  • has a composite primary key, consisting of userid and groupid.

Database Schema

The user table is called "mm_admin" in my case, and the groups table is called "mm_admin_mm_groups".

I have created the "mm_groups" table to store extra information for groups, but that table is ignored by the jdbcRealm.

Some serious disadvantages of the jdbcRealm are:
  • groups are cached, which means if a user changes groups, the Glassfish Server needs to be rebooted.
  • flexibility is about zero, for instance if I have an expiration date attached to my usertable, I'm out of luck.
All this causes me to look elsewhere, namely towards the flexibleJDBCRealm5

The flexibleJDBCRealm

The great advantage of the flexibleJDBCRealm is that you can add SQL queries that are run to retrieve passwords and groups.

Instructions

Well, according to instructions found here6, you have to:
  1. download the flexiblejdbcrealm-deploy-1.2-all.jar
  2. put it into glassfish/domains/domain1/lib directory
  3. change glassfish/domains/domain1/config/login.conf to add
    flexibleJdbcRealm {
    org.wamblee.glassfish.auth.FlexibleJdbcLoginModule required;
    };
  4. reboot the glassfish
  5. In the Glassfish Administration Console, go to Configurations -> server-config -> Security -> Realms -> and select "New"
  6. enter the class name org.wamblee.glassfish.auth.FlexibleJdbcRealm
  7. set the properties, for example like in the image above.

Properties

The properties that can be entered could use a little more explaining compared to what is available at [6].
password.digest
uses MessageDigest(String algorithm). Possible values are "MD5", "SHA-1" and "SHA-256".
password.encoding
the encoding, I find HEX to be the most useful. Possibile values are "TEXT", "HEX" and "BASE64".
sql.groups
select groupid from mm_admin_mm_groups where name in (?)
sql.password
select passwd from mm_admin where name in (?) and validuntil > now()
jaas.context
flexibleJdbcRealm
datasource.jndi
of course, the connection string to the database
NOTE: he's complaining about setting properties in the realm with a = in them. So I had to go back to an "in (?)" construction for the SQL queries.

Logging

In glassfish/domains/domain1/config/logging.properties, add: org.wamblee.level=FINEST.

Application Configuration

My web.xml would look like thusly:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <security-constraint>
        <display-name>Administration</display-name>
        <web-resource-collection>
            <web-resource-name>Administration REST Resources</web-resource-name>
            <description/>
            <url-pattern>/resources/administration/*</url-pattern>
            <url-pattern>/administration/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>deputy</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>deputyRealm</realm-name>
    </login-config>
    <security-role>
        <description/>
        <role-name>deputy</role-name>
    </security-role>
</web-app>
My glassfish-web.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app 
    PUBLIC 
    "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" 
    "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">

<glassfish-web-app error-url="">
  <security-role-mapping>
    <role-name>deputy</role-name>
    <group-name>deputy</group-name>
  </security-role-mapping>
  <class-loader delegate="true"/>
  <jsp-config>
    <property name="keepgenerated" value="true">
      <description>Keep a copy of the generated servlet class' java code.</description>
    </property>
  </jsp-config>
</glassfish-web-app>
In this file you can create a mapping between security roles and groups.

Declarative Security

An example of declarative security using Annotations:
@DeclareRoles("deputy")
@RolesAllowed("deputy")
@Stateless
@Path("/administration/worldattributes")
public class WorldattributesBean extends AbstractFacade<Worldattribute>
{
This means the role definition in the web.xml can be removed.

In the example above, the security role is applied to the entire Bean, so for each method in the bean, instead of on each method that requires the role.

Programmatic Security

Unfortunately, some fine-grained security can only be done with programmatic means, for example determining if a person who has authenticated themselves owns a certain object that needs mutated upon. In my example, this info in a Rest service can be obtained through a SecurityContext:
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.Context;
...
@POST
@Override
@Consumes(
{
     "application/xml""application/json"
})
public void create(Worldattribute entity, @Context SecurityContext sc)
{
  itsLog.info("create");
  final String name = sc.getUserPrincipal().getName();

References

[1] Oracle - Security in the Java EE Platform
http://docs.oracle.com/javaee/7/tutorial/doc/security-intro.htm
[2] The Java EE 7 Tutorial
Release 7 for Java EE Platform
[3] Oracle - Using the JDBC Realm for User Authentication
http://docs.oracle.com/javaee/6/tutorial/doc/glxgo.html
[4] Understanding Web Security
http://java.dzone.com/articles/understanding-web-security
[5] FlexibleJDBCRealm
http://flexiblejdbcrealm.wamblee.org/site/
[6] Installation instructions
http://flexiblejdbcrealm.wamblee.org/site/documentation/snapshot/installation.html

Sunday, 12 October 2014

REST and Error Messages

WebApplicationException

In Java REST you can throw a WebApplicationException, which indicates that something went wrong. You can add the HTTP Status to the exception, to indicate what went wrong.
throw new WebApplicationException(Response.Status.BAD_REQUEST);
But that amount of information is in most cases too little. Sure, a HTTP Status of 404 (Not Found) is quite clear, but you'd like some more information.

Luckily, I found out that we can add an entity in the Response and add the Response to the WebApplicationException.

In fact, it is the most convenient to just create your own subclass of WebApplicationException to handle this automatically.

Your own WebApplicationException


An Error Entity

The entity that gets translated into JSON and passed over the line, in my case called ErrorDetails, can provide all the information you need.

The getResponse method is the one that creates the Response, which is used to provide the HTTP Status code and the error payload for the WebApplicationException.

The json generated looks like:

    timestamp="2014-09-21T21:34:01.831", 
    errormessage="sdsgsdgsgd was not found.", 
    stacktrace=””,
    user="sdsgsdgsgd"
}

JQuery

It just took a little effort to retrieve the ErrorDetail object from the Xqhr object in the JQuery Ajax call. This should be done during error processing, as shown in the JQuery Ajax call below.

The webError in the code above is a function to parse the JSON containing ErrorDetails object, provided below.

It parses the jqXHR.responseText, to be precise. And if a stacktrace is provided, the details are put into a HTML tag with id "warning". An 'alert' is always provided.

References

Whatever can go wrong … Error Handling and RESTful Services
http://djna.wordpress.com/2009/12/07/whatever-can-go-wrong-error-handling-and-restful-services/
RESTful API Design: what about errors?
https://blog.apigee.com/detail/restful_api_design_what_about_errors
How to get the jQuery $.ajax error response text?
http://stackoverflow.com/questions/1637019/how-to-get-the-jquery-ajax-error-response-text
Use jQuery to catch and display ASP.NET AJAX service errors
http://encosia.com/use-jquery-to-catch-and-display-aspnet-ajax-service-errors/