9 Replies Latest reply on Jan 26, 2012 5:00 AM by aa a

    Identity.instance().login() not possible with custom IdentityStore

    Stephanie Stroka Newbie

      Hey,


      I wrote a custom identityStore (which implements org.jboss.seam.security.management.IdentityStore, of course) and configured it in components.xml in the following way:




      <security:identity-manager identity-store="#{kiwiIdentityStore}"/>
         <security:jpa-identity-store user-class="kiwi.model.user.User" role-class="kiwi.model.user.Role"/>
         
      <!--    <security:jpa-permission-store user-permission-class="kiwi.model.security.Permission"/> -->
       
         <component name="kiwiIdentityStore"
            class="kiwi.service.user.KiWiIdentityStoreImpl" startup="true"
            scope="APPLICATION">
         </component>



      This works, I guess, since Seam does not complain about this configuration on JBoss AS startup.
      The problem that I have is that Identity.instance().login();does not work, and Identity.instance().isLoggedIn() returns false afterwards.



      The createUser(), which is implemented in the custom IdentityStore can be seen below:




      @Override
      public boolean createUser(String username, String password,
                String firstname, String lastname) {
           // create new user ...
           Query q = entityManager.createNamedQuery("currentUserFactory.getUserByLogin");
           q.setParameter("login", username);
           User user = null;
           
           try {
                q.setMaxResults(1);
                user = (User) q.getSingleResult();
           } catch(NonUniqueResultException ex) {
                log.error("User #0 exists already", username);
                return false;
           } catch(NoResultException ex) {
                user = new User(username);
                user.setResource(
                          tripleStore.createUriResource(
                                         configurationService.getBaseUri()+"/user/"+username));
                user.setType(tripleStore.createUriResource(Constants.NS_KIWI_CORE + "User"));
                user.setFirstName(firstname);
                user.setLastName(lastname);
                user.setPasswordHash(hashPassword(password, username));
                user.setEnabled(true);
                q.setHint("org.hibernate.cacheable", true);
                cacheProvider.put(username, user);
                entityManager.persist(user);
                
                if (Events.exists())
                     Events.instance().raiseEvent(EVENT_ACCOUNT_CREATED, user);
                
                return true;
           }
           return false;
      }




      Does anyone of you know why I cannot login with Seams Identity.instance().login() or what I have to change that it works?


        • 1. Re: Identity.instance().login() not possible with custom IdentityStore
          Nikolay Elenkov Master

          How is your User class annotated? I guess you derived from JpaIdentityStore, so put a breakpoint at JpaIdentityStore.authenticate() and check what exactly is happening.

          • 2. Re: Identity.instance().login() not possible with custom IdentityStore
            Tauseef Ahmed Newbie

            Hello,


            I suppose it is based on annotated User class where reference to KiWiIdentityStoreImpl.


            by the y do you want to have separate identityStore.



            Regards,


            Tauseef

            • 3. Re: Identity.instance().login() not possible with custom IdentityStore
              Stephanie Stroka Newbie

              Hey, thanks for your replies.


              My user class is annotated in the following way:


              @Entity
              @org.hibernate.annotations.Entity(optimisticLock=OptimisticLockType.VERSION)
              @Table(name = "KiWiUser",uniqueConstraints = @UniqueConstraint(columnNames = "login"))
              @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
              public class User implements Serializable { ... }



              I haven't derived the JPAIdentityStore, but my KiWiIdentityStore implements the org.jboss.seam.security.management.IdentityStore interface. The authenticate() method is called on Identity.instance().login(). It's code can be seen in the following:


              @Override
              public boolean authenticate(String username, String password) {
                   User u = null;
                   if((u = getUser(username)) != null && u.isEnabled() != false) {
                        String p = null;
                        if((p = u.getPasswordHash()) != null) {
                             if(p.equals(hashPassword(password, username))) {
                                  // send event "User Authenticated"
                                  if (Events.exists()) {
                                       Events.instance().raiseEvent(EVENT_ACCOUNT_AUTHENTICATED, u);
                                  }
                                  return true;
                             }
                        } else {
                             return false;
                        }
                   } else {
                        return false;
                   }
                   return false;
              }



              The reason why I implement my own IdentityStore is, because I have some NotNull-constraints on fields in the User class, which need to be filled out before I persist the User. And I don't want to split the User entity into two entities.

              • 4. Re: Identity.instance().login() not possible with custom IdentityStore
                Nikolay Elenkov Master

                Stephanie Stroka wrote on Feb 03, 2010 10:36:


                My user class is annotated in the following way:


                The JPA annotation are not really relevant. Show the @UserPrincipal, @UserPassword annotations.



                I haven't derived the JPAIdentityStore, but my KiWiIdentityStore implements the org.jboss.seam.security.management.IdentityStore interface. The authenticate() method is called on Identity.instance().login(). It's code can be seen in the following:


                So if your class is called, that's good. You just have to debug it to find out why it returns false. (it's your code!) You might want to simplify a bit too: if the user is not found, just return false and be done with it.





                • 5. Re: Identity.instance().login() not possible with custom IdentityStore
                  Shane Bryzak Master

                  Stephanie Stroka wrote on Feb 03, 2010 10:36:


                  The reason why I implement my own IdentityStore is, because I have some NotNull-constraints on fields in the User class, which need to be filled out before I persist the User. And I don't want to split the User entity into two entities.



                  Why don't you just write an observer for JpaIdentityStore.EVENT_PRE_PERSIST_USER to populate the other fields?  Your use case is exactly the reason why this event was created.

                  • 6. Re: Identity.instance().login() not possible with custom IdentityStore
                    Stephanie Stroka Newbie

                    @Nikolay: Thank's for your reply. For some strange reason my authorize() method returned true. Would be trivial in the other case :)


                    @Shane Thanks, this is a good hint. I tried to follow your advise, but I still have some (minor) problems. After I create a User entity, I'd like to return it. I set entityManager.flushmode to auto, called flush() after I created the user with IdentityManager.instance().getIdentityStore().createUser(...) and then tried to query the User entity, but that fails (NoResultException). Any further ideas?



                    btw: I really appreciate that someone answers me on this thread, because my statistics on unanswered questions is quite high in this forum. Thanks guys :-)

                    • 7. Re: Identity.instance().login() not possible with custom IdentityStore
                      Shane Bryzak Master

                      To get the User entity after it's created, write an observer for the JpaIdentityStore.EVENT_USER_CREATED event instead.


                      By the way, you should just be using IdentityManager.createUser() (and not through getIdentityStore() ) to create the user, otherwise you'll be skipping the security check and you'll have a security hole in your application.

                      • 9. Re: Identity.instance().login() not possible with custom IdentityStore
                        aa a Newbie
                        Hi everyone,
                        I have a problem with @Observer(JpaIdentityStore.EVENT_USER_AUTHENTICATED) annotation.

                        I'm working on a web service project and I wrote a login methon in web service class like this;

                        public boolean login(String username, String password)
                        {
                              Identity.instance().getCredentials().setUsername(username);
                              Identity.instance().getCredentials().setPassword(password);
                              Identity.instance().login();
                              return Identity.instance().isLoggedIn();
                        }

                        and I wrote in IdentityAuthenticator class:

                        @Observer(JpaIdentityStore.EVENT_USER_AUTHENTICATED)
                        public void onAuthenticated(GvnKullanici gvnKullanici)
                        {
                           try {
                             System.out.println("login");
                             Contexts.getSessionContext().set(BAGLI_KULLANICI, gvnKullanici);
                                     } catch (Exception e)
                                {
                                        // TODO: handle exception
                                        e.printStackTrace();
                                }
                                       
                        }

                        But in web service side, when Identity.instance().login(); line runs, it does not call onAuthenticated method. I think Observer annotation does not work for me. login method returns false.
                        Do you have any idea about this problem?

                        Thank you
                        Regards,

                        Özge.