Adding Spring-Security to Openxava
Introduction The purpose of this article is to see how to integrate Spring Security on top of an Openxava standalone application. Openxava builds portlets as well as standalone applications. When working with portlets deployed on a portal such as Liferay, they handle secured access by configuration. A standalone application lets you have to handle this functionality yourself. This page will illustrate how to add spring security (authentication/authorisation) functionalities. The focus will be on the authorizations aspects since authorization is often enterprise-environment specific. To demonstrate the integration, this article will use the minuteproject Lazuly showcase application generated for Openxava. The first part identifies and explains the actions to undertake. The second part explains what minuteproject can do to fasten your development by generated a customed spring-security integration for you Openxava application. Eventually a set of tests will ensure that the resulting application is correctly protected for URL direct access as well as content display. Furthermore, the integration is technologically non-intruisive. You do not have to change Openxava code for it to work. Spring-Security Openxava integration Technical Access URL access The url pattern is the following http://servername:port/applicationcontext/xava/module.jsp?application=appName&module=moduleName given like that it is hard to protect. The module and application are passed as parameters. The URL has to be revisited with http://servername:port/applicationcontext/applicationPath/module And the 'parameter' access are banned. Enabling new URL access Add a servlet package net.sf.minuteproject.openxava.web.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ModuleHomeServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher dispatcher; String [] uri = request.getRequestURI().split("/"); if (uri.length < 4) { dispatcher = request.getRequestDispatcher("/xava/homeMenu.jsp"); } else { dispatcher = request.getRequestDispatcher( "/xava/home.jsp?application=" + uri[1] + "&module=" + uri[3]); } dispatcher.forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } homeMenu.jsp is a page including a header with menu (to protect and whose menu link URL are correspond to the secured format) and a footer. Add a servlet configuration Servlet configuration snippet done in Openxava servlets.xml. moduleHome net.sf.minuteproject.openxava.web.servlet.ModuleHomeServlet moduleHome /MenuModules/* This snippet will be package in war web.xml at build time by OpenXava ant script. Jsp access Prohibit any Openxava jsp access except the one of the menu To do that add an spring applicationContext-security.xml in you classpath (ex: Openxava src folder). ... This means that all path after xava will be accessible (ex: css...) safe jsp expect one homeMenu.jsp is available to all registered user (ie having role ROLE_APPLICATION_USER cf attribution at authorisation part further). Of course ensure that the role ROLE_NOT_PRESENT is really not present in your app. Business Access The idea is to give CRUD access on a entity base on role. Define roles and UC To be more explicit, I define 3 roles with their scope. Administrator can administrate ROLE and COUNTRY entities Application_user can manage all the other conference related tables safe the master data table mentionned above. Reviewer can access to the statistic views but not the administration. Both reviewer and Administrator can do what Application_user can do. In applicationContext-security.xml the role can be mapped to specific URLs Impact of the roles access on your model modal navigation Be coherent As I said before 'the CRUD access on a entity is role based' but the affectation mechanism has to reflect that. OpenXava has annotation to create an entity from another one. It is then logical that we cannot create entity B from entity A, if we do not have CRUD rights on entity B. The mechanism will consist in this case of affectation only with search functionalities. In our scenario it means that a user with 'application_user' only can select a country but can not create any (no create or update icons available). It is also true at the menu level, a user is entitled to see only its menu items corresponding to its profile. Here the menu is done in JSP. To secure the access you can wrap to code to secure with taglib code coming with spring security or add a little taglib such as the following isUserInRole.tag located in web/WEB-INF/tags/common. Wrap the code to protect here the administrator menu and each menu item Administration CountryRole Authentication/Authorization For the user to operate, he must be authenticated and authorised (moment where his role profile is loaded granting him with business access rights). I use an simple authentication and authorisation based a DB information. Of course you are not supposed to use that in production ;) In applicationContext-security.xml add the following snippet. java:comp/env/jdbc/conferenceDS Both authorisation and authentication queries have to be valid. Here, they are done on top of views, which means that you have to implement 2 views: user_authentication and user_authorisation. The datasource is the same as the one of the Openxava application View gives you flexibility because if you have indirection level of granularity such as (user-role-permission), your view can associate user to role Authentication flow Eventually you need to handle an authentication flow composed of welcome page login page access denied page logout link The flow is handled by applicationContext-security.xml Add the following snippet. Login.jsp is strongly inspired by spring petclinic sample Login test Locale is: Your login attempt was not successful, try again. Reason: . User:Password:Don't ask for my password for two weeks index.jsp Welcome to Conference login accessDenied.jsp Access denied! Not to forget a logout functionality here added on the menu Logoff Spring security dependencies Add spring security jars into web/WEB-INF/lib spring-aop-3.0.4.RELEASE.jar spring-asm-3.0.4.RELEASE.jar spring-beans-3.0.4.RELEASE.jar spring-context-3.0.4.RELEASE.jar spring-core-3.0.4.RELEASE.jar spring-expression-3.0.4.RELEASE.jar spring-jdbc-3.0.4.RELEASE.jar spring-security-acl-2.0.3.jar spring-security-config-3.1.0.M1.jar spring-security-core-2.0.3.jar spring-security-core-3.1.0.M1.jar spring-security-core-tiger-2.0.3.jar spring-security-taglibs-2.0.3.jar spring-security-web-3.1.0.M1.jar spring-tx-3.0.4.RELEASE.jar spring-web-3.0.4.RELEASE.jar Spring security context Spring security context had been mentioned at different level, here is the complete version java:comp/env/jdbc/conferenceDS Reference the context Openxava listeners.xml is the place where you can set web.xml-snippets to be package in web.xml at Openxava build time Add the following snippet org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:applicationContext-security.xml springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /* The minuteproject way Doing the integration can be time consuming. As you can notice there is some effort to have the code compliant for a webapp here Openxava to be bodyguard by Spring-Security. Meanwhile when dealing with data centric application, this knowledge can be crystalized to be instantly available. Because...there is an underlying concept that guides our choice and lead to best pratices. It is one thing to execute them, it is another to state it. The question is how do we specify which entity to access and to which role. The idea is to express with simplicity the relationship between role or permission and action. In our case the actions are: a full CRUD an affectation mechanism The full CRUD is associated to a specific role. The affection (linkage of an entity from another by search) is when to entities are linked but not all the role of the main entities are the same as the roles of the target. Otherwise affection goes with creation and update. And the roles are: Administrator Application_user Reviewer Now it is time for a primary school exercice If you represent an entity-relationship diagram, you should see boxes and links. Boxes for entities and links for relationships. Give each role/permission a color. Paint all the boxes that are full CRUD with the corresponding role color... Yes, you may paint the same box twice (resulting is color combination). The result gives you the Color access spectrum of your DB. Of course, we can further decline the gradient with other function (read-only, controller specific...) But the underlying idea is evident. What Minuteproject allows you to do it by enriching your model with this color spectrum at the entity level or at the package level. This enables you to work with concept only closed to UC agnostic of technology implementations. Minuteproject configuration snippet Generation Minuteproject configuration full The configuration is similar to lazuly show case enhanced with security aspects org.gjt.mm.mysql.Driver jdbc:mysql://127.0.0.1:3306/conference root mysql The main points are exclude entities starting with user_ (i.e. the security entity used by spring configuration) add security access on package level package admin is accessible by role administrator only package statistics is accessible by role reviewer only default package (conference) is accessible by any application_user add spring-security track in the target add reference in openxava to spring-security The track springsecurity holding the configuration is not yet bundled in minuteproject release 0.8 but will be present for 0.8.1+. Set up Database Implement the views Here a very dummy implementation. create view user_authentication as select email as username, first_name as password, '1' as active from conference_member ; create view user_authorisation as select cm.email as username, r.name as role from conference_member cm, role r, member_role mr where mr.role_id = r.id and mr.conference_member_id = cm.id union select cm.email as username, concat('ROLE_',r.name) as role from conference_member cm, role r, member_role mr where mr.role_id = r.id and mr.conference_member_id = cm.id ; As you can not there is a little redundancy in the user_authentication view, since sometimes the role administrator is refered sometimes role_administrator. This will be homogenized in next release. Add some default value Here a very dummy implementation. INSERT INTO country (id, name, iso_name) VALUES (-1, 'France', 'FR'); INSERT INTO address (id, street1, street2, country_id) VALUES(-1, 'rue 1', 'rue 2', -1); INSERT INTO conference_member (id, conference_id, first_name, last_name, email, address_id, status ) VALUES (-1, -1, 'f', 'a', 'fa@test.com', -1, 'ACTIVE' ); INSERT INTO role (id, name) VALUES (-1, 'ADMINSTRATOR' ); INSERT INTO role (id, name) VALUES (-2, 'ROLE_APPLICATION_USER' ); INSERT INTO member_role (conference_member_id, role_id) VALUES (-1, -1); INSERT INTO member_role (conference_member_id, role_id) VALUES (-1, -2); So when user fa@test.com connects he will get the role Administrator which allows him to access the administrator menu and create a new role called 'REVIEWER'. He can also create a new conference member and associate with the role 'REVIEWER'. Set up Application Download the lazuly-openxava-springsecurity minuteproject configuration from google code minuteproject. Copy file into /mywork/config Execute In /mywork/config: model-generation.cmd mp-config-LAZULY-Openxava-with-spring-security.xml The generated code goes to /DEV/output/openxava-springsecurity/conference Packaging Here the packaging/deployment is a 2 steps exercices (unfortunately): there is no more the start-tomcat/stop-tomcat command in OX distribution spring dependencies are not included Steps Check that Openxava 4.3 is available, and OX_HOME is set to Openxava 4.3 from /DEV/output/openxava-springsecurity/conference run build-conference(.cmd/sh). This will trigger the build that is successful but not the deployment due to information before. Open the project generated by the build in Openxava workspace Add Spring security dependencies Start tomcat server (remark: The Datasource for the application is present in tomcat/config/context.xml) Deploy Enjoy Testing Welcome page Default URL at context root of the application. Login page Any other direct called where the user is not authenticated will be intercepted and routed to this page Contextual Menu The user have access to the admin and conference part not the statistics. The URLs have been modified. When the user tries to access the standard OX style URL he recieves an access denied (ex: module.jsp) Add role reviewer Add user Affect user with role reviewer and default (application_user) Logoff (click logoff) Login as Reviewer On login page enter username=bc@test.com and password=b In the contextual menu you do see the 'admin' package' And you get an access deny when manipulating directly the URL Now the application is secured. Conclusion This article showed the configuration and manipulation to integrate spring security with openxava in a non-intrusive manner. It stressed a new concept 'DB color access spectrum' and how to densify the security information in minuteproject configuration. DB color access spectrum is a concept which ask only to be extended: Ad-hoc functions, controllers Store procedures It is simple to express and analyst friendly. It is not bound to a technology. It is a step in easily defining fine grain access, its combination with profile based access and state based access (to do manually... for the moment ;)) could pave the way to intuitive and implicit workflows instead of heavy BPM solutions.
July 5, 2013
by Florian Adler
·
7,520 Views
·
1 Like