In my project I use Grails 1.3.3 and Acegi security plugin 0.5.3. There's cool stuff to set action-level permission inside controller:
@Secured(['ROLE_ADMIN', 'ROLE_CHIEF_EDITOR', 'ROLE_EDITOR'])
class AdminController {
def index = { }
@Secured(['ROLE_ADMIN'])
def status = {}
@Secured(['ROLE_ADMIN'])
def controllers = {}
}
This works great but forces you to duplicate permission check in .gsp if you want to hide links from not authorized viewers. I created link taglib which checks if current user have enough permissions to access resulting action and hides . Guys who wrote Acegi plugin provided no link check and I found a way to simulate filter invocation.
package site.taglib
import org.grails.plugins.springsecurity.service.AuthenticateService
import org.springframework.security.ConfigAttributeDefinition
import org.springframework.util.StringUtils
class SecutiryTagLib {
protected static final ConfigAttributeDefinition DENY = new ConfigAttributeDefinition(Collections.emptyList());
AuthenticateService authenticateService
def securedLink = { attrs, body ->
def writer = getOut()
def elementId = attrs.remove('elementId')
def callController = attrs.controller
def callAction = attrs.action
if (!callAction) callAction = "index"
def controllerUri = "/$callController/$callAction/".toLowerCase()
ConfigAttributeDefinition configAttribute = null
Object configAttributePattern = null
def compiled = authenticateService.objectDefinitionSource.getConfigAttributeMap()
def urlMatcher = authenticateService.objectDefinitionSource.urlMatcher
def rejectIfNoRule = false
if (authenticateService.securityConfig.controllerAnnotationsRejectIfNoRule instanceof Boolean) {
rejectIfNoRule = authenticateService.securityConfig.controllerAnnotationsRejectIfNoRule
}
for (Map.Entry<Object, ConfigAttributeDefinition> entry: compiled.entrySet()) {
Object pattern = entry.getKey();
if (urlMatcher.pathMatchesUrl(pattern, controllerUri)) {
if (configAttribute == null || urlMatcher.pathMatchesUrl(configAttributePattern, (String) pattern)) {
configAttribute = entry.getValue();
configAttributePattern = pattern;
}
}
}
if (configAttribute == null && rejectIfNoRule) {
configAttribute = DENY;
}
def linkRoles = StringUtils.collectionToDelimitedString(configAttribute?.getConfigAttributes(), ',')
if (authenticateService.ifAnyGranted(linkRoles)) {
def link = createLink(attrs)
writer << "<a href=\"${link}\""
if (elementId) {
writer << " id=\"${elementId}\""
}
writer << "${attrs.collect {k, v -> " $k=\"$v\"" }.join('')}>"
writer << "${body()}</a>"
}
}
}
After this you can simply rename
g:link to
g:securedLink
<g:securedLink controller="admin" action="status ">Status</g:securedLink>