You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by cm...@apache.org on 2012/09/07 16:35:43 UTC

svn commit: r1382051 - /incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext

Author: cmoulliard
Date: Fri Sep  7 14:35:43 2012
New Revision: 1382051

URL: http://svn.apache.org/viewvc?rev=1382051&view=rev
Log:
Add JPA and Security documentation

Modified:
    incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext

Modified: incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext
URL: http://svn.apache.org/viewvc/incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext?rev=1382051&r1=1382050&r2=1382051&view=diff
==============================================================================
--- incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext (original)
+++ incubator/deltaspike/site/trunk/content/deltaspike/modules.mdtext Fri Sep  7 14:35:43 2012
@@ -23,7 +23,458 @@ Notice:    Licensed to the Apache Softwa
 
 # Security
 
+## SecurityBinding for class and method invocations
+
+This feature of the security module functions by intercepting method calls, and performing a security check before invocation is allowed to proceed.
+
+In order to use the DeltaSpike security module, you must first have installed the proper dependencies into your POM file. Once this is complete, you may proceed to create a security parameter binding annotation. This is what we will use to add security behavior to our business classes and methods.
+
+    Create the SecurityBinding
+    @Retention(value = RUNTIME)
+    @Target({TYPE, METHOD})
+    @Documented
+    @SecurityBindingType
+    public @interface CustomSecurityBinding {
+    }
+
+Next, we must define an Authorizer class to implement behavior for our custom SecurityBindingType. This class is simply a CDI bean which declares a @Secures method, qualified with the security binding annotation we created in the first step.
+
+This method has access to the InvocationContext of the method call, so if we need to access parameter arguments, we can do so using the given context. Note that we may also inject other beans into the parameter list of our @Secures method.
+
+    Create the Authorizer
+    @ApplicationScoped
+    public class CustomAuthorizer
+    {
+        @Secures
+        @CustomSecurityBinding
+        public boolean doSecuredCheck(InvocationContext invocationContext, BeanManager manager, @LoggedIn User user) throws Exception
+        {
+            return user.isLoggedIn(); // perform security check
+        }
+    }
+
+We can then use our new annotation to secure business or bean methods. This binding annotation may be placed on the entire class (securing all methods,) or on individual methods that you wish to secure.
+
+    Secure a bean method
+    @ApplicationScoped
+    public class SecuredBean1
+    {
+        @CustomSecurityBinding
+        public void doSomething(Thing thing)
+        {
+            thing.doSomething();
+        }
+    }
+
+Next, we may access parameter values from the method invocation directly in our authorizer bean by creating custom @SecurityParameterBinding types; this is a simple step once we have completed the work above:
+
+    Create a parameter binding annotation
+    @Retention(value = RUNTIME)
+    @Target({PARAMETER})
+    @Documented
+    @SecurityParameterBinding
+    public @interface CurrentThing {
+    }
+
+Now, when a secured method is invoked, we can inject actual parameter values as arguments into our authorizer method, providing domain-level security in our applications:
+
+    Update the Authorizer to use parameter binding
+    @ApplicationScoped
+    public class CustomAuthorizer
+    {
+        @Secures
+        @CustomSecurityBinding
+        public boolean doSecuredCheck(InvocationContext invocationContext, BeanManager manager, @LoggedIn User user, @CurrentThing Thing thing) throws Exception
+        {
+            return thing.hasMember(user); // perform security check against our method parameter
+        }
+    }
+
+Note that our business method must also be annotated.
+
+    Complete the parameter binding
+    @ApplicationScoped
+    public class SecuredBean1
+    {
+        @CustomSecurityBinding
+        public void doSomething(@CurrentThing Thing thing)
+        {
+            thing.doSomething();
+        }
+    }
+
+Our method is now secured, and we are able to use given parameter values as part of our security authorizer!
+
+## Integrating 3rd party security frameworks
+
+### @Secured
+
+{{@Secured}} is build on {{@SecurityBindingType}} and a very simple alternative to the rest of the security module.
+It's a basic hook to integrate a custom security concept, 3rd party frameworks,... . It doesn't provide a full blown security concept like the rest of the security module, but other DeltaSpike modules ensure that the security concepts are integrated properly (e.g. correct behaviour within custom scope implementations,...). It just allows to integrate other security frameworks easily.
+
+(In MyFaces CODI it was originally a CDI interceptor. This part changed a bit, because between the interceptor and {{@Secured}} is the {{@SecurityBindingType}} concept which triggers {{@Secured}} as on possible approach. Therefore the basic behaviour remains the same and you can think about it like an interceptor.)
+
+    Securing all intercepted methods of a CDI bean
+    //...
+    @Secured(CustomAccessDecisionVoter.class)
+    public class SecuredBean
+    {
+        //...
+    }
+
+or
+
+    Securing specific methods
+    //...
+    public class SecuredBean
+    {
+        @Secured(CustomAccessDecisionVoter.class)
+        public String getResult()
+        {
+            //...
+        }
+    }
+
+### AccessDecisionVoter
+
+This interface is (besides the {{Secured}} annotation) the most important part of the concept. Both artifact types are also the only required parts.
+
+    public class CustomAccessDecisionVoter implements AccessDecisionVoter
+    {
+        @Override
+        public Set<SecurityViolation> checkPermission(AccessDecisionVoterContext accessDecisionVoterContext)
+        {
+            Method method = accessDecisionVoterContext.<InvocationContext>getSource().getMethod();
+
+            //...
+        }
+    }
+
+[TODO] hint about the changed parameter/s
+
+### SecurityViolation
+
+In case of a detected violation a {{SecurityViolation}} has to be added to the result returned by the {{AccessDecisionVoter}}.
+
+[TODO] AbstractAccessDecisionVoter
+
+### @Secured and Stereotypes with custom Meta-data
+
+If there are multiple {{AccessDecisionVoter}} and maybe in different constellations, it's easier to provide an expressive CDI stereotypes for it. Later on that also allows to change the behaviour in a central place.
+
+    Stereotype support of @Secured}
+    @Named
+    @Admin
+    public class MyBean implements Serializable
+    {
+      //...
+    }
+
+    //...
+    @Stereotype
+    @Secured(RoleAccessDecisionVoter.class)
+    public @interface Admin
+    {
+    }
+
+Furthermore, it's possible to provide custom meta-data easily.
+
+    Stereotype of @Secured with custom meta-data}
+    @Named
+    @Admin(securityLevel=3)
+    public class MyBean implements Serializable
+    {
+      //...
+    }
+
+    //...
+    @Stereotype
+    @Secured(RoleAccessDecisionVoter.class)
+    public @interface Admin
+    {
+      int securityLevel();
+    }
+
+    @ApplicationScoped
+    public class RoleAccessDecisionVoter implements AccessDecisionVoter
+    {
+        private static final long serialVersionUID = -8007511215776345835L;
+
+        public Set<SecurityViolation> checkPermission(AccessDecisionVoterContext voterContext)
+        {
+            Admin admin = voterContext.getMetaDataFor(Admin.class.getName(), Admin.class);
+            int level = admin.securityLevel();
+            //...
+        }
+    }
+{code}
+
+## AccessDecisionVoterContext
+
+[TODO]
+
+## SecurityStrategy SPI
+
+[TODO]
+
 # JPA
 
+## @Transactional
+
+This annotation is an alternative to transactional EJBs which allows to execute a method within a transaction.
+Before it's possible to start using the annotation, it's required to implement a CDI producer for an {{EntityManager}} and it's needed to inject the {{EntityManager}} in the bean which uses {{@Transactional}}. As shown later on it's also possible to use multiple qualifiers for using different {{EntityManager}}s.
+
+The following example shows a simple producer for an {{EntityManager}} and the corresponding dispose-method.
+Producing it as request scoped bean means that the dispose method will be called on finishing the request.
+As an alternative it's possible to use a special scope called {{@TransactionScoped}} provided by the same DeltaSpike module.
+
+    Producer for the default EntityManager
+    //...
+    public class EntityManagerProducer
+    {
+        //or manual bootstrapping
+        @PersistenceContext
+        private EntityManager entityManager;
+
+        @Produces
+        @RequestScoped
+        protected EntityManager createEntityManager()
+        {
+            return this.entityManager;
+        }
+
+        protected void closeEntityManager(@Disposes EntityManager entityManager)
+        {
+            if (entityManager.isOpen())
+            {
+                entityManager.close();
+            }
+        }
+    }
+
+The following examples show how to use the {{EntityManager}} produced by the example above.
+
+    Beans with transactional method
+    //...
+    public class TransactionalBean
+    {
+        @Inject
+        private EntityManager entityManager;
+
+        @Transactional
+        public void executeInTransaction()
+        {
+            //...
+        }
+    }
+
+    Simple transactional bean (all methods transactional)
+    //...
+    @Transactional
+    public class TransactionalBean
+    {
+        @Inject
+        private EntityManager entityManager;
+
+        //...
+    }
+
+As illustrated in the following example it's also possible to use {{@Transactional}} for stereotypes.
+
+    Stereotype for transactional beans (+ usage)
+    @Stereotype
+    @Transactional
+    @ApplicationScoped
+    public @interface Repository
+    {
+    }
+
+    //...
+    @Repository
+    public class TransactionalBean
+    {
+        @Inject
+        private EntityManager entityManager;
+
+        //...
+    }
+
+Besides such simple usages, it's also supported to use qualifiers to access multiple persistence-units in parallel.
+The default qualifier for {{@Transactional}} is {{@Any}}. Therefore a transaction for every injected entity manager will be started.
+The example afterwards shows how to change this default behaviour.
+
+    Producer for multiple entity managers (+ usage)
+    //...
+    public class EntityManagerProducer
+    {
+        @PersistenceContext(unitName = "firstDB")
+        private EntityManager firstEntityManager;
+
+        @PersistenceContext(unitName = "secondDB")
+        private EntityManager secondEntityManager;
+
+        @Produces
+        @First
+        @RequestScoped
+        protected EntityManager createFirstEntityManager()
+        {
+            return this.firstEntityManager;
+        }
+
+        protected void closeFirstEntityManager(@Disposes @First EntityManager entityManager)
+        {
+            if (firstEntityManager.isOpen())
+            {
+                firstEntityManager.close();
+            }
+        }
+
+        @Produces
+        @Second
+        @RequestScoped
+        protected EntityManager createSecondEntityManager()
+        {
+            return this.secondEntityManager;
+        }
+
+        protected void closeSecondEntityManager(@Disposes @Second EntityManager entityManager)
+        {
+            if (secondEntityManager.isOpen())
+            {
+                secondEntityManager.close();
+            }
+        }
+    }
+
+
+    //...
+    public class FirstLevelTransactionBean
+    {
+        @Inject
+        private @First EntityManager firstEntityManager;
+
+        @Inject
+        private NestedTransactionBean nestedTransactionBean;
+
+        @Transactional
+        public void executeInTransaction()
+        {
+            //...
+            this.nestedTransactionBean.executeInTransaction();
+        }
+    }
+
+    //...
+    public class NestedTransactionBean
+    {
+        @Inject
+        private @Second EntityManager secondEntityManager;
+
+        @Transactional
+        public void executeInTransaction()
+        {
+            //...
+        }
+    }
+
+The following example shows how to use only the specified {{EntityManager}}/s
+
+    Activating entity managers manually
+    public class MultiTransactionBean
+    {
+        @Inject
+        private EntityManager defaultEntityManager;
+
+        @Inject
+        private @First EntityManager firstEntityManager;
+
+        @Inject
+        private @Second EntityManager secondEntityManager;
+
+        @Transactional(qualifier = Default.class)
+        public void executeInDefaultTransaction()
+        {
+        }
+
+        @Transactional(qualifier = First.class)
+        public void executeInFirstTransaction()
+        {
+        }
+
+        @Transactional(qualifier = Second.class)
+        public void executeInSecondTransaction()
+        {
+        }
+
+        @Transactional(qualifier = {First.class, Second.class})
+        public void executeInFirstAndSecondTransaction()
+        {
+        }
+    }
+
+All examples also work with nested calls. In the following example the transaction handling is done on the entry point (after FirstLevelTransactionBean#executeInTransaction).
+
+    Joining existing transaction in nested call
+    //...
+    public class FirstLevelTransactionBean
+    {
+        @Inject
+        private EntityManager entityManager;
+
+        @Inject
+        private NestedTransactionBean nestedTransactionBean;
+
+        @Transactional
+        public void executeInTransaction()
+        {
+            this.nestedTransactionBean.executeInTransaction();
+        }
+    }
+
+    //...
+    public class NestedTransactionBean
+    {
+        @Inject
+        private EntityManager entityManager;
+
+        @Transactional
+        public void executeInTransaction()
+        {
+            //...
+        }
+    }
+
+The final transaction handling for all {{EntityManager}} s is also done after the outermost transactional method if {{NestedTransactionBean}} uses a different {{EntityManager}}.
+So it's possible to catch an exception in {{FirstLevelTransactionBean}} e.g. to try an optional path instead of an immediate rollback.
+
+## @TransactionScoped
+
+{{@Transactional}} also starts a context which is available as long as the transaction started by {{@Transactional}}. Besides other beans you can use this scope for the {{EntityManager}} itself. That means the {{EntityManager}} will be closed after leaving the method annotated with {{@Transactional}}.
+
+    Producer for the default EntityManager which should be used only for one transaction
+    //...
+    public class EntityManagerProducer
+    {
+        //or manual bootstrapping
+        @PersistenceContext
+        private EntityManager entityManager;
+
+        @Produces
+        @TransactionScoped
+        protected EntityManager createEntityManager()
+        {
+            return this.entityManager;
+        }
+
+        protected void closeEntityManager(@Disposes EntityManager entityManager)
+        {
+            if (entityManager.isOpen())
+            {
+                entityManager.close();
+            }
+        }
+    }
+
+