5 Replies Latest reply on Feb 13, 2011 8:05 PM by Nikolay Elenkov

    Extend JpaIdentityStore

    Hristo Mitkov Newbie

      Hello,
      I'm trying to use IdentityManagement in my application but I need to extend JpaIdentityStore and override it's method public Object lookupUser(String username). In this method I need to look for users in the database not only by 'username' but also by additional field 'organization.
      The problem is that in IdentityManager.initIdentityStore() the field identityStore is initialized with Seam's built-in component.
      This is my class:



      @Name("org.jboss.seam.security.identityStore")
      @Install(precedence = Install.APPLICATION, value = false)
      @Scope(ScopeType.APPLICATION)
      @BypassInterceptors
      public class JpaIdentityStore extends org.jboss.seam.security.management.JpaIdentityStore {
           public Object lookupUser(String username) {
                try {
                     EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
                     Object user = entityManager.createQuery("select u from UserAccount u where username = :username and organization = :organization")
                     .setParameter("username", username)
                     .setParameter("organization", Identity.instance().getCredentials()).getOrganization())
                     .getSingleResult();
                     
                     return user;
                } catch (NoResultException ex) {
                     return null;
                }
           }





      The code :



      identityStore = (IdentityStore) Component.getInstance(JpaIdentityStore.class, true); 




      returns the built-in component org.jboss.seam.security.management.JpaIdentityStore and my custom lookupUser(String username) is never called.


      I tried to override the IdentityManager class.
       



      @Scope(EVENT)
      @Name("org.jboss.seam.security.identityManager")
      @Install(precedence = Install.APPLICATION)
      @BypassInterceptors
      public class IdentityManager extends org.jboss.seam.security.management.IdentityManager {
           public boolean authenticate(String username, String password) {
                if (Strings.isEmpty(username))
                     return false;
                IdentityStore identityStore = (IdentityStore) Component.getInstance("myIdentityStore",true);
                return identityStore.authenticate(username, password);
           }





      and give the name myIdentityStore to my custom JpaIdentityStore class.
      (Interestingly in this case in method IdentityManager.instance() the code :



      (IdentityManager) Component.getInstance(IdentityManager.class, EVENT);



      returns my custom IdentityManager)
           
           This way my custom lookupUser method is called during user authentication but the problem this time is that fields: IdentityManager.identityStore and IdentityManager.roleIdentityStore are again initialized with seam's built-in JpaIdentityStore. This happens in IdentityManager.initIdentityStore() where Component.getInstance(JpaIdentityStore.class, true);  returns org.jboss.seam.security.management.JpaIdentityStore


      Can anyone help me!? How can I extend JpaIdentityStore and just override it's lookupUser method and make the login module use it? And how Component.getInstance(JpaIdentityStore.class); can return an instance of my subclass?


      Thank you

        • 1. Re: Extend JpaIdentityStore
          Nikolay Elenkov Master

          Hristo Mitkov wrote on Aug 10, 2009 16:38:


          The code :


          identityStore = (IdentityStore) Component.getInstance(JpaIdentityStore.class, true); 



          returns the built-in component org.jboss.seam.security.management.JpaIdentityStore and my custom lookupUser(String username) is never called.



          You need to install your custom IdentityStore in components.xml to get this to work. Cf. this code from IdentityManager.java:


          protected void initIdentityStore()
          {    
             // Default to JpaIdentityStore
             if (identityStore == null)
             {
                identityStore = (IdentityStore) Component.getInstance(JpaIdentityStore.class, true);
             }
          ...
          



          If there is already an IdentityStore configured, it will be used as is and the code above not executed.


          HTH

          • 2. Re: Extend JpaIdentityStore
            Marco Mancuso Newbie

            Hello, i'm trying to do something similar. I have to add a method to the IdentityStore, so i extended this interface:


            public interface IdentityStore extends org.jboss.seam.security.management.IdentityStore{
                 
                 public List<String> listRoles(String filter);
            
            }
            



            and the JpaIdentityStore to implement my listRoles(String filter): 




            @Name("it.manage.action.interfaces.identityStore")
            @Install(precedence = Install.APPLICATION, value = false)
            @Scope(APPLICATION)
            @BypassInterceptors
            public class JpaIdentityStore extends
                      org.jboss.seam.security.management.JpaIdentityStore {
            
                 /**
                  * 
                  */
                 private static final long serialVersionUID = -647636212618363493L;
            
                 public JpaIdentityStore() {
                      super();
                 }
            
                 
                 public List<String> listRoles(String filter) {
                      return lookupEntityManager().createQuery(
                 "select r.name from " + getRoleClass().getName() + " r"
                 + "where lower(name) like :rolename").setParameter("rolename","%" + (filter != null ? filter.toLowerCase() : "") + "%").getResultList();
            
                 }
            
                 private EntityManager lookupEntityManager() {
                      return (EntityManager) getEntityManager().getValue();
                 }
                 
                 @Override
                 public Class getUserClass() {           
                         return UserAccount.class;
                 }
                 
                 @Override
                 public Class getRoleClass() {
                         return Role.class;
                 }
                 
                 @Override
                 public Object lookupUser(String arg0) {         
                         return super.lookupUser(arg0);
                 }
                 
                 @Override
                 public boolean authenticate(String username, String password) {
                         
                         return super.authenticate(username, password);
                 }
            }



            Is it right the @Name i gave to the JpaIdentityStore class?


            In the components.xml i put:



            <security:identity-manager installed="true"  identity-store="#{jpaIdentityStore}" />



            Should i change something else in this file?


            When i use my UserManager i try to get my IdentityStore with




            identityStore = (IdentityStore) Component.getInstance(JpaIdentityStore.class, true);



            (where JpaIdentityStore is my class) I receive a null Object, instead the identityStore of
            the IdentityManager is an org.jboss.seam.security.management.JpaIdentityStore object.


            What's wrong?


            Thank you!


            • 3. Re: Extend JpaIdentityStore
              Nikolay Elenkov Master

              Marco Mancuso wrote on Aug 11, 2009 15:28:


              Is it right the @Name i gave to the JpaIdentityStore class?



              If you want to override the built-in component, you have to use the same name, namely:


              @Name("org.jboss.seam.security.identityManager")
              



              If you want to have your own implementation, without overriding the default one, you should
              use a different name and reflect that in components.xml:



              <security:identity-manager installed="true"  identity-store="#{myIdentityStore}" />



              HTH

              • 4. Re: Extend JpaIdentityStore
                Beyaz  Newbie

                This works;


                @Name("org.jboss.seam.security.identityStore")
                @Install(precedence = Install.APPLICATION, value = false)
                @Scope(ScopeType.APPLICATION)
                @BypassInterceptors
                public class JpaIdentityStoreExtended extends org.jboss.seam.security.management.JpaIdentityStore {
                     public boolean authenticate(String username, String password) {
                          System.out.println("**** In Extended JpaIdentityStore");
                          return super.authenticate(username, password);
                     }
                }



                and in components.xml



                 <security:jpa-identity-store class="org.seam.security.JpaIdentityStoreExtended"
                   user-class="org.seam.security.User"
                   role-class="org.seam.security.Role"/>




                • 5. Re: Extend JpaIdentityStore
                  Nikolay Elenkov Master

                  Beyaz   wrote on Feb 11, 2011 16:24:


                  This works;

                   <security:jpa-identity-store class="org.seam.security.JpaIdentityStoreExtended"
                     user-class="org.seam.security.User"
                     role-class="org.seam.security.Role"/>






                  Probably, but not such a good idea to put your stuff in the org.seam.security package.