Implementing Grails Spring Security ACL in web application

0
201

Introduction

The contents of this article was developed and implemented about couple of years back. Though I had intention to promulgate what I did but was in vacillate due to busyness. Finally, I strict my mind to share this.

This article will help to incorporate Grails Spring ACL in grails web application effectively. So that, Developers can reuse the security procedure in their multiple web applications. It is a role based security system and also authentication and authorization can be glued to page, action and in a segment of code. The work flows are given below:

Background

If you want to get some more information regarding ‘spring security acl’ in grails then you can read the documentation from this url: http://grails-plugins.github.io/grails-spring-security-acl/

But in this article the concrete elements have been picked up and explained the way to use these and implement in the web application. It is considerd that, Grails development environment is already setup to use the content and knowledge from this article. To implement grails acl we need few plugins as pre-requisites and they are as follows:

  • Spring-security-acl
  • Spring-security-core
  • At first install spring security acl plugins in your application directory by writing the following command in the command prompt:
  • Go to application’s root directory and type: grails install-plugin spring-security-acl
  • Install plugin spring security core to use certain classes of this plugin in the application’s root directory through following command
  • grails install-plugin spring-security-core. This will install the spring-security-core version that is compatible with your currently installed grails (grails-2.1.1 or grails 2.2.1)
  • Run grails grails s2-quickstart command in your application’s directory in the command prompt. This is used to create acl needed domain classes.The command can be written as grails s2-quickstart access_control User Role. This will create three classes User,Role and UserRole inside access_control folder. You can name your own folder name as your need.
  • Run grails create-acl-domain command. This command will create few other domain classes like AclClass, AclEntry, AclObjectIdentity and AclSid. For example, AclClass will be used to set permission for the particular domain class.
  • BootStrap.groovy runs immediately when the application compiles. So, all the initial settings related to acl can be done here.

Using the code

Copy the following code in BootStrap class file:

import static org.springframework.security.acls.domain.BasePermission.ADMINISTRATION
import static org.springframework.security.acls.domain.BasePermission.DELETE
import static org.springframework.security.acls.domain.BasePermission.READ
import static org.springframework.security.acls.domain.BasePermission.WRITE
import org.springframework.security.authentication. UsernamePasswordAuthenticationToken
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextHolder as SCH


class BootStrap {

 def aclService
 def aclUtilService
 def objectIdentityRetrievalStrategy
 def sessionFactory
 def springSecurityService

 def init = { servletContext ->
 loginAsAdmin()
 sessionFactory.currentSession.flush()
 SCH.clearContext()
 }

 private void loginAsAdmin() {



 SCH.context.authentication = new UsernamePasswordAuthenticationToken(
 'admin', 'admin123',
 AuthorityUtils.createAuthorityList('ROLE_ADMIN'))
 }

}

There has to be an authentication to create ACLs. We have to initialize one user as an admin to start the ACL to work.

We have to include following import statements in the BootStrap.groovy at the top (if any base permission is needed then import BasePermissions). To avoid any sort of unwanted result include all.

  • import static org.springframework.security.acls.domain.BasePermission.ADMINISTRATION
  • import static org.springframework.security.acls.domain.BasePermission.DELETE
  • import static org.springframework.security.acls.domain.BasePermission.READ
  • import static org.springframework.security.acls.domain.BasePermission.WRITE
  • import org.springframework.security.authentication. UsernamePasswordAuthenticationToken
  • import org.springframework.security.core.authority.AuthorityUtils
  • import org.springframework.security.core.context.SecurityContextHolder as SCH
  • BuildConfig.groovy

To compile any plugin at runtime, write the plugin name inside plugins closure. I have written as compile ‘:spring-security-core:1.2.7.3’

Since plugin version varies based on the grails compatibility version, so you have to compile the core plugin that has been installed with the spring-security-core command earlier.

  • Config.groovy

In case of spring-security-core:1.2.7.3

Spring-security-core plugin adds following in the Config.groovy file

grails.plugins.springsecurity.userLookup.userDomainClassName = ‘access_control.User’

grails.plugins.springsecurity.userLookup.authorityJoinClassName = ‘access_control.UserRole’

grails.plugins.springsecurity.authority.className = ‘access_control.Role’

This will maintain User, Role operation for the acl permission tags. Role and User with assigned roles can be created with the above domains (User, Role)

In case of spring-security-core:2.0-RC2

You will see some extra code segments as below:

grails.plugin.springsecurity.controllerAnnotations.staticRules = [

‘/’:[‘permitAll’],

‘/index’:[‘permitAll’],

‘/index.gsp’:[‘permitAll’],

‘/**/js/**’:[‘permitAll’],

‘/**/css/**’:[‘permitAll’],

‘/**/images/**’:[‘permitAll’],

‘/**/favicon.ico’:[‘permitAll’],

‘/Stock/**’:[‘permitAll’],

‘/AclClass/**’:[‘permitAll’]

]

You have to do some extra working to invoke acl permission for each controller class. So you have to add each domain class as above. Here you are observing that Stock class is invoked for ACL. This will invoke controller of the domain class to the ACL.

  • Create Login Controller in the controller folder. You can create this whenever you want. Copy and paste the following code:
import grails.converters.JSON
import javax.servlet.http.HttpServletResponse
import grails.plugin.springsecurity.SpringSecurityUtils
import org.springframework.security.authentication.AccountExpiredException
import org.springframework.security.authentication.CredentialsExpiredException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.web.WebAttributes
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import groovy.sql.Sql
import groovy.json.JsonOutput
import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.JSONArray;

class LoginController {



 def authenticationTrustResolver



 def springSecurityService




 def index = {
 if (springSecurityService.isLoggedIn()) 
 {
 session["User"]=springSecurityService.authentication.name
 
 redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
 }

 else 
 {
 redirect action: 'auth', params: params
 }
}




 def auth = {
 def config = SpringSecurityUtils.securityConfig
 if (springSecurityService.isLoggedIn()) 
 {
 redirect uri: config.successHandler.defaultTargetUrl
 return
 }

 String view = 'auth'
 String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
 render view: view, model: [postUrl: postUrl,
 rememberMeParameter: config.rememberMe.parameter]
 }




def authAjax = {
 response.setHeader 'Location', SpringSecurityUtils.securityConfig.auth.ajaxLoginFormUrl
 response.sendError HttpServletResponse.SC_UNAUTHORIZED
}




 def denied = {
 if (springSecurityService.isLoggedIn() &&
 authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) 
 {
 
 redirect action: 'full', params: params
 }
}




 def full = {
 def config = SpringSecurityUtils.securityConfig
 render view: 'auth', params: params,
 model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication),
 postUrl: "${request.contextPath}${config.apf.filterProcessesUrl}"]
 }




 def authfail = {
 def username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
 String msg = ''
 def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
 
 if (exception) 
 {
 if (exception instanceof AccountExpiredException) 
 {
 msg = g.message(code: "springSecurity.errors.login.expired")
 }

 else if (exception instanceof CredentialsExpiredException) 
 {
 msg = g.message(code: "springSecurity.errors.login.passwordExpired")
 }

 else if (exception instanceof DisabledException) 
 {
 msg = g.message(code: "springSecurity.errors.login.disabled")
 }

 else if (exception instanceof LockedException) 
 {
 msg = g.message(code: "springSecurity.errors.login.locked")
 }

 else 
 {
 
 msg="Invalid user" 
 }
 }

 if (springSecurityService.isAjax(request)) 
 {
 render([error: msg] as JSON)
 }

 else 
 {
 flash.message = msg
 redirect action: 'auth', params: params
 }
}




 def ajaxSuccess = {
 render([success: true, username: springSecurityService.authentication.name] as JSON)
 }




 def ajaxDenied = {
 render([error: 'access denied'] as JSON)
 }
}
  • Create Logout Controller in the controller folder and paste the following code. You will call this logout controller action whenever you click on the logout button in your web application. This will clear all your login data from session, cache and cookie:

Hide   Copy Code

import grails.plugin.springsecurity.SpringSecurityUtils

class LogoutController {




def index = {

redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl 
}
}
  • Create auth and denied view pages for the login controller:

In your auth page copy and paste the following code:

<div id='login'>
<div class='inner'>
<div class='fheader'><g:message code="springSecurity.login.header"/></div>

 <g:if test='${flash.message}'>
 <div class='login_message' style="color: red;">${flash.message}</div>
 </g:if>

 <form action='${postUrl}' method='POST' id='loginForm' class='cssform' autocomplete='off'>

 <p>
 <label for='username'>
 <g:messageCode="springSecurity.login.username.label"/>:
 </label>
 <input type='text' class='text_' name='j_username' id='username'/>
</p>

 <p>
 <label for='password'>
 <g:messageCode="springSecurity.login.password.label"/>:
 </label>
 <input type='password' class='text_' name='j_password' id='password'/>
</p>

 <p id="remember_me_holder">
 <input type='checkbox' class='chk' name='${rememberMeParameter}'id='remember_me' <g:if test='${hasCookie}'>checked='checked'</g:if>/>
 <label for='remember_me' style="font-size: 11px; font-weight: normal;"><g:message code="springSecurity.login.remember.me.label"/></label>
 <input type='submit' id="submit" class="submit" value='${message(code: "springSecurity.login.button")}'/>
 </p>
 </form>

</div>
</div>
</div> <!- loginbox -->

${postUrl} will check the authentication which isJ_spring_security_check.

  • In your denied page copy and paste the following code.

Hide   Copy Code

 <head>
 <meta name='layout' content='main' />
 <title><g:message code="springSecurity.denied.title" /></title>
</head>

<body>
 <div class='body'>
 <div class='errors'><g:message code="springSecurity.denied.message" /></div>
 </div>
</body>

Although this page will be redirected whenever unauthorized access takes place. You can redirect some other page based on your need.

  • Create Role and User using Role and User domain from the browser.
  • Finally Implement authentication in a controller or action as below:

Create a controller then copy and paste following code in that controller:

Hide   Copy Code

import grails.plugins.springsecurity.Secured 
import org.springframework.security.access.prepost.PostFilter
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.acls.domain.BasePermission
import org.springframework.security.acls.model.Permission
import org.springframework.transaction.annotation.Transactional
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils 




@Secured(['ROLE_USER']) 
class AController {

 
 
 def index() {
}
}

Run the application and hit the action of that controller. Check your ACL whether or not the above Controller works as it intened to do. If it does then your ACL settings are implemented perfectly and  working emaculately .

Now Move to Implement & Handle Role, User, Set permission and apply dynamic permission to a controller for a project:

Note: If the procedure are being followed properly mentioned above then Role, User, UserRole will reside in a folder named ‘access_control’  

Role domain will look like as below:

Hide   Copy Code

package access_control

class Role {

 String authority
 static mapping = {
 cache true
 }

 static constraints = {
 authority blank: false, unique: true
 }

 String toString(){
 return authority
 }
}

Note: Create role by prefixing ROLE. for example if you want to create a general role, then create as ROLE_GENERAL format.

Generate Controller and View for the Role domain class if they are not created already. After creating the Role domain, controller and view the system is ready to create a role.

Copy and paste the following code in your previously generated User domain. Copy the inner code of the User Class closure:

package access_control

class User {

 transient springSecurityService
 String username
 String password
 String email
 boolean enabled
 boolean accountExpired
 boolean accountLocked
 boolean passwordExpired
 static transients = ['springSecurityService']

 static constraints = {
 username blank: false, unique: true
 password blank: false
 }


 static mapping = {
 table 'acl_user'
 password column: '`password`'
 
 }


 Set<Role> getAuthorities() {
 UserRole.findAllByUser(this).collect { it.role } as Set
 }


 def beforeInsert() {
 encodePassword()
 }


 def beforeUpdate() {
 if (isDirty('password')) {
 encodePassword()
 }
 }


 protected void encodePassword() {
 password = springSecurityService.encodePassword(password)
 }

String toString(){
 return username
}
}

Copy following code in the User controller:

package access_control

import org.springframework.dao.DataIntegrityViolationException
import groovy.sql.Sql

class UserController {

 static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

 def index() {
 redirect(action: "list", params: params)
 }

 def list(Integer max) {
 params.max = Math.min(max ?: 10, 100)
 [userInstanceList: User.list(params), userInstanceTotal: User.count()]
 }

 def create() {
 String mainQu="from UserRole where user.id=0"
 def roles =UserRole.executeQuery(mainQu)
 def roleOfUsers=roles.role.id
 [userInstance: new User(params),rolesUsers : roleOfUsers]
 
 }

 def save() {
 def userInstance = new User(params)
 def roleList = params.list('roles')
 if (!userInstance.save(flush: true)) 
 {
 render(view: "create", model: [userInstance: userInstance])
 return
 }

 for (int i=0;i<roleList.size();i++) 
 {
 
 String role=roleList[i].toString()
 def RoleInstance=Role.get(role)
 
 UserRole.create userInstance, RoleInstance,true
 }

 flash.message = message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])
 redirect(action: "show", id: userInstance.id)
 }


 def show(Long id) {
 def userInstance = User.get(id)
 String mainQu="from UserRole where user.id="+ userInstance.id
 def userRoleList =UserRole.executeQuery(mainQu)
 def roleNamesOfUser=userRoleList.role.authority
 if (!userInstance) 
 {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
 redirect(action: "list")
 return
 }
 [userInstance: userInstance,roleListOfUserInstance:roleNamesOfUser,rolescount:roleNamesOfUser.size()]
 }


 def edit(Long id) {
 def userInstance = User.get(id)
 String mainQu="from UserRole where user.id="+ userInstance.id
 def userRoleList =UserRole.executeQuery(mainQu)
 String pass=userInstance.getPassword().bytes.encodeBase64() .toString()
 def roleOfUsers=userRoleList.role.id

 

 int tempv
 for (int i=0;i<roleOfUsers.size();i++){
 for (int j=i;j<roleOfUsers.size();j++){
 if (roleOfUsers[i]>roleOfUsers[j]){
 tempv=roleOfUsers[i]
 roleOfusers[i]=roleOfUsers[j]
 roleOfUsers[j]=tempv
 }
 }
 }




 if (!userInstance) 
 {

 flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
 redirect(action: "list")
 return

 }

 [userInstance: userInstance, rolesUsers:roleOfUsers]
 }


def update(Long id, Long version) {
 def userInstance = User.get(id)
 if (!userInstance) {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
 redirect(action: "list")
 return
 }

 if (version != null) {
 if (userInstance.version > version) {
 userInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
 [message(code: 'user.label', default: 'User')] as Object[],
 "Another user has updated this User while you were editing")
 render(view: "edit", model: [userInstance: userInstance])
 return
 }
 }

 userInstance.properties = params
 def roleList = params.list('roles')
 if (!userInstance.save(flush: true)) 
 {
 render(view: "edit", model: [userInstance: userInstance])
 return
 }

 UserRole.removeAll(userInstance)
 for (int i=0;i<roleList.size();i++) {
 

 String role=roleList[i].toString()
 def RoleInstance=Role.get(role)
 
 UserRole.create userInstance, RoleInstance,true
 }

 flash.message = message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])
 redirect(action: "show", id: userInstance.id)
 }


def delete(Long id) {

def userInstance = User.get(id)

if (!userInstance) {

flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])

redirect(action: "list")

return

}

try {

userInstance.delete(flush: true)

UserRole.removeAll(userInstance)

flash.message = message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), id])

redirect(action: "list")

}

catch (DataIntegrityViolationException e) {

flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'user.label', default: 'User'), id])

redirect(action: "show", id: id)

}

}

}

Copy and paste the following code in the form_view of the user:

<%@ page import="access_control.User" %>
<%@ page import="access_control.UserRole" %>

<div class="form-holder">

<table>
<tr>
 <td>
 <label for="username">
 <g:message code="user.username.label" default="User Name" />
 <span class="required-indicator">*</span>
 </label>
</td>

<td><g:textField name="username" required="" value="${userInstance?.username}"/></td>
<td>
<label for="password">
<g:message code="user.password.label" default="Password" />
<span class="required-indicator">*</span>
</label>
</td>

<% if(userInstance.id>0){%>
<g:passwordField name="Showpassword"required="" value="${userInstance?.password}"/>%{--readonly="readonly"--}%
<%}else{%>
<g:passwordField name="password"required="" value="${userInstance?.password}"/>
<%}%>
</td>
</tr>

<tr>
<td><strong>Role</strong></td>
<td><select name="roles" multiple size=5>
<g:each var="i" in="${access_control.Role.list()}" status="count">
<g:if test="${i.id==rolesUsers[count]}">
<option value="${i.id}" selected="selected">${i.authority}</option>

</g:if>

<g:else>
${count = count-1} %{--if content inside roleUsers does not match then hold count on previous index--}%
<option value="${i.id}">${i.authority}</option>
</g:else>

</g:each>
</select></td>
<td><strong>Email</strong></td>
<td><g:textField name="email" required="" value="${userInstance?.email}"/></td>

</tr>


<tr>

<td>
<label for="accountExpired">
<g:message code="user.accountExpired.label" default="Account Expired" />
</label>
</td>

<td>
<g:checkBox name="accountExpired" value="${userInstance?.accountExpired}" />
</td>

<td>
<label for="accountLocked">
<g:message code="user.accountLocked.label" default="Account Locked" />
</label>
</td>

<td>
<g:checkBox name="accountLocked" value="${userInstance?.accountLocked}" />
</td>

</tr>

<tr>
<td>
<label for="enabled">
<g:message code="user.enabled.label" default="Enabled" />
</label>
</td>

<td>
<g:checkBox name="enabled" value="${userInstance?.enabled}" />
</td>


<td>
<label for="passwordExpired">
<g:message code="user.passwordExpired.label" default="Password Expired" />
</label>
</td>

<td>
<g:checkBox name="passwordExpired" value="${userInstance?.passwordExpired}" />
</td>
</tr>

</table>
</div>

Left other views of the user domain as it is. You can create user with assigned role now.

Test by creating a Domain for setting permission for controller and menus:

  • Run project and Browse to previously created ACL_CLASS . Create a class named ‘Stock’, and keep track of its id. Which will be used later in the stock controller for permission.

Create Access_Control_Menu domain . domain will look like as below:

package access_control

import org.codehaus.groovy.grails.plugins.springsecurity.acl.AclClass

Access_Control_Menu {

 Integer id
 Role obj_role
 
 AclClass obj_acl_class
 Boolean read_val
 Boolean write_val
 Boolean edit_val
 Boolean delete_val


 static constraints = {
 }

 static mapping={
 table("step_access_controll") 
 version(false)
 id column: 'id'
 obj_role column:'role_id'
 obj_acl_class column: 'acl_class_id'

}
}

Generate controller and view for the Access_Control_Menu domain:

package access_control

import org.springframework.dao.DataIntegrityViolationException


class Access_Control_MenuController {

 static allowedMethods = [save: "POST", update: "POST", delete: "POST"]


 def index() {
 redirect(action: "list", params: params)
 }


 def list(Integer max) {
 params.max = Math.min(max ?: 10, 100)
 [access_Control_MenuInstanceList: Access_Control_Menu.list(params), access_Control_MenuInstanceTotal: Access_Control_Menu.count()]
 }


 def create() {
 [access_Control_MenuInstance: new Access_Control_Menu(params)]
 }


 def save() {
 def access_Control_MenuInstance = new Access_Control_Menu(params)
 if (params.read_val)
 access_Control_MenuInstance.read_val=1
 else
 access_Control_MenuInstance.read_val=0


 if (!access_Control_MenuInstance.save(flush: true)) {
 render(view: "create", model: [access_Control_MenuInstance: access_Control_MenuInstance])
 return
 }


 flash.message = message(code: 'default.created.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), access_Control_MenuInstance.id])
 redirect(action: "show", id: access_Control_MenuInstance.id)
 }


 def show(Long id) {

 def access_Control_MenuInstance = Access_Control_Menu.get(id)

 if (!access_Control_MenuInstance) {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "list")
 return
}
[access_Control_MenuInstance: access_Control_MenuInstance]
 }


 def edit(Long id) {
 def access_Control_MenuInstance = Access_Control_Menu.get(id)
 if (!access_Control_MenuInstance) {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "list")
 return
 }

 [access_Control_MenuInstance: access_Control_MenuInstance]

 }


 def update(Long id, Long version) {
 def access_Control_MenuInstance = Access_Control_Menu.get(id)
 if (!access_Control_MenuInstance) {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "list")
 return
 }


 if (version != null) {
 if (access_Control_MenuInstance.version > version) {
 access_Control_MenuInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
 [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu')] as Object[],
 "Another user has updated this Access_Control_Menu while you were editing")
 render(view: "edit", model: [access_Control_MenuInstance: access_Control_MenuInstance])
 return 
 }
}

 access_Control_MenuInstance.properties = params
 if (!access_Control_MenuInstance.save(flush: true)) {
 render(view: "edit", model: [access_Control_MenuInstance: access_Control_MenuInstance])
 return
 }

 flash.message = message(code: 'default.updated.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), access_Control_MenuInstance.id])
 redirect(action: "show", id: access_Control_MenuInstance.id)
 }


 def delete(Long id) {

 def access_Control_MenuInstance = Access_Control_Menu.get(id)
 if (!access_Control_MenuInstance) {
 flash.message = message(code: 'default.not.found.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "list")
 return
 }


 try {
 access_Control_MenuInstance.delete(flush: true)
 flash.message = message(code: 'default.deleted.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "list")
 }

 catch (DataIntegrityViolationException e) {
 flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'access_Control_Menu.label', default: 'Access_Control_Menu'), id])
 redirect(action: "show", id: id)
 }

}
}

Access Control Menu _form Veiw:

<%@ page import="access_control.Access_Control_Menu" %>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'obj_acl_class', 'error')} required">

<label for="obj_acl_class">

<g:message code="access_Control_Menu.obj_acl_class.label" default="Objaclclass" />

<span class="required-indicator">*</span>

</label>

<g:select id="obj_acl_class" name="obj_acl_class.id" from="${grails.plugin.springsecurity.acl.AclClass.list()}" optionKey="id" required="" value="${access_Control_MenuInstance?.obj_acl_class?.id}" class="many-to-one"/>

</div>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'obj_role', 'error')} required">

<label for="obj_role">

<g:message code="access_Control_Menu.obj_role.label" default="Objrole" />

<span class="required-indicator">*</span>

</label>

<g:select id="obj_role" name="obj_role.id" from="${access_control.Role.list()}" optionKey="id" required="" value="${access_Control_MenuInstance?.obj_role?.id}" class="many-to-one"/>

</div>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'read_val', 'error')} ">

<label for="read_val">

<g:message code="access_Control_Menu.read_val.label" default="Readval" />

 </label>

<g:checkBox name="read_val" value="${access_Control_MenuInstance?.read_val}" />

</div>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'write_val', 'error')} ">

<label for="write_val">

<g:message code="access_Control_Menu.write_val.label" default="Writeval" />

 </label>

<g:checkBox name="write_val" value="${access_Control_MenuInstance?.write_val}" />

</div>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'edit_val', 'error')} ">

<label for="edit_val">

<g:message code="access_Control_Menu.edit_val.label" default="Editval" />

</label>

<g:checkBox name="edit_val" value="${access_Control_MenuInstance?.edit_val}" />

</div>


<div class="fieldcontain ${hasErrors(bean: access_Control_MenuInstance, field: 'delete_val', 'error')} ">

<label for="delete_val">

<g:message code="access_Control_Menu.delete_val.label" default="Deleteval" />

</label>

<g:checkBox name="delete_val" value="${access_Control_MenuInstance?.delete_val}" />

</div>

Now System is ready to give permission to a particular controller using role or roles and class for the menu.

Create Domain named ‘Stock’ on a test basis, If not created already.

Hide   Copy Code

package stock

class Stock {

String item

static mapping = {
table 'stock'
version false
}


static constraints = {
item blank: false, unique: true
}

}

Create controller and views for the ‘Stock’ domain if they do not exist. Paste following code in the Stock controller:

package stock


import org.springframework.dao.DataIntegrityViolationException

import grails.plugin.springsecurity.annotation.Secured
import org.springframework.security.access.prepost.PostFilter
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.acls.domain.BasePermission
import org.springframework.security.acls.model.Permission
import org.springframework.transaction.annotation.Transactional
import grails.plugin.springsecurity.SpringSecurityUtils
import javax.servlet.http.HttpServletResponse
import access_control.Access_Control_Menu
import access_control.Role




class StockController {

def exportService
def dataSource
def grailsApplication
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
static transactional = false
def aclPermissionFactory
def aclService
def aclUtilService
def springSecurityService
static PermitRolesCreate 
static PermitRolesEdit
static PermitRolesRead
static PermitRolesDelete


def index() {

PermitRolesCreate=""
PermitRolesEdit=""
PermitRolesRead=""
PermitRolesDelete=""

def ac= Access_Control_Menu.findAll("from Access_Control_Menuas a where a.obj_acl_class.id=:classid",['classid'🙁long)526]) [526 is the ACL_CLASS id that was created earlier. Access_control_menu entries will be retrieved based on that id and all permission information will be initialized for this particular class and controller]

ac.each {
def roles=Role.findAll("from Role as r where r.id="+it.obj_role.id)
if (it.write_val==true)
PermitRolesCreate +=""+roles[0].authority+","
if (it.edit_val==true)
PermitRolesEdit +=""+roles[0].authority+","
if (it.read_val==true)
PermitRolesRead +=""+roles[0].authority+","
if (it.delete_val==true)
PermitRolesDelete +=""+roles[0].authority+","
}

redirect(action: "list", params: params)
}


 def list(Integer max) {

 if (SpringSecurityUtils.ifAnyGranted(PermitRolesRead)){ 
 params.max = Math.min(max ?: 10, 100)
 [stockInstanceList: Stock.list(params), stockInstanceTotal: Stock.count()]
 }

 else
 redirect (action: "error403", controller: "Errors")
 }


 def create() {

 if (SpringSecurityUtils.ifAnyGranted(PermitRolesCreate)){ 
 [stockInstance: new Stock(params)]
 }
 else{
 redirect (action: "error403", controller: "Errors")
 }

 }
 }

Test by trying to go to list and create page and observe the result.

Stock View: keep the views as they are.

Check Stock by browsing. Change permission and then check again whether it works according to your given permission.

Thanks

LEAVE A REPLY