Securing your Liferay Service using PermissionChecker
May 3rd, 2010 by Bert WillemsTags:Java, Liferay, Security
Welcome to 3rd article in this series of articles showing you how you can develop custom Liferay services. In the previous article I showed you how you can implement a custom Liferay service and expose it as a web service. In this article I will show you how you can secure your service using Liferay’s build-in permission model.
The permission system in Liferay is pretty powerful: you configure permissions on roles or teams. Next you apply roles to either groups (communities, organizations) or individual users. In this article we will define a new permission: the permission to access our “very exiting business logic” sayHello. After all, we have invested countless hours in developing it; we don’t want everybody to use it without us knowing
.
I hope this article is useful to you. Please let me know if you have any questions or comments; just drop me a message and I will get back to you as soon as I can.
0. Project Setup
I have made some modifications to the code since my last article, so please download and unzip the starting point of our application. Please familiarize yourself with the project structure. I have refactored the view of the SayHelloPortlet to render using a JSP called sayHello.jsp, this will help us further along in this article.
Please note that I have modified the service contract specified in HelloWorldService.java. I have added the groupId parameter which we will use later in this article. Here is the new service contract:
String sayHello(long groupId, String name);
I have updated all the service implementation files as well to reflect changes in the contract.
1. Implement the permission check on the service
The first step is to implement the actual check on permission in our service implementation. Replace the sayHello method in HelloWorldServiceImpl.java with the following code (note the marked lines are new lines):
public String sayHello(long groupId, String name) {
try {
if (!getPermissionChecker().hasPermission(groupId, "nl.devatwork.hello.world.service", groupId, "SAY_HELLO"))
return "Hah, I don't think you can use my service. You don't have permission";
} catch (PrincipalException ex) {
return "security blew up";
}
return "Hello, " + name;
}
Lets dissect this code: The first thing we do is to get the instance of the PermissionChecker from our base class PrincipalBean. The PermissionChecker will do the heavy lifting for us, that is convenient isn’t it?
The second step is the call to the method hasPermission. This method performs the actual check for us. The method has the following signature:
public boolean hasPermission(long groupId, String name, long primKey, String actionId);
The first argument, groupId, determines the scope of the check. Remember I told you that you can apply roles to communities and organizations? Those things are groups with and ID. In the next step I will show you how we will get the value for groupId.
The second argument, name, is the name of our permission. The convention is we pass a String representation of our package in which the service lives.
The third argument, primKey, is the primary key of the resource we are protecting. Our service is a so-called top level resource which do not have a primary key that is why we will use the value of groupId. If we would have a model stored in the database we would specify the ID of the model here.
The final argument, actionId, is the identifier of the action. We will use a capitalized version of the method name here.
I think that is enough info about these few lines of code.
2. Getting the scope
Now that our service checks for permission we need to modify our portlet to provide the correct groupId in order for Liferay to scope the authorization properly. Please add the highlighted lines to SayHelloPortlet.java:
public void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException {
ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
long groupId = themeDisplay.getScopeGroupId();
String msg = HelloWorldServiceUtil.sayHello(groupId, "Liferay Dev");
request.setAttribute("msg", msg);
request.setAttribute("groupId", groupId);
getPortletContext().getRequestDispatcher("/WEB-INF/jsp/sayHello.jsp").include(request, response);
}
As you can see Liferay provides a nice utility called ThemeDisplay from which we can get the scope groupId.
3. Telling Liferay about our new permission
So far we have implemented the necessary code to check for permission. Now we have to inform Liferay that there is a new permission, otherwise you won’t be able to configure it and that would be a waste of effort, wouldn’t it? Create a new file called portlet.properties in the resource folder of the portlet application and paste the following content into it:
resource.actions.configs=resource-actions/default.xml
This properties file tells Liferay to look for resource actions (permissions) in default.xml in the folder resource-actions. Lets create that file now and paste the following content into it:
<?xml version="1.0" encoding="UTF-8"?>
<resource-action-mapping>
<model-resource>
<model-name>nl.devatwork.hello.world.service</model-name>
<portlet-ref>
<portlet-name>SayHelloPortlet</portlet-name>
</portlet-ref>
<supports>
<action-key>SAY_HELLO</action-key>
</supports>
<community-defaults/>
<guest-defaults/>
<guest-unsupported/>
</model-resource>
</resource-action-mapping>
I have highlighted the important lines. Please take a look at the first highlighted line. Does it look familiar to you? Yes, it is the same as the value of the name argument of the hasPermission method.
The second highlighted line tells Liferay that the SayHelloPortlet can configure this permission, I will show you how in the next step.
The final highlighted line should also look familiar to you. It is the same as the value of the actionId argument of the hasPermission method.
4. Create configure permissions link
This is the final step, we implemented the check, we told Liferay about our new permission. Now we need a place to configure it. Modify sayHello.jsp:
<%@ page contentType="text/html" isELIgnored="false" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<liferay-security:permissionsURL
modelResource="nl.devatwork.hello.world.service"
modelResourceDescription="Hello Service Permissions"
resourcePrimKey="${groupId}"
var="permissionURL"/>
<p>the msg was: ${msg}</p>
<div>
<p>lets <a href="${permissionURL}">configure</a> the permission for our service</p>
</div>
We have added a link to configure permission to our service. Notice that modelResource is again the same as the value of the name argument of the hasPermission method.
Now that we have implemented all the necessary changes we can compile and deploy the new JAR’s and WAR’s and start our application. Go ahead and add permissions, remove them, login and logout under different accounts. Our permission is working like a charm. If you haven’t followed all the steps above you can download the finished project.
That is it for now,I hope you have learned something. Let me know if you have any questions or comments. Bye.

7 Replies to “Securing your Liferay Service using PermissionChecker”
December 16th, 2010 at 02:14
Hi Bert;
Great post, i just upgrade the code of the liferay version to 6.0.5(avoiding portal-kernel), and i try to invoke the service via de portlet the but liferay keeps saying “the service is not set”, and also I cannot see the service listed at http://127.0.0.1:8080/tunnel-web/secure/axis, What do you think could be the cause for this?
ERROR [jsp:154] java.lang.RuntimeException: HelloWorldService is not set
at nl.devatwork.hello.world.service.HelloWorldServiceUtil.getService(HelloWorldServiceUtil.java:8)
at nl.devatwork.hello.world.service.HelloWorldServiceUtil.sayHello(HelloWorldServiceUtil.java:19)
at nl.devatwork.hello.world.portlets.SayHelloPortlet.doView(SayHelloPortlet.java:17)
at javax.portlet.GenericPortlet.doDispatch(GenericPortlet.java:328)
at javax.portlet.GenericPortlet.render(GenericPortlet.java:233)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:101)
at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:64)
at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:92)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)
at com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:638)
at com.liferay.portlet.InvokerPortletImpl.invokeRender(InvokerPortletImpl.java:723)
at com.liferay.portlet.InvokerPortletImpl.render(InvokerPortletImpl.java:425)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
December 16th, 2010 at 07:32
Hello Adolfo,
I am not sure why this error has thrown. I haven’t done any LR 6.0 development myself but I reckon it has something to do with changes in how service work in 6.0.
Mayb you can use the service builder directly to generate your service? See: http://www.liferay.com/community/wiki/-/wiki/Main/Service+Builder
Good luck and let me know if it worked,
Bert
January 17th, 2011 at 18:28
Hi there,
I have tryed following your instructions but i allways get a NullPointerException when deploying the portlet:
at com.liferay.portal.security.permission.ResourceActionsUtil._readActionKeys(ResourceActionsUtil.java:921)
at com.liferay.portal.security.permission.ResourceActionsUtil._readGuestUnsupportedActions(ResourceActionsUtil.java:967)
at com.liferay.portal.security.permission.ResourceActionsUtil._readPortletResource(ResourceActionsUtil.java:1101)
at com.liferay.portal.security.permission.ResourceActionsUtil._read(ResourceActionsUtil.java:900)
at com.liferay.portal.security.permission.ResourceActionsUtil._read(ResourceActionsUtil.java:888)
at com.liferay.portal.security.permission.ResourceActionsUtil.read(ResourceActionsUtil.java:428)
To see if i was doing something wrong i downloaded the project, but it seems that its not the portlet described here.
January 17th, 2011 at 22:05
Hello MagmaRules,
What version of Liferay are you using?
Greets,
Bert
April 21st, 2011 at 16:04
Hi
thanks for the excellent articles…. I was able to make all of them work. Re: creating and exposing servcies without using service builder or ext.
Two questions:
1) what advantages do you see with this method, over using service-builder or ext? ( i have to explain to my dept why i chose this)
2) i didn’t see in these examples, how to access underlying tables. I have added a couple of tables in the Liferay database, and I need to expose them with basic CRUD operations. and as a follow up to this question…. how to, using hibernate rather than straight JDBC.
thank you in advance for any response,
–Eli
April 21st, 2011 at 16:29
Hello Eli.
There isn’t a clear advantage, considering the requirement you describe in 2 I recommend you use the Liferay Service Builder. It will take care of your table access concern for you. See the service builder Wiki on the Liferay website for more info.
Regards,
Bert
August 22nd, 2011 at 04:55
[...] http://www.devatwork.nl/2010/05/securing-your-liferay-service-using-permissionchecker/ [...]