{"id":16088,"date":"2014-11-19T14:52:02","date_gmt":"2014-11-19T09:22:02","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=16088"},"modified":"2016-06-28T11:12:49","modified_gmt":"2016-06-28T05:42:49","slug":"object-based-security-using-spring-security-acl-in-grails","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/object-based-security-using-spring-security-acl-in-grails\/","title":{"rendered":"Object based security using Spring Security ACL in Grails"},"content":{"rendered":"<p><a href=\"http:\/\/www.tothenew.com\/java-development-services\">Spring<\/a> security is used to secure the URL and only authenticated user is allowed to access that. But sometimes we need to secure the java Class instances and here comes ACL to rescue us.<\/p>\n<p>Let&#8217;s see why we need <b>object based security\/ACL<\/b> model.<\/p>\n<p>Suppose, there is relation &#8220;<b>BankAccount<\/b>&#8221; and 10 records exists for it. So as per the requirement, only authorized person should have access to his\/her account i.e only BankAccount holder or some bank authorities should have access over it and not any other have.<\/p>\n<p>Now, depending on the User&#8217;s role we can restrict only the URLs using Spring Security core but not the access to any record. To achieve the object based security we need Spring Security ACL. <b>Spring Security ACL uses Spring Security Core API.<\/b><\/p>\n<p>You can use Spring Security ACL in any Java web application, <b>for <\/b><b>configuring<\/b> the same in Grails App you can follow the <b><a href=\"http:\/\/grails.org\/plugin\/spring-security-acl\" target=\"_blank\">link<\/a><\/b> .<\/p>\n<p>After successful configuration there will be new tables will be created<\/p>\n<ol>\n<li>\n<pre><span style=\"font-family: sans-serif;\">acl_class<\/span><\/pre>\n<\/li>\n<li>\n<pre><span style=\"font-family: sans-serif;\">acl_entry<\/span><\/pre>\n<\/li>\n<li>\n<pre><span style=\"font-family: sans-serif;\">acl_object_identity<\/span><\/pre>\n<\/li>\n<li>\n<pre><span style=\"font-family: sans-serif;\">acl_sid<\/span><\/pre>\n<\/li>\n<\/ol>\n<p><strong>Note:<\/strong> This is tested till Grails version 2.3.7 and I am not going to explain tables that were created due to Spring Security Core api (ie: user, role, user_role etc)<\/p>\n<p><strong>Note: <\/strong>Spring ACL security framework provides some beans(or say <a href=\"http:\/\/www.tothenew.com\/grails-application-development\">grails services<\/a>) that ease our task like <span style=\"font-family: sans-serif;\">aclService<\/span>, a<span style=\"font-family: sans-serif;\">clUtilService, permissionEvaluator<\/span><\/p>\n<p>The whole ACL functionality designed to work around above 4 tables.<\/p>\n<ul>\n<li>\n<pre><span style=\"font-family: sans-serif;\"><b>acl_class<\/b><\/span><\/pre>\n<\/li>\n<\/ul>\n<p><span style=\"font-family: sans-serif;\"><b>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 <\/b>Object class that need to be secured using object based security (for example Account domain discussed in above example) should have an entry in this table<br \/>\n<\/span><br \/>\n<span style=\"font-family: sans-serif;\"><br \/>\naclService.createAcl(domainObject), per domain class only one entry is required in this table<\/span><\/p>\n<ul>\n<li>\n<pre><span style=\"font-family: sans-serif;\"><b>acl_sid<\/b><\/span><\/pre>\n<\/li>\n<\/ul>\n<p><span style=\"font-family: sans-serif;\"><b>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 <\/b>This table contains the entry for user or role to whom we want to provide permission on any object instance. We don&#8217;t need to maintain this table at all, when we add any permission to any user, entry is automatically handled by AclUtilService.<\/span><\/p>\n<ul>\n<li>\n<pre><span style=\"font-family: sans-serif;\"><b>acl_object_identity<\/b><\/span><\/pre>\n<\/li>\n<\/ul>\n<p><span style=\"font-family: sans-serif;\"><b>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 <\/b>For each secured instance of object there should be an entry in this table. This entry is also maintained by AclUtilService when we add a permission to any object instance.<br \/>\n<\/span><\/p>\n<ul>\n<li>\n<pre><span style=\"font-family: sans-serif;\"><b>acl_entry<\/b><\/span><\/pre>\n<\/li>\n<\/ul>\n<p><span style=\"font-family: sans-serif;\">\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0 Whenever we add or remove a permission to\/from an object instance for a user\/role, the entry for each permission (read,write,create,administration) is maintained in this table.<\/span><\/p>\n<pre><span style=\"font-family: sans-serif;\">\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 aclUtilService.addPermission(domainObject, User.findByName('xyz'), BasePermission.ADMINISTRATION)<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>Once we have done with providing permission to an object, now its time to secure our operation over it<\/p>\n<pre>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0<span style=\"font-family: sans-serif;\">\r\n           @PostFilter(\"hasPermission(filterObject, 'administration') or hasPermission(filterObject, 'read')\")\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 List&lt;Account&gt; listAccounts(){\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 Account.list()\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 }\r\n<\/span><\/pre>\n<p>In above code we have used PostFilter annotation, that processes the returning object list, and only returns the authorized list of objects for logged in user(objects on which user have either administration or read rights) .<\/p>\n<p>&nbsp;<\/p>\n<pre>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0<span style=\"font-family: sans-serif;\">\r\n          @PreFilter(\"hasPermission(filterObject, 'read')\")\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 Map fetchAmountInAccounts(List&lt;Account&gt; accounts){\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 Map map=[:];\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 accounts.each{\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 map.put(it,it.amount);\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 map\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 }\r\n<\/span><\/pre>\n<p>In above code only authorized objects will be provided to the function for any operation from the supplied list of objects.<\/p>\n<p>We can also restrict some operation on any object using PreAuthorize annotation,<\/p>\n<pre><span style=\"font-family: sans-serif;\">\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n        @PreAuthorize(\"hasPermission(#account,'admin')\")\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 void deleteAccount(Account account, OtherInfo info){}\r\n<\/span><\/pre>\n<p>Here if logged-in user doesn&#8217;t have admin permission on supplied account instance, he will not be able to perform operation over it. @PreAuthorize decides if a method can be invoked or not.<\/p>\n<p>We can also apply access control check after method execution using PostAuthorize annotation,<\/p>\n<pre>\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0<span style=\"font-family: sans-serif;\">@PostAuthorize(\"hasPermission(returnObject,'read')\")\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 Account searchAccount(FilterParams params){\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \/\/search activity\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 account\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0 }<\/span><\/pre>\n<p>above code ensures that only authorized user will be able to see the account details.<\/p>\n<p>PermissionEvaluator interface provides a way to check if some user have particular permission on any object instance or not,<\/p>\n<pre>permissionEvaluator.hasPermission(authentication, domainObject, BasePermission.READ)<\/pre>\n<p>returns true\/false stating if provided user have permission on given domainObject or not.<\/p>\n<p><a href=\"anilagrawal038\/aclExample.git\" target=\"_blank\">Here<\/a> is a sample application to test the Spring Security ACL.<\/p>\n<p><strong>May be required:<\/strong><\/p>\n<p>We found an issue in Spring Security ACL grails plugin (spring-security-acl:2.0-RC1), to handle it create a class as below<\/p>\n<p>&nbsp;<\/p>\n<pre>\u00a0\u00a0\u00a0 \u00a0\u00a0 <span style=\"font-family: sans-serif;\">\r\n            import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 import org.springframework.security.acls.domain.ObjectIdentityImpl\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 import org.springframework.security.acls.model.ObjectIdentity\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 import org.springframework.security.acls.model.ObjectIdentityGenerator\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy\r\n\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 class MyObjectIdentityRetrievalStrategy implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {\r\n\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 ObjectIdentity getObjectIdentity(domainObject) {\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 domainObject = GrailsHibernateUtil.unwrapIfProxy(domainObject)\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String className = domainObject.getClass().name\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 createObjectIdentity(domainObject.id, className)\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 ObjectIdentity createObjectIdentity(Serializable id, String type) {\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new ObjectIdentityImpl(type, id)\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 }<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>And make an entry in spring\\resources.groovy class inside beans closer<\/p>\n<p><span style=\"font-family: sans-serif;\">\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0 \u00a0\u00a0 objectIdentityRetrievalStrategy(MyObjectIdentityRetrievalStrategy)<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Spring security is used to secure the URL and only authenticated user is allowed to access that. But sometimes we need to secure the java Class instances and here comes ACL to rescue us. Let&#8217;s see why we need object based security\/ACL model. Suppose, there is relation &#8220;BankAccount&#8221; and 10 records exists for it. So [&hellip;]<\/p>\n","protected":false},"author":140,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":10},"categories":[7],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/16088"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/140"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=16088"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/16088\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=16088"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=16088"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=16088"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}