-
JSR-308, checkers framework and static analysis on GeeCON
Posted on April 26th, 2010 1 commentI’ll be speaking about the JSR-308 specification (annotations on java types), which will be part of Java 7, on the GeeCON conference, which will take place from the 13th till the 14th of May 2010 in Poznan, Poland.
Apart from an introduction to the new annotations, I will cover the checkers framework, and do a live demo of some of the bundled checkers (nullability, immutability), as well as of my typestate checker. I will also show how to implement a simple custom checker, using the framework.
If you’ll be there, be sure not to miss it. If you’ve not yet registered, visit http://2010.geecon.org :).
See you there,
Adam -
Extending the security interceptor for Weld/JSF2
Posted on April 13th, 2010 2 commentsIn my previous post, I described how to create a simple security interceptor, which checks conditions defined using EL expressions, e.g.:
@Secure("#{loggedInUser.name == arg0.name}") public List<Message> listMessages(User owner) { ... }Now, it would be nice to be able to stack such annotations, so that they can be placed:
* on methods
* on classes – then the constraint applies to all methods
* on other annotations, to create “security bindings”An example usage could be:
@Secure("#{loggedInUser != null}") public class Messages { @AdminOnly public void deleteAllMessages() { ... } @Secure("#{loggedInUser.maxMessageListCount == count}") public List<Message> listMessages(@ELVar("user") User owner, @ELVar("count") int count) { ... } }where
@AdminOnlyis defined as:@SecureBinding @Secure("#{loggedInUser.isAdministrator}") public @interface AdminOnly { }This way common security constraints can be expressed as annotations or on the class. I’m also using an improvement suggested by Dan Allen, to name the method arguments using
@ELVar, instead of naming themarg0,arg1, etc. This also allows to refer to method arguments in the “security binding” annotations, whatever the position of the argument is.How to implement such annotations? Well, the first step is to create a portable extension (meaning it will work with any CDI implementation, not just Weld), which will gather, for each method, all the
@Secureannotations, and their values, into one single annotation,@InterceptSecure. Having such a set of constraints to check for each method, we add the annotation to the method meta-data, using a utility class from Weld Extensions: theNewAnnotatedTypeBuilder. As the@InterceptSecureis an interceptor binding, the security interceptor will be called whenever the method is invoked.The extension observes the
ProcessAnnotatedTypeevent, which is fired for each bean type. If necessary, the type can be modified, to include the new annotations. The annotation is only added to Weld meta-data, not to the method itself (so there’s no bytecode manipulation or such).One last obstacle to overcome is to get the value of the generated
@InterceptSecureannotation in the interceptor. Currently this is not possible using e.g.BeanManager, but should be address in CDI Maintenance Release (see here), so as a temporary solution all the generated annotations are stored in a map in the extension. All extensions are application-scoped beans, so the information can be accessed from the interceptor. One shortcoming of the solution is that one method may belong to several, differently annotated CDI beans.The code for the annotation and extension:
@InterceptorBinding public @interface InterceptSecure { @Nonbinding String[] value(); } public class SecurityExtension implements Extension { private final Map<Method, InterceptSecure> interceptSecureForMethods = new HashMap<Method, InterceptSecure>(); public InterceptSecure getInterceptSecure(Method m) { return interceptSecureForMethods.get(m); } public <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> event) { // A flag indicating if the builder was used to modify the annotations boolean used = false; NewAnnotatedTypeBuilder<T> builder = new NewAnnotatedTypeBuilder<T>(event.getAnnotatedType()); // We need to read the values of the @Secure annotation that are present on: // 1. types (classes) // 2. methods // 3. arbitrarily nested on @SecureBinding annotations // Gathering the initial secure values from the type List<String> initialSecureValues = new ArrayList<String>(); for (Annotation annotation : event.getAnnotatedType().getAnnotations()) { collectSecureValues(annotation, initialSecureValues); } for (AnnotatedMethod<?> m : event.getAnnotatedType().getMethods()) { // Gathering the secure values from the method final List<String> values = new ArrayList<String>(initialSecureValues); collectSecureValues(m, values); // If any values have been gathered, adding the annotation to the method and storing it // in the map. if (values.size() > 0) { InterceptSecure is = new InterceptSecureImpl(values.toArray(new String[values.size()])); builder.addToMethod(m.getJavaMember(), is); used = true; interceptSecureForMethods.put(m.getJavaMember(), is); } } // Setting the new annotated type, if any changed were made if (used) { event.setAnnotatedType(builder.create()); } } private void collectSecureValues(AnnotatedMethod m, List<String> values) { for (Annotation annotation : m.getAnnotations()) { collectSecureValues(annotation, values); } } private void collectSecureValues(Annotation annotation, List<String> values) { if (Secure.class.isAssignableFrom(annotation.annotationType())) { values.add(((Secure) annotation).value()); } else { if (annotation.annotationType().getAnnotation(SecureBinding.class) != null) { for (Annotation nestedAnnotation : annotation.annotationType().getAnnotations()) { collectSecureValues(nestedAnnotation, values); } } } } private static class InterceptSecureImpl extends AnnotationLiteral<InterceptSecure> implements InterceptSecure { private final String[] values; private InterceptSecureImpl(String[] values) { this.values = values; } @Override public String[] value() { return values; } } }And for the interceptor:
@Interceptor @InterceptSecure("") public class SecurityInterceptor { @Inject private SecurityExtension se; @AroundInvoke public Object checkSecurity(InvocationContext ctx) throws Exception { // Getting the generated @InterceptSecure annotation for the method. // After the CDI Maintenance Release is released, it should be possible to get the annotated // type of the currently invoked bean, see: // http://old.nabble.com/Retrieving-the-Bean-object-for-an-interceptor-td28147499.html // For now, we just use a map in the extension. One limitation is that this doesn't allow // different security annotations for methods which are used in several beans. InterceptSecure is = se.getInterceptSecure(ctx.getMethod()); String[] toCheck = is == null ? null : is.value(); // Check the el conditions as in the previous post // (...) return ctx.proceed(); } }Adam
-
Hibernate 3.5-Final, Envers included, released!
Posted on April 1st, 2010 No commentsHibernate 3.5 was just released; congratulations to Steve and the whole team!
It’s the first final Hibernate release that includes Envers. You can find it both in the bundle downloadable from SF, as well as in the Maven repository.
Happy Easter,
Adam

