From ffdf3bebd1b69ea494aa3e9bf4042972bce23f0b Mon Sep 17 00:00:00 2001 From: David Mackessy Date: Wed, 18 Dec 2024 13:20:26 +0000 Subject: [PATCH] feat: Add option to exclude ALL auth from check --- .../org/hisp/dhis/security/RequiresAuthority.java | 10 +++++++--- .../mvc/interceptor/AuthorityInterceptor.java | 13 ++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/security/RequiresAuthority.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/security/RequiresAuthority.java index bddbd150b2d6..72a388319db5 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/security/RequiresAuthority.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/security/RequiresAuthority.java @@ -37,9 +37,11 @@ * Annotation that takes in any number of {@link Authorities}. This allows us to check if a {@link * org.hisp.dhis.user.User} has any of the {@link Authorities} passed in. * - *

{@link Authorities#ALL} is automatically added to the check, as having this Authority allows - * access to all methods by default. No need to pass {@link Authorities#ALL} in the arguments. See - * {@link AuthorityInterceptor}. + *

{@link Authorities#ALL} is automatically added to the check by default, as having this + * Authority allows access to all methods by default. No need to pass {@link Authorities#ALL} in the + * arguments. See {@link AuthorityInterceptor}.
+ * {@link Authorities#ALL} will only be excluded from the check if explicitly requested, using the + * optional param `excludeAllAuth=true`. * *

Can be used at Class or Method level. Usage at the method level will always take precedence * (matching how Spring works). Class level usage only applies if there is no usage at the method @@ -50,4 +52,6 @@ @Retention(RetentionPolicy.RUNTIME) public @interface RequiresAuthority { Authorities[] anyOf(); + + boolean excludeAllAuth() default false; } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/mvc/interceptor/AuthorityInterceptor.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/mvc/interceptor/AuthorityInterceptor.java index 991c06fa7505..d687128f6648 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/mvc/interceptor/AuthorityInterceptor.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/mvc/interceptor/AuthorityInterceptor.java @@ -54,8 +54,8 @@ * the passed-in {@link org.hisp.dhis.security.Authorities}. The exception message includes the * required {@link org.hisp.dhis.security.Authorities} for the endpoint. * - *

{@link Authorities#ALL} is automatically added to the check, as having this Authority allows - * access to all methods by default. + *

{@link Authorities#ALL} is only excluded if explicitly requested. The default includes {@link + * Authorities#ALL} in the check, as this is how the system operates. */ @Component public class AuthorityInterceptor implements HandlerInterceptor { @@ -88,7 +88,7 @@ public boolean preHandle( return checkForRequiredAuthority(requiresMethodAuthority); } - // heck if RequiresAuthority is at method level + // heck if RequiresAuthority is at class level if (handlerMethod.getBeanType().isAnnotationPresent(RequiresAuthority.class)) { RequiresAuthority requiresClassAuthority = handlerMethod.getBeanType().getAnnotation(RequiresAuthority.class); @@ -98,8 +98,11 @@ public boolean preHandle( } private boolean checkForRequiredAuthority(RequiresAuthority requiresAuthority) { - // include 'ALL' authority in required authorities - List requiredAuthorities = new ArrayList<>(List.of(Authorities.ALL)); + List requiredAuthorities = new ArrayList<>(); + + // include 'ALL' authority in required authorities if not excluded + if (!requiresAuthority.excludeAllAuth()) requiredAuthorities.add(Authorities.ALL); + requiredAuthorities.addAll(List.of(requiresAuthority.anyOf())); // get user authorities