I don't know if this is a sweet solution, but an alternative would be to create your own @Restrict annotation with a @Nonbinding value (as Shane said), but use @InterceptorBinding instead of @SecurityBindingType. Then, create an interceptor class like this:
@Interceptor
@Restrict("")
public class RestrictInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
@AroundInvoke
public Object invoke(InvocationContext ctx) throws Exception {
Restrict restrict = getRestrictAnnotation(ctx.getMethod());
String value = restricao.value();
//now your EL or whatever is in value var
}
private Restrict getRestrictAnnotation(Method m) {
for (Annotation a: m.getAnnotations()) {
if (a instanceof Restrict) { return (Restrict) a; }
}
return null;
}
PS.: don't forget to include the interceptor in the beans.xml.
I still don't know if it's the best way to do, but I made it, based on your suggestion :
InterceptorBinding :
{code}
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Restrict {
@Nonbinding String value();
}
{code}
Interceptor (Using Solder to resolve EL expressions.):
{code}
@Restrict("")
@Interceptor
public class RestrictInterceptor implements Serializable {
transient @Inject
Expressions expressions;
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception {
Restrict restrict = getRestrictAnnotation(ctx.getMethod());
String value = restrict.value();
try {
Boolean hasPermission = expressions.<Boolean>evaluateValueExpression(value);
if (hasPermission) {
return ctx.proceed();
} else {
throw new AuthorizationException("Following expression evaluated to false : \"" + value + "\"");
}
} catch (ELException e) {
throw new AuthorizationException(e.getMessage());
}
}
private Restrict getRestrictAnnotation(Method m) {
for (Annotation a : m.getAnnotations()) {
if (a instanceof Restrict) {
return (Restrict) a;
}
}
return null;
}
}
{code}
Usage example :
{code}
@Restrict("#{permissions.has('users', 'create')}")
public String createUser() {
...
}
{code}
The "permissions" EL name refer to a custom bean that encapsulate calls to "identity.hasPermission(Object, String)" and caches the result in the request scope.
I do this because I cannot control how many time a sigle permission check will be made in JSF. ie, the following code will call many time the permission check ( I think I counted about 6 time) :
{code}
<h:commandLink action="#{userAction.createUser}" value="Create New User" rendered="#{identity.hasPermission('users', 'create')}"/>
{code}
I use Rule based security (with drools).
Just wanted to share a "complete" example.