From 28d43901dccf45bf1cedd9783f2cbab0a1a0b7cd Mon Sep 17 00:00:00 2001 From: davidbairdala Date: Tue, 15 Jul 2014 15:58:14 +1000 Subject: [PATCH] AlaSecured annotations can now be applied to "property" style controller actions, including webflow actions --- AlaWebThemeGrailsPlugin.groovy | 2 +- application.properties | 4 +- grails-app/conf/BuildConfig.groovy | 2 +- .../au/org/ala/web/AlaSecuredFilters.groovy | 59 +++++++++++++------ src/java/au/org/ala/web/AlaSecured.java | 2 +- 5 files changed, 45 insertions(+), 24 deletions(-) diff --git a/AlaWebThemeGrailsPlugin.groovy b/AlaWebThemeGrailsPlugin.groovy index f1d7758..6d5051e 100644 --- a/AlaWebThemeGrailsPlugin.groovy +++ b/AlaWebThemeGrailsPlugin.groovy @@ -4,7 +4,7 @@ import grails.util.Holders class AlaWebThemeGrailsPlugin { // the plugin version - def version = "0.8" + def version = "0.8.1" // the version or versions of Grails the plugin is designed for def grailsVersion = "2.1 > *" // the other plugins this plugin depends on diff --git a/application.properties b/application.properties index a9035c1..1270b09 100644 --- a/application.properties +++ b/application.properties @@ -1,5 +1,5 @@ #Grails Metadata file -#Thu May 15 09:16:05 EST 2014 -app.grails.version=2.3.8 +#Tue Jul 15 14:07:18 EST 2014 +app.grails.version=2.3.11 app.name=ala-web-theme app.servlet.version=2.5 diff --git a/grails-app/conf/BuildConfig.groovy b/grails-app/conf/BuildConfig.groovy index c0a5dde..9614300 100644 --- a/grails-app/conf/BuildConfig.groovy +++ b/grails-app/conf/BuildConfig.groovy @@ -41,7 +41,7 @@ grails.project.dependency.resolution = { plugins { runtime ":jquery:1.7.1" runtime ":resources:1.2.1" - compile(":tomcat:7.0.50", + compile(":tomcat:7.0.54", ":release:3.0.1") { export = false } diff --git a/grails-app/conf/au/org/ala/web/AlaSecuredFilters.groovy b/grails-app/conf/au/org/ala/web/AlaSecuredFilters.groovy index 327f3c4..7425659 100644 --- a/grails-app/conf/au/org/ala/web/AlaSecuredFilters.groovy +++ b/grails-app/conf/au/org/ala/web/AlaSecuredFilters.groovy @@ -23,27 +23,48 @@ class AlaSecuredFilters { } String methodName = actionName ?: "index" + // The action annotation may be applied to either a method or a property + AlaSecured actionAnnotation = null + // Look for a method on the controller whose name matches the action... Method method = cClazz.getMethods().find { method -> method.name == methodName && Modifier.isPublic(method.getModifiers()) } - AlaSecured ca = cClazz.getAnnotation(AlaSecured) - AlaSecured ma = method?.getAnnotation(AlaSecured) - AlaSecured sa = ma ?: ca - if (sa) { + if (method) { + actionAnnotation = method.getAnnotation(AlaSecured) + } else { + // if a method could not be found, look for a property (private field) on the class, for when actions are declared in this style: + // def action = { ... } + def field = cClazz.declaredFields.find { it.name == methodName } + // If a field could not be found, it may be a spring web flow action, so look for that (name suffixed with "Flow")... + if (!field) { + def target = "${methodName}Flow" + field = cClazz.declaredFields.find { it.name == target } + } + + if (field) { + actionAnnotation = field.getAnnotation(AlaSecured) + } + } + + // Action annotations trump class annotations + AlaSecured classAnnotation = cClazz.getAnnotation(AlaSecured) + AlaSecured effectiveAnnotation = actionAnnotation ?: classAnnotation + + if (effectiveAnnotation) { boolean error = false - if (sa.value()) { - if (sa.anyRole() && sa.notRoles()) { + if (effectiveAnnotation.value()) { + if (effectiveAnnotation.anyRole() && effectiveAnnotation.notRoles()) { throw new IllegalArgumentException("Only one of anyRole and notRoles should be specified") } - def roles = sa.value().toList() + def roles = effectiveAnnotation.value().toList() - if (sa.anyRole() && !securityPrimitives.isAnyGranted(roles)) { + if (effectiveAnnotation.anyRole() && !securityPrimitives.isAnyGranted(roles)) { error = true - } else if (sa.notRoles() && !securityPrimitives.isNotGranted(roles)) { + } else if (effectiveAnnotation.notRoles() && !securityPrimitives.isNotGranted(roles)) { error = true - } else if (!sa.anyRole() && !securityPrimitives.isAllGranted(roles)) { + } else if (!effectiveAnnotation.anyRole() && !securityPrimitives.isAllGranted(roles)) { error = true } } else { @@ -51,25 +72,25 @@ class AlaSecuredFilters { } if (error) { - if (sa.message()) { - flash.errorMessage = sa.message() + if (effectiveAnnotation.message()) { + flash.errorMessage = effectiveAnnotation.message() } if (params.returnTo) { redirect(url: params.returnTo) - } else if (sa.statusCode() != 0) { - render(status: sa.statusCode()) - } else if (sa.redirectUri()) { - redirect(uri: sa.redirectUri()) + } else if (effectiveAnnotation.statusCode() != 0) { + render(status: effectiveAnnotation.statusCode()) + } else if (effectiveAnnotation.redirectUri()) { + redirect(uri: effectiveAnnotation.redirectUri()) } else { - def redirectController = sa.redirectController() + def redirectController = effectiveAnnotation.redirectController() if (!redirectController) { - if (!ma) { + if (!actionAnnotation) { log.warn('Redirecting to the current controller with a Controller level @AlaSecured, this is likely to result in a redirect loop!') } redirectController = controllerName } - redirect(controller: redirectController, action: sa.redirectAction()) + redirect(controller: redirectController, action: effectiveAnnotation.redirectAction()) } return false } diff --git a/src/java/au/org/ala/web/AlaSecured.java b/src/java/au/org/ala/web/AlaSecured.java index 2129379..1141578 100644 --- a/src/java/au/org/ala/web/AlaSecured.java +++ b/src/java/au/org/ala/web/AlaSecured.java @@ -8,7 +8,7 @@ * * @author Simon Bear (simon.bear@csiro.au) */ -@Target({ElementType.TYPE, ElementType.METHOD}) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited