What is it?
With the Octopus framework, you have a permission based security framework for Java EE which is highly customisable, CDI integrated and focussed on type-safety. You can protect URL’s, JSF components, CDI methods and EJB invocations with one and the same permission check code.
Since security is one of those cross cutting concerns, we don’t want to code it next to our statements performing the business requirements. So you will be able to use annotations to protect methods and custom tags for JSF components.
It is licensed under the Apache License V2 and is sponsored by C4J.
Permission based
The Java EE ecosystem has his own security mechanism but it is role based. And this way of working has some major disadvantages.
To better illustrate this, lets examine an example.
Suppose we have an HR application where we can manage the employees of the company. And we have 4 roles, linked to 4 types of people. The employee itself, their manager, the HR assistant and the big boss. Each of them can see different type of information and perform different actions. The salary for instance, as employee you can see your own salary but not the one of your colleagues. But your manager can see the salary of all the people who are working in his department. But not the salary of an employee in another department. The HR assistant can see them all, just as the big boss. But updating the salary is restricted to the HR and big boss.
Since for each action of information that is shown, a certain role is required, it becomes a problem when you need to change something. Suppose we need to replace functionality, like some action can be performed now by all employees or you want to define a 5th role and rearrange the allowed actions. You need to recompile your application in those situations. And you need to test it again to see if there is no security issue created. You want to make sure that people can’t see information which they aren’t allowed to see.
With a permission based approach, on the contrary, this is much easier. Each action or data information needs a certain permission to execute or view it. The user gets assigned those permissions that he needs. When you need to reassign some security rules, it is sufficient to assign different permissions to the user to have your desired effect. There is no need to recompile your code and thus in theory you also don’t need to retest your application. Since you already verified that only users which have the required permission can perform the action.
Build on top of
Permission based security is not available by default in Java EE, but there is an excellent framework that can assist you. Apache Shiro is designed to do permission based security in any kind of application, from a Java SE application like a swing based one, to any web application.
For JSF there is no specific support but as described in the blogpost of BalusC, you can use it also for JSF with some small changes.
In the past, I already prototyped the possibility to have security on JSF components, which was based on the CDI extension CODI. ( see http://jsfcorner.blogspot.be/2011/03/jsf-security.html)
So I took those two sources of information and bundled it in the Octopus framework.
Setup
In order to add the framework, you need to add the Octopus maven artefact to your project.
<dependency> <groupId>be.c4j.ee.security</groupId> <artifactId>octopus</artifactId> <version>0.9.2</version> </dependency>
It brings also Shiro web and Extval core into your application. The latter is used for intercepting the JSF rendering so that we can add security for specific JSF components as I’ll show you later in this text.
It uses also CODI (MyFaces Extensions CDI), especially the modules Messaging and Web. But you need to specify the dependency in your project as I wanted to give you the freedom of which modules you want to include.
The next thing you need to do is to define in the file securedURLs.ini, place it in the WEB-INF folder, the URLs that needs to be secured.
/pages/** = user
With the above information, we secure all the URL’s in the pages path and they can only be visited by authenticated users. All the other pages can be visited anonymous.
The last thing we need now, is the page which will be shown when the Octopus frameworks needs the credentials of the users. It will open by default the /login.xhtml page (suffix is defined by the JSF servlet definition) where you can have input fields for username and password.
You can use any JSF component library in combination with the Octopus framework. Also the layout and structure of the login page is completely under control of the developer. You can link to #{loginBean.userName} and #{loginBean.password} for the fields value and the button can execute #{loginBean.doLogin} method to perform the authentication.
If the authentication succeeds, the user is redirected to the original requested page, but now authenticated.
Configuration
In the previous chapter there was already a small configuration step, the securedURLs.ini, but there is one other very important configuration requirement.
Octopus is designed to handle all the security features but leaves the retrieval and definition of users and there rights to the developer. This allows to use any backend system, database, LDAP or any other system you like, for the storage of the security related data. And there is one exchange point where we give that information in the Octopus required format.
So define a bean which extends be.c4j.ee.security.realm.SecurityDataProvider. By implementing the 2 methods of the interface we can provide Octopus with all the required data.
The method getAuthenticationInfo() is called when Octopus executes the login method we have specified behind our button on the login page.
The parameter AuthenticationToken contains the username (AuthenticationToken.getPrincipal() -> String ) and password (AuthenticationToken.getCredentials() -> char[]).
You don’t need to verify yourself if the supplied password matches the one entered by the user. This is because Octopus, in combination with Shiro also supports hashed credentials. Therefor you supply all the information Octopus needs to perform the verification itself.
You can use the AuthenticationInfoBuilder to build the required return object, an example is shown below.
@Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) { AuthenticationInfoBuilder infoBuilder = new AuthenticationInfoBuilder(); infoBuilder.principalId(principalId++).name(token.getPrincipal().toString()); // TODO: Change for production. Here we use username as password infoBuilder.realmName("MyApp").password(token.getPrincipal()); return authenticationInfoBuilder.build(); }
When the user name is not known, you are allowed to return null.
The second method, getAuthorizationInfo(), is called whenever the system needs authorization information about the user. Again, you can use a builder, AuthorizationInfoBuilder, to supply Octopus the permissions assigned to the user. This information is cached so this method is only called once for each user.
A more extensive description about the usage of permissions is given in another blog post.
Securing methods
The most important methods that you like to secure, are the EJB methods. They contain your business logic and you want to protect them so that only the allowed users can execute the method. Octopus contains the class be.c4j.ee.security.interceptor.AppSecurityInterceptor which can be used as interceptor on EJB methods. The preferred way is that you define the interceptor on all EJB’s with the aid of the ejb descriptor file (ejb-jar.xml)
<?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" > <interceptors> <interceptor> <interceptor-class>be.c4j.ee.security.interceptor.AppSecurityInterceptor</interceptor-class> </interceptor> </interceptors> <assembly-descriptor> <interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>be.c4j.ee.security.interceptor.AppSecurityInterceptor</interceptor-class> </interceptor-binding> </assembly-descriptor> </ejb-jar>
If you do this, then all methods are secured and as it should be, by default they aren’t accessible anymore (default is permission denied). There are various annotations to allow users (or requires certain permissions) to execute the method. The Java EE annotation @PermitAll is also supported but of course use it with care.
More about the securing of EJB methods can be read in the users guide (under construction) and some further posts.
Securing JSF components
The idea of securing JSF components is already described in my other post ( http://jsfcorner.blogspot.be/2011/03/jsf-security.html). The functionality is extended within the Octopus framework. The securedComponent tag received 2 other attributes, permission and role where you can specify the named permission and the named role that needs to be checked. More examples on this will be available on the user guide and in following posts.
An example of a secured commandButton
<p:commandButton action="createDepartment" value="Create department" ajax="false"> <sec:securedComponent permission="DEPARTMENT_CREATE" /> </p:commandButton>
Tight CDI integration
Octopus uses some advanced CDI stuff and overriding of the default functionality can be done by using a @Specialized CDI bean.
A lot of artefacts can be injected using the @Inject annotation and there are automatically named beans created that can verify if users have some certain permission or role.
But I also hit the boundaries of CDI. Because I wanted to make everything as type safe as possible, I used typed beans with generics. An example is the lookup between and enums which lists the correspondence between named permission and the actual Permission object, PermissionLookup<? extends NamedPermission> . But within the CDI spec there are restrictions imposed and thus I need to resort to some manual lookup.
More about some of the CDI stuff will be presented in another post.
Compatibility
The first version of Octopus is tested with Glassfish 3.1.2.2 and TomEE 1.6. But is the idea to make it compatible with all Java EE 6 and Java EE 7 servers. Maybe we need some small tweaks to make it work on other servers, but since we only use standard Java EE, it should work on any server.
Status
As this is a first version of the framework, a lot of small issues can pop up. Also there is still a lot of work that needs to be done regarding the testing and documentation of it. These will be addressed in the coming months. Also a lot of the possible issues will be resolved as the framework will be used to create various small show case applications, they will be publicly available, and in the production application which will be started soon.
But for now, consider it as a beta.
Conclusion
Octopus is still in the early days of development but it has already almost all the features that you need to implement a flexible permission based security solution for Java EE. You can find the code on bitbucket https://bitbucket.org/contribute-bitbucket/javaeesecurityfirst (as C4J is an Atlassian Partner) and any feedback is of course very welcome.
Stay tuned for more detailed information about Octopus later on.
No comments:
Post a Comment