Details
-
Bug
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
1.5.1
-
None
-
Weld 2.2.15.Final
Description
Short Overview of What I'm trying to Do
I'm trying to make a CDI-based equivalent of javax.annotation.security.RolesAllowed that uses my custom ROLE enum.
@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) @Inherited @Stereotype @Secured(MyRoleAccessDecisionVoter.class) public @interface MyRolesAllowed { ROLE[] value(); } @RequestScoped public class MyRoleAccessDecisionVoter extends AbstractAccessDecisionVoter { @Inject private Principal principal; @Override protected void checkPermission(AccessDecisionVoterContext voterContext, Set<SecurityViolation> violations) { // get the roles from the annotation ROLE[] rolesAllowed = voterContext.getMetaDataFor(MyRolesAllowed.class.getName(), MyRolesAllowed.class).value(); // BUG ABOVE! it'll have class-level annotation instead of the method-level annotation } } @MyRolesAllowed({ADMIN, ROOT, USER}) @Stateless public class TestBean { @MyRolesAllowed({ADMIN, ROOT}) public List<String> getWhatever() { return ImmutableList.of(); } }
My Thoughts
It looks like org.apache.deltaspike.security.impl.authorization.SecuredAnnotationAuthorizer is where the bug is.
It parses both method- and class-level annotations in extractMetadata(), in that order (method first, then class).
Then that data gets passed to DefaultAccessDecisionVoterContext.addMetaData(), which puts it in a HashMap.
Because the order is method-first, that entry in the map gets overwritten by the class-level info.
Workaround
Use AccessDecisionVoterContext.getSource().getMethod().getAnnotationsByType() and use the annotation's value, if any.
InvocationContext context = voterContext.getSource(); // get the metadata from the method, only required if using DS <= 1.5.1 MyRolesAllowed[] methodLevelAnnotations = context.getMethod().getAnnotationsByType(MyRolesAllowed.class); if(methodLevelAnnotations.length != 0) { rolesAllowed = methodLevelAnnotations[0].value(); } else { // get the roles from the class-level annotation, if available rolesAllowed = voterContext.getMetaDataFor(MyRolesAllowed.class.getName(), MyRolesAllowed.class).value(); }