This blog post compares Java EE Security with Apache Shiro and Spring Security based on self-defined categories. It’s aimed at readers who want to gain a rather rough idea which framework to pick for securing their application. Hence, this post won’t go deep into details. In order to provide some context, we’ll take a brief look at the test environment. Then follows the actual comparison. The self-defined categories are Documentation, Ease of Use, Community Support and Differentiating Features. Our findings are wrapped up in the conclusion.
Java EE Security API
Java EE applications usually consist of multiple components. A container holds these components. Java EE’s security model specifies that the container must provide or support certain security features. You can implement these features in two ways: declarative and programmatic.
Declarative: the developer specifies security requirements in the deployment descriptor and / or in code using annotations. The cool thing about annotations is that you can place them on your classes and / or methods instead of writing lengthy XML code.
Programmatic: offers the ability to make security related decisions based on the security context. “The Java EE Tutorial, Release 7” documentation recommends this approach if the expressiveness of annotations and deployment descriptors is not enough. An example would be making a resource accessible only during a certain time of day.
Both approaches are based on the Java Authentication and Authorization Service (JAAS) API.
The two main traits of Apache Shiro (“shiro” = jap. “castle”) are it’s simplicity and container independency. It’s core features are authentication, authorization, cryptography and session management.
Authentication is simple and intuitive by design. The process is subject-based and is performed by the developer using only a few method calls. Error diagnosis is facilitated by a rich exception hierarchy. Remember- Me functionality is included per se. Pluggable DAO’s can be used to implement realms and it’s possible to login a subject into multiple realms while maintaining a uniform view of it.
Authorization is also subject-based. Access rights are determined by the subjects roles and permissions. To start implementing permissions right away, one can use Shiro’s home made Wildcard Permission Syntax. For improved user experience and performance different caching solutions are supported.
Cryptography features are centered around simplicity. Shiro’s main goal here is to enable easy use of the Java Cryptography Extension. Since Shiro’s API is interface-driven and POJO-based, crypto-components can be easily configured using any JavaBeans compatible format.
Session Management with Shiro is possible even for non-web-based applications. Since the session objects are also POJO’s, they can be persisted on any kind of storage. Some of the more popular caching solutions can be used here as well.
Additionally, Shiro offers web-specific features. By enabling Shiro for your application through web.xml you can secure any URL and can also specify filter chains for each of them.
Like with the former two frameworks, Spring Security’s functionality is centered around authentication and authorization. It can be used with a Spring-less application as well as with a Spring-based one. This is mainly because Spring Security is, like Apache Shiro, container independent.
Spring Security had it’s beginnings in the late year of 2003 as a project called “The Acegi Security System for Spring”, a simple implementation at the time, which was not initially published. As more members of the Spring community asked for security features, they were provided with the aforementioned project. Early 2004 around 20 people were using the project. More and more joined and eventually a SourceForge project was created in march 2004. In may 2006 Acegi became an official Spring subproject, in 2007 it became part of the Spring Portfolio and was renamed “Spring Security”.
The frameworks were tested on a simple web-application consisting of a REST API and an index.html (also: login/logout/error.html) developed in Eclipse Neon for Java EE with WildFly 10.1.0.Final as the application server and PostgreSQL 9.6 for persistence.
The configuration of the frameworks was done in a declarative style whenever possible.
Please be aware that this is a relative comparison between the three frameworks.
The Java EE Security documentation is definitely the most basic one, as it not only explains how to use the security features but also takes it’s time (and space, it’s a lengthy read) to explain basic application security concepts. The fact that most other frameworks follow the security model layed out in the documentation makes it worthwhile to read, especially for beginners, even if you don’t plan on actually using the API. If you want to get started quick though, you might want to look for something more concise.
Spring Security’s documentation is really comprehensive. You can do a quick start and just keep on reading, if you want to learn more. Aside from some basic application security terms, it covers everything Spring Security can do. Or at least you are likely to feel like it, because when you read about a certain component, five (or so) new, relevant components might be mentioned. So it may leave you feeling a bit overwhelmed.
Compared to the other two, Apache Shiro’s documentation is somewhere in between. It does explain some basic terms and definitions and most of how Shiro itself works or what can be done with it. However, notice it is said “most”, not “all”, as you might come across some empty “TODO” sections.
Ease of Use
For a very basic configuration using a declarative style, all three are similarly easy, with Shiro being somewhat ahead and Java EE Security lacking somewhat behind, leaving Spring Security somewhere in the middle.
Apache Shiro Example
What’s really comfortable about Shiro’s declarative style of configuration is how slick (it even looks good) and easy it is. You write your configuration in a simple INI file. XML is only used to enable Shiro itself.
Here is what your shiro.ini could look like:
# login / logout configuration | authc = shiro standard FormAuthenticationFilter
authc.loginUrl = /login.html # specifying which URL to redirect to, when Shiro attempts to authenticate a user via authc
authc.successUrl = /index.html # the redirect-URL after a successful login
logout.redirectUrl = /logout.html # the redirect-URL after a successful logout
# define some test users
jan = passwort, employer # format: username = password[, role1[, role2[, roleN]]]
naj = passwort, employee
ajn = passwort
# define permissions for roles
employer = * # granted all permissions
employee = shop:browse:* # granted permission to browse the shop and do any related action
# protect urls
/login.html = authc # this step is necessary to register /login.html as the loginUrl of the authc filter
/index.html = authc # catch requests to /index.html and let the authc filter process them
/ = authc # same as above
# specify logout url
/logout = logout # catch requests to /logout and let the logout filter process them
# REST urls | noSessionCreation is used to avoid creation of sessions | authcBasic = shiro's standard BasicHttpAuthenticationFilter
/rest/shop/browse/** = noSessionCreation, authcBasic, perms["shop:browse:*"] # the perms filter additionally checks the subject for the specified permissions
/rest/shop/add = noSessionCreation, authcBasic, roles[employer] # the roles filter checks the subject for the specified roles
/rest/shop/delete/* = noSessionCreation, authcBasic, roles[employer]
Java EE Security Example
Configuration of Java EE Security via web.xml is somewhat tiring in comparison. The biggest disadvantage, however, is the fact that the web.xml alone won’t suffice. You will also have to configure your application server. This may get really frustrating when trying to implement a more advanced feature, like a JDBC realm.
Notice there are no other URL’s protected besides /index.html. The REST URL’s were secured using annotations, which is somewhat easier in this case. See the big, fat <security-constraint> element almost at the end? Compared to shiro.ini you are more busy writing element names than the actual rules. This might seem not critical for a small application, since you can specify multiple <url-pattern>’s. But imagine writing this with considerably more roles and rules to enforce and url’s to protect.
<param-name>resteasy.role.based.security</param-name> <!-- turn on JAX-RS Annotations -->
<login-config> <!-- configure authentication -->
<auth-method>FORM</auth-method> <!-- form-based authentication chosen -->
<realm-name>secureDomain</realm-name> <!-- name of your security realm on the application server -->
<form-login-config> <!-- specify the login and error page -->
<security-constraint> <!-- here you can make a set of URL's only accessible to certain user roles -->
<web-resource-collection> <!-- you can also specify wich HTTP methods have to be protected -->
<url-pattern>/index.html</url-pattern> <!-- the URL pattern to be protected -->
<auth-constraint> <!-- the set of roles which are granted access to the URL's specified in <web-resource-collection> -->
<security-role> <!-- the security roles used by the application -->
Spring Security Example
Spring Security’s basic configuration is quite easy. It might even be somewhat easier than Shiro’s. It will create a login page (if you don’t have one) and add protection against CSRF and session fixation. The automatic protection works best with JSP’s though. Workarounds will be necessary for HTML.
To implement custom components, you’ll have to learn bean definition in XML and injection with Spring. This can result in a lot of bean declarations, making the .xml hard to read. Also, use of annotations requires further Spring or AspectJ dependencies.
<!-- use the <http> element to configure a filter chain -->
<http pattern="/rest/**" create-session="never"> <!-- apply chain on a specific URL using 'pattern' | control session creation using 'create-session' -->
<intercept-url pattern="/**" access="hasRole('EMPLOYER')" /> <!-- access to every URL following /rest/ is restricted to the 'EMPLOYER' role -->
<http-basic /> <!-- turn on HTTP Basic Authentication -->
<http> <!-- a <http> element without a pattern attribute is applied to all incoming requests that are not caught by other <http> elements before it -->
<intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" /> <!-- grant everyone access to /login.html -->
<intercept-url pattern="/index.jsp" access="hasRole('EMPLOYEE') or hasRole('EMPLOYER')" /> <!-- restrict access to index.jsp to subjects in the 'EMPLOYEE' or 'EMPLOYER' role -->
<form-login login-page="/login.jsp" default-target-url="/index.jsp"
always-use-default-target="true" /> <!-- turn on form authentication, set default success url, tell spring to always use that url -->
<logout /> <!-- turn on logout -->
<remember-me /> <!-- turn on remember me -->
<csrf disabled="true" /> <!-- turn on csrf protection -->
<authentication-manager> <!-- turn on authentication services -->
<authentication-provider> <!-- compares the supplied username/password combination with the ones stored in <user-service> -->
<user-service> <!-- store username/password pairs in-memory -->
<user name="jan" password="passwort" authorities="ROLE_EMPLOYER" />
<user name="naj" password="passwort" authorities="ROLE_EMPLOYEE" />
There isn’t much to say here, since Spring Security has a huge community compared to the other two. There are a lot of questions and answers on Stack Overflow (SO) related to Spring Security, so one is most likely to find at least a hint to some problem. Also, the official forums aren’t supported anymore, they are available only in read mode. Support has been moved to SO. There, the mods monitor certain tags.
Support for Shiro is rather “okay”. There is an official user forum with medium activity. Searching for help on other sources will not yield that much more results. It’s likely you will see the same people (for example the original developer Lez Hazelwood) answering questions on popular sites (such as SO), which is not necessarily bad. It might take some time to solve unexpected problems.
The worst thing about Java EE Security support is that you also have to rely on the community of the container you are using. So the support, effort and time needed to solve problems will vary.
All three are under active development, however. While Java EE Security is getting new features with the Soteria API (Java EE 8), Spring Security and Shiro are being constantly improved.
Shiro shines with it’s simplicity and flexibility. This is further underlined by INI configuration. Shiro also does it’s best to be as independent of other technologies as possible. It also requires very few dependencies, making it lightweight. Session Management for non-web applications (like a CLI client or a mobile app) and the Wildcard Permission Syntax are also considerable.
Spring Security’s automatic protection mechanisms give it an initial edge in the context of web-applications. Overall one can say that the framework is relatively comprehensive in regards of web. However, this comes at the cost of being rather heavyweight and bound to Spring tech in some cases. In contrast to Shiro’s Wildcard Permission Syntax, permissions in Spring Security can be implemented based on Spring EL.
Java EE Security is rather lacking here. In other words, it really doesn’t offer any outstanding features and just covers the most basic needs of application security.
If you have a rather small application with not too many users and roles and don’t need to use any overly advanced features, feel free to use Java EE Security. It provides a solid base just for that. Java EE Security possibilities are quickly exhausted though. For example, you can specify only one authentication mechanism for the whole application. Also, if the application needs to be portable, one should definitely use one of the other two frameworks.
Now if there is need for a largely independent, lightweight and extensible security solution, Apache Shiro is the way to go. The downside, however, is that it might take some time to overcome problems. One might also have to implement some features by themselves. Shiro’s design (interface-driven and POJO-based) facilitates this, however.
At last, if the application is already Spring-based, one might as well stay on the train and use Spring Security, there aren’t any real downsides in this case (beside Spring Security being somewhat harder to implement). This is different for spring-less applications, even more if one never has worked with Spring before. Implementation of advanced features is even harder at first and annotations cannot be used unless Spring itself or AspectJ are included. Also, if there is need for Spring OAuth2, one must use spring-mvc, instead of Jersey or RESTeasy, to create REST resources.
With this, our comparison comes to an end. Again, a small reminder about the relativity of our observation. Experiment with the frameworks by yourself and use the one that suits your needs best.