Friday, 31 October 2014

getAsModifableSet()

At work we have taken great care to limit access to a Set of values, as elements of the set have constraints between each other, that need to be sustained.

So any call to retrieve a set, is always done using Collections.unmodifiableSet.

public Set<T> getCycles() 
{
  return Collections.unmodifiableSet(cycles);
}

I would have been much more at ease, if we had also decided to make the elements of the set Immutable Objects, but alas, this is the status quo.

As it is right now, it's possible to change the attributes of the individual elements, and so break the constraints between them.

Surprise

Imagine the surprise of my colleague, when, out of nowhere, he found the following method:
public abstract SortedSet<T> getAsModifableSet();

The typo in the name is actually in the code, I swear! My grasp of the intricacies of spelling is beyond reproach.

And it returns a very implementation-specific Set as well.

And it's public too.

I'm sure there are always good reasons for these things, but sometimes I'd like to run my head into a wall.

Sunday, 26 October 2014

Covariant return type

“In object-oriented programming, a covariant return type of a method is one that can be replaced by a "narrower" type when the method is overridden in a subclass.”

Since JDK 5.0 it is possible to provide covariant return types in methods of subclasses.[2] Before this release, the Java programming language was invariant with regard to method return types.

Unfortunately, covariance is not possible with method parameters. If you wish to use that, reference [1] has a good explanation of how to do this using Generics.

Example

public abstract class Animal
{
public abstract Food eats();
}
public abstract class Food{}
public class Grass extends Food
{
public Grass() {}
@Override
public String toString()
{
return "grass";
}
}
public class Meat extends Food
{
public Meat() {}
@Override
public String toString()
{
return "meat";
}
}
public class Cow extends Animal
{
@Override
public Grass eats()
{
return new Grass();
}
@Override
public String toString()
{
return "cow";
}
}
public class Lion extends Animal
{
@Override
public Meat eats()
{
return new Meat();
}
@Override
public String toString()
{
return "lion";
}
}
view raw covariant.java hosted with ❤ by GitHub

Scala

In Scala all three are possible, contravariant, covariant and invariant for both method parameters as well as method return types. It is used fairly frequently.

For more information, the blog in [3] has some excellent explanation.

References

[1] Covariant Parameter Types
https://www.java-tips.org/java-se-tips-100019/24-java-lang/482-covariant-parameter-types.html
[2] Wikipedia - Covariant return type
http://en.wikipedia.org/wiki/Covariant_return_type
[3] Atlassian Blogs - Covariance and Contravariance in Scala
http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/

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 "PLAIN", "MD2", "MD5", "SHA-1", "SHA-256", "SHA-384" and SHA-512.
password.encoding
the encoding, I find HEX to be the most useful. Possibile values are "TEXT", "HEX" and "BASE64". A variation of "HEX" is "HEX:<digits>", for example "HEX:40". This padds the beginning of the encoding with zeros to reach the length required. For example MySQL itself always creates passwords using the SHA() function to 40 hex digits also padding the beginning with zeros.
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();

FAQ

I get WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: No LoginModules configured for flexibleJdbcRealm?
You forgot to add the entry to the login.conf as specified above.

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

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
/**
*
* @author mr.bear
*/
public class MudWebException extends WebApplicationException
{
/**
* Create a new MudWebException.
*
* @param name the name of the player.
* @param message the message to send to the player.
* @param status the HTTP status code.
*/
public MudWebException(String name, String message, Response.Status status)
{
super(message, (new ErrorDetails(name, message)).getResponse(status));
}
/**
* Create a new MudWebException.
*
* @param name the name of the player.
* @param message the message to send to the player.
* @param status the HTTP status code.
* @param errormessage the error message to log in GlassFish (which can provide additional information too sensitive for the user).
*/
public MudWebException(String name, String message, String errormessage, Response.Status status)
{
super(errormessage, (new ErrorDetails(name, message)).getResponse(status));
}
/**
* Create a new MudWebException caused by a different exception.
*
* @param name the name of the player.
* @param message the message to send to the player.
* @param status the HTTP status code.
* @param e the underlying exception that was thrown.
*/
public MudWebException(String name, String message, Throwable e, Response.Status status)
{
super(e, (new ErrorDetails(name, message, e)).getResponse(status));
}
/**
* Create a new MudWebException caused by a different exception.
*
* @param name the name of the player.
* @param status the HTTP status code.
* @param e the underlying exception that was thrown.
*/
public MudWebException(String name, Throwable e, Response.Status status)
{
super(e, (new ErrorDetails(name, e)).getResponse(status));
}
/**
* Create a new MudWebException caused by a different exception.
*
* @param status the HTTP status code.
* @param e the underlying exception that was thrown.
*/
public MudWebException(Throwable e, Response.Status status)
{
super(e, (new ErrorDetails(e)).getResponse(status));
}
}

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.
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Object that is sent to the client as a json string, upon throwing
* a MudWebException.
*
* @see MudWebException
* @author mr.bear
*/
@XmlRootElement
public class ErrorDetails
{
public Date timestamp;
public String errormessage;
public String stacktrace;
public String user;
public ErrorDetails()
{
// required for REST
}
ErrorDetails(String errormessage)
{
this.timestamp = new Date();
this.errormessage = errormessage;
}
ErrorDetails(String user, String errormessage)
{
this(errormessage);
this.user = user;
}
ErrorDetails(Throwable t)
{
this.timestamp = new Date();
this.errormessage = t.getMessage();
this.stacktrace = stackTraceToString(t);
}
ErrorDetails(String user, Throwable t)
{
this(t);
this.user = user;
}
ErrorDetails(String user, String message, Throwable t)
{
this(t);
this.user = user;
this.errormessage = message;
}
private String stackTraceToString(Throwable e)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
public Response getResponse(Response.Status status)
{
return Response.status(status).entity(this).build();
}
}

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.
$.ajax({
type: 'POST',
url: some_url // Which url should be handle the ajax request.
cache: false,
success: (function(data) {processor(data); }),
error: webError,
complete: (function() { if (window.console) console.log("complete"); }),
dataType: 'json', //define the type of data that is going to get back from the server
contentType: 'text/plain; charset=utf-8',
data: command
}); // end of ajax
view raw ajaxcalls.js hosted with ❤ by GitHub

The webError in the code above is a function to parse the JSON containing ErrorDetails object, provided below.
function webError(jqXHR, textStatus, errorThrown)
{
if (window.console)
{
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}
try
{
var errorDetails = JSON.parse(jqXHR.responseText);
if (window.console) console.log(errorDetails);
} catch(e)
{
alert("An error occurred.");
if (window.console) console.log(e);
return;
}
if (errorDetails.stacktrace !== undefined)
{
var buffer = "Timestamp: " + errorDetails.timestamp + "<br/>";
buffer += "Errormessage: " + errorDetails.errormessage + "<br/>";
buffer += "Stacktrace: " + errorDetails.stacktrace + "<br/>";
buffer += "User: " + errorDetails.user + "<br/>";
buffer += "Browser CodeName: " + navigator.appCodeName + "<br/>";
buffer += "Browser Name: " + navigator.appName + "<br/>";
buffer += "Browser Version: " + navigator.appVersion + "<br/>";
buffer += "Cookies Enabled: " + navigator.cookieEnabled + "<br/>";
buffer += "Platform: " + navigator.platform + "<br/>";
buffer += "User-agent header: " + navigator.userAgent + "<br/>";
var $ = Karchan.$;
$("#warning").html(buffer);
}
alert(errorDetails.errormessage);
}
view raw weberror.js hosted with ❤ by GitHub

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/

Sunday, 5 October 2014

Getting the Stacktrace

Found this snippet to get the stacktrace as a printable String on StackOverflow[1].
public String stackTraceToString(Throwable e)
{
StringBuilder sb = new StringBuilder();
for (StackTraceElement element : e.getStackTrace())
{
sb.append(element.toString());
sb.append("\n");
}
return sb.toString();
}
view raw StackTrace.java hosted with ❤ by GitHub
However, this only provides the stacktrace of the exception, not the possible underlying exception as well.
For that, you should look at:
public String stackTraceToString(Throwable e)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
Of course, if you do not wish to reinvent the wheel, there is always org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable).

Just thought I'd write this down here, I always forget how to do it.

References

[1] How can I convert a stack trace to a string?
http://stackoverflow.com/questions/1149703/how-can-i-convert-a-stack-trace-to-a-string