10 Replies Latest reply on Nov 17, 2010 7:37 AM by gabrielsr

    How to get the authenticated user in Drools

      Hello,


      I have loggedUser object in the session context. I want to use some of the logged user properties in my drools rools, but how? How can I put loggedUser session object into drools working memory??


      Please, could anybody provide any axamples? I'm stacked with it.


      Regards


      Jarek

        • 1. Re: How to get the authenticated user in Drools
          stefanotravelli

          Declare your session-scoped object as a global variable in the rule using the name of the object as the variable name.


          This doesn't put your object in the working memory, but you can write a rule that accesses it and make an insert(), if needed.



          stefano


          • 2. Re: How to get the authenticated user in Drools

            Hi Stefano,


            i'm new to Drools and its concept is still a bit fuzzy form me.
            Could you provide an examle of declaring global variabe using session object?


            Thanks


            Jarek

            • 3. Re: How to get the authenticated user in Drools
              stefanotravelli

              Drools has the concept of global variables. It's well defined in the Drools documentation, but the basic is that this variables are set to some value when the working memory is created.


              With the Seam Drools integration usually you don't create working memories because they are managed by the RuleBase (or the RuleAgent) component.


              However Seam managed working memories come with a special GlobalResolver (see org.jboss.seam.drools.SeamGlobalResolver) that resolves seam context variables as Drools globals (from Javadoc).


              So you simply declare the global:



              package mypackage
              import com.something.User
              global User loggedUser
              
              rule "check logged user"
                dialect "mvel"
                when
                  eval(loggedUser.name == "stefano")
                then
                  ... do something
              end
              




              The global variable loggedUser will be resolved from Seam contexts, just like when you type @In(value = "loggedUser") in a regular Java class.


                 


              • 4. Re: How to get the authenticated user in Drools

                Hi Stefano,


                Thanks a lot for the hint. But still I have some problems.


                I have rool like this


                package Permissions;
                
                import java.security.Principal;
                
                import org.jboss.seam.security.permission.PermissionCheck;
                import org.jboss.seam.security.Role; 
                
                import pl.unizeto.webrbe.model.User;
                
                global pl.unizeto.webrbe.model.User loggedUser;
                
                rule UserList
                     no-loop
                     dialect "mvel"
                when
                     perm: PermissionCheck(name == "user", action == "list", granted == false)
                     //eval("USER" memberOf loggedUser.dataAccessTypes)
                     //eval(loggedUser.username == "admin")
                     eval(true);
                then
                     System.out.println("DEBUG - loggedUser = " + loggedUser); // for debug
                     perm.grant();


                end


                loggedUser has a factory like this


                @Factory(value = "loggedUser", autoCreate = true)
                public User getLoggedUser() {
                ...
                }



                UserList.page.xml has restriction like


                <restrict>#{s:hasPermission('user', 'list')}</restrict>



                but loggedUser is always null. After going to UserList.xhtml page i got

                DEBUG - loggedUser = null



                Why? Is there something i missed??


                Uncomenting


                eval(loggedUser.username == "admin")



                couse


                Exception during request processing:
                Caused by javax.el.ELException with message: "org.drools.RuntimeDroolsException: org.mvel.CompileException: unable to resolve property: username"



                but it's perhapse of loogedUser been null


                Regards


                Jarek


                • 5. Re: How to get the authenticated user in Drools
                  stefanotravelli

                  You are right. My fault.


                  SeamGlobalResolver is not used by RuleBasedPermissionResolver, so the global variable is not resolved.


                  It would seem reasonable to me to use SeamGlobalResolver even in the RuleBasedPermissionResolver as it is in ManagedWorkingMemory. Maybe we should ask for such a feature to the Seam team.


                  In the meanwhile you can get your component from the Seam contexts using a function. Something like:


                   
                  package Permissions;
                  
                  import java.security.Principal;
                  
                  import org.jboss.seam.security.permission.PermissionCheck;
                  import org.jboss.seam.security.Role; 
                  
                  import pl.unizeto.webrbe.model.User;
                  import org.jboss.seam.Component;
                  
                  global pl.unizeto.webrbe.model.User loggedUser;
                  
                  
                  function boolean isAdmin()
                  {
                     User loggedUser = Component.getInstance("loggedUser", true);
                     return "admin".equals(loggedUser.getUsername());
                  }
                  
                  rule UserList
                       no-loop
                       dialect "mvel"
                  when
                       perm: PermissionCheck(name == "user", action == "list", granted == false)
                       //eval("USER" memberOf loggedUser.dataAccessTypes)
                          eval(isAdmin())
                       //eval(true);
                  then
                       System.out.println("DEBUG - loggedUser = " + loggedUser); // for debug
                       perm.grant();




                  However, I assume this is only a sample. If your use case really need only the user name, then you can get it from the Principal that is inserted in the working memory together with all the Roles of the current user.



                  rule "r"
                  when
                    principal: Principal(name == "admin")
                    perm: PermissionCheck(name == "user", action == "list", granted == false)
                  then
                    perm.grant();
                  end
                  



                  stefano

                  • 6. Re: How to get the authenticated user in Drools

                    Thanks Stefano. You helped me a lot.


                    I created the JIRA issue for this: https://jira.jboss.org/jira/browse/JBSEAM-3877


                    Jarek

                    • 7. Re: How to get the authenticated user in Drools

                      Stefano one more question if you mind:


                      How to write my own resolver to inject some context variables (for ex loggedUser :) ) into drools workin memory every time drools rools are checked?


                      Jarek

                      • 8. Re: How to get the authenticated user in Drools

                        I think i found the solution.


                        In an authenticate() function of Autenticator component i've added:


                        ...
                        // put the logged user into drools working memory
                        RuleBasedPermissionResolver resolver = RuleBasedPermissionResolver.instance();
                        if(resolver != null) {
                             resolver.getSecurityContext().insert(user);
                        }
                        ...
                        



                        and now rools is simple as


                        rule UserList
                             no-loop
                             dialect "mvel"
                        when
                             user: User()
                             perm: PermissionCheck(name == "user", action == "list", granted == false)
                             eval("USER" memberOf user.dataAccessTypes)
                        then
                             perm.grant();
                        end
                        



                        That's it. Thanks again Stefano.


                        Jarek

                        • 9. Re: How to get the authenticated user in Drools

                          The above solution is not the right way, becouse we can get 'lazy initialization' exception (user entity is disconnected from entitymanager).


                          I've done another trick which proves that using SeamGlobalResolver is RuleBasedPermissionResolver is the right way.


                          Fisrt: i copy SeamGlobalResolver.java source from SEAM to my application action package. I have to because SeamGlobalResolver class is private for org.jboss.seam.drools package.


                          Second: in Authenticator component i have added:


                          @Observer(Identity.EVENT_POST_AUTHENTICATE)
                          public void setUserAccountInSecurityContext() {
                               // Add Seam context variables resolver as Drools globals
                               // Look here: http://www.seamframework.org/Community/HowToGetTheAuthenticatedUserInDrools
                               // and here: https://jira.jboss.org/jira/browse/JBSEAM-3877 
                               RuleBasedPermissionResolver resolver = RuleBasedPermissionResolver.instance();
                               resolver.getSecurityContext().setGlobalResolver(
                                    new SeamGlobalResolver(resolver.getSecurityContext().getGlobalResolver()));
                          }
                          



                          Now this rool (with global) is workin perfect:


                          package Permissions;
                          
                          import java.security.Principal;
                          
                          import org.jboss.seam.security.permission.PermissionCheck;
                          import org.jboss.seam.security.Role; 
                          import org.jboss.seam.Component;
                          
                          import pl.unizeto.webrbe.model.User;
                          import pl.unizeto.webrbe.model.DataAccessTypeEnum;
                          
                          global pl.unizeto.webrbe.model.User loggedUser;
                          
                          dialect "mvel"
                          
                          rule UserList
                               no-loop
                          when
                               perm: PermissionCheck(name == "user", action == "list", granted == false)
                               
                               eval(loggedUser.dataAccessTypes contains DataAccessTypeEnum.USER)
                               //for dialect "java" (default) it should be
                               //eval(loggedUser.getDataAccessTypes().contains(DataAccessTypeEnum.USER))
                          then
                               perm.grant();
                          end
                          



                          Jarek

                          • 10. Re: How to get the authenticated user in Drools
                            gabrielsr

                            Thanks, with the issue was correct in Seam 2.1, now you can just insert a user into the context:


                            public boolean authenticate() {
                            ...                                                     Contexts.getSessionContext().set(usuarioLogado, usuario);
                            }


                            and take it with a global var in drools:


                            global br.com.esec.licenca.model.Usuario usuarioLogado;



                            • )