Securing REST web services is a very debated topic on the Internet. Because REST represents an architecture, and not a protocol - like SOAP -, there aren’t any specifications dealing with security, leaving this aspect as a design decision for the software engineers / developers. Still, if you search the web to find out what are the approaches, you’ll see that most of the results suggest you use basic authentication over HTTPS.
The basic authentication is a trivial way of authenticating HTTP requests directly by the web server, without any added effort for the developer. Since REST isn’t very pretentious (it uses the well known HTTP methods for accessing resources), leaving the authentication to the web server is a natural thing to do. Still, this doesn’t mean that your REST API is secure. You merely separate users that should have access to your API from users that should be denied access. Enabling HTTPS on the server is the next step that needs to be followed, so that all the requests are secured. This avoids the classical man-in-the-middle attack and also assures that the credentials sent by the users aren’t visible to the whole world (although they are BASE64 encoded by the basic authentication mechanism, decoding them is a child’s play).
A practical example
For the next paragraphs, I will be very specific (the title should have already told you this). To add something more, let’s assume you use Maven (because you’re a real developer) and Jetty (only for testing - I assume that for production you use a proper server, like Tomcat). Enabling HTTPS on any other server shouldn’t be much different.
To enable HTTPS and basic user authentication on Jetty by using Maven, you would have to use an additional plug-in for generating keystores, unless you already have a keystore that you would like to use, in which case you should not keep it in the
target folder of your project. The following section of
pom.xml should do the trick:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
The highlighted lines indicate the user realm. This is a file which describes to the server who are your users and what roles are they assigned. The specified file contains records of this form:
Now you must configure your web application to accept HTTPS encrypted content. This is done in the web.xml file, by adding the following lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
REST web services and Apache CXF
So, everything is set up and working. Well, almost. If your REST web services also include some client code, you might encounter an exception with the following message:
The exception is thrown because the certificate your server uses is not from a known Certificate Authority. If you have studied the POM example, you’d see that the certificate is generated at every execution of the
install goal. Moreover, the certificate is self-signed. From here we have two solutions:
try to create a single key store and save it in the
srcfolder, configuring the server to use the file from this location; then start the server and use the program written by Andreas Sterbenz which you can find here; grab the certificate and move the resulted file into the security folder of your JRE (on Linux this should be
/usr/lib/jvm/java-6-sun/jre/lib/security/); although this will work okay on your machine, if your project should be accessed by multiple developers, each member of the team has to add that certificate to his/hers JVM (which is not quite nice);
create an alternative
TrustStoreused only by your application; this is by far the most elegant solution, which adds some more code to the application but doesn’t force your team members to add dummy certificates to their JVM.
The class implementing the
X509TrustManager is trivial:
1 2 3 4 5 6 7 8 9 10 11
To make all your Apache CXF REST clients use the new trust store, it is necessary to create a static method in an utility class that sets everything up for the clients:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The properties file you see loaded in the previous code output contains the username and password for authentication, but it’s different from the realm. This is because the realm would be harder to parse, although the information is still plain text. Although it might seem redundant to have the username and password in two files, the realm can actually hold users belonging to different roles - therefore the parsing effort.
PropertiesLoader class is not standard, but again it’s something trivial:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Having done all this, your clients should now work as expected. Just remember that the
FakeTrustStore is to be used only for testing purposes.