3 Replies Latest reply on Apr 27, 2009 5:51 PM by Radu B

    IdentityManager : useful for non default use case ?

    Gaël Beaudoin Newbie

      Hi !


      We're starting to port our seam 2.0 application over to seam 2.1. The major change is seam security and its new nifty API.


      We have it working with a default JpaIdentityStore and JpaPermissionStore mapped to our old entities. So far, so good.


      We've started to look at the seamspace example to look how to use the IdentityManager class. And as we understand it, it only covers really basic use-case as everything is based on string-based users (as oposed to Class / Template based one). Our user class has many more fields than those covered by the create method and UserAction class. So we can't use the IdentityManager methods neither UserAction class to create or delete users.


      Creating our own IdentityManager isn't that of a problem, but I found it quite surprising that we can't make better use of the provided IdentityManager. Moreover, the UserAction class can only be used in applications that doesn't need anything more than firstname, lastname and username (IMHO, almost anyone needs more ?).


      I would have thought of something like IdentityManager.createUser(Object user) where Object implements an interface or a base seam User class, or anything that let us have custom User class and still being able to use the IdentityManager for CRUD operations.


      So ... either we've not understood the code entirely, either we have to go our own way. What do you think ? What do you suggest ?

        • 1. Re: IdentityManager : useful for non default use case ?
          Shane Bryzak Master

          You can extend UserAction to include additional fields if you need them.  Also, if you're using JpaIdentityStore, then it raises the event org.jboss.seam.security.management.prePersistUser before persisting the user entity, giving you the opportunity to set additional fields on the entity object before persisting to the database.  You simply need to add an observer for this event to your extended UserAction component, and set the additional field values there.

          • 2. Re: IdentityManager : useful for non default use case ?
            Thiago F. Crepaldi Newbie

            You can extend UserAction to include additional fields if you need them. Also, if you're using JpaIdentityStore, then it raises the event org.jboss.seam.security.management.prePersistUser before persisting the user entity, giving you the opportunity to set additional fields on the entity object before persisting to the database. You simply need to add an observer for this event to your extended UserAction component, and set the additional field values there.

            Hello, Shane, that is exactly what i am looking for, but all I can find is WHAT i should do to get those extra fields in my user form, not exactly HOW.


            I did:



            @Observer("org.jboss.seam.security.management.prePersistUser")
            public void onPrePersist(User user) {
                      
            }
            
            @Observer("org.jboss.seam.security.management.userCreated")
            public void onUserCreated(User user) {
            
            }




            and that's all i got.
            How do I persist my email extra field extending UserAction ?


            if i code



            <h:outputLabel for="email" value="Email" styleClass="formLabel"/>
            <h:inputText id="email" value="#{userAction.email}" readonly="#{identityManager.userExists(userAction.email)}"/>
            <h:message for="email" styleClass="validationError"/>




            i got a problem, since userAction doesn't have this field.


            So, how to display fulfilled fields when an user try to view/update it ?


            Thiago

            • 3. Re: IdentityManager : useful for non default use case ?
              Radu B Newbie

              I also spent one day with this issue.
              I wanted a way to add user account confirmation and to use the default forms generated by seam-get, UserAccountHome and UserAccountList with all my custom fields and without much modifications to the xhtml files.
              I have relations with another tables in my UserAccount component, so I can not use UserAction class.


              The easiest solution for me was to create a method in UserAccountHome class which will:



              • check for password confirmation

              • call identityManager.createUser(getInstance().getUsername(), password) (you will have the entity persisted after this call)

              • call identityManager.grantRole(getInstance().getUsername(), role);

              • retrieve the new user from the database: UserAccount userAccount = userAccountDAO.findUser(usernameSaved, false, false);

              • set your new fields as wanted (like userAccount.setActivationCode(activationCode);)

              • persist the user with the new values (getEntityManager().persist(userAccount);)



              You will need to add the fieleds private List<String> roles, private String password and private String confirm to your UserAccountHome class and use them in UserAccountEdit.xhtml (instead of userAccountHome.instance.roles)


              The save button will call userAccountHome.save method


              Code example:


              @Name("userAccountHome")
              public class UserAccountHome extends EntityHome<UserAccount> {
              ....
                  @In IdentityManager identityManager;
                  
                  @In UserAccountDAO userAccountDAO;
              
                  private List<String> roles;
                  private String password;
                  private String confirm;
              ....
              
                  public String save() {             
                       
                       if ((getInstance() == null) || (getInstance().getUsername().trim().length() < 2) || (identityManager.userExists(getInstance().getUsername()))) {
                          FacesMessages.instance().addToControl("username", "Failed to create user");
                          log.debug("user '{0}' already exists", getInstance().getUsername());
                          
                          return "failure";              
                       }
                       
                       String usernameSaved = getInstance().getUsername();
                       boolean isEnabled = getInstance().isEnabled();
                       boolean isActivated = getInstance().isActivated();         
                       
                      if (!password.equals(confirm)) {
                         FacesMessages.instance().addToControl("password", "Passwords do not match");
                         log.debug("Password do not match: {0} - {1}", password, confirm);
                         
                         return "failure";
                      }
                      
                      boolean success = identityManager.createUser(usernameSaved, password);
                      log.info("User created: {0}", usernameSaved);
                              
                      if (success) {
                         for (String role : roles) {
                            identityManager.grantRole(usernameSaved, role);
                            log.info("Adding role to user {0}: {1}", usernameSaved, role);
                         }
                         
                         if (!isEnabled || !isActivated) {
                            identityManager.disableUser(usernameSaved);   
                         }
                      
                         Date currentDate = new Date();
                         
                         String raw = "md5".concat(getInstance().getUsername()).concat(currentDate.toString());
                         String activationCode = DigestUtils.md5Hex(raw);        
                         
                         log.info("Setting activation code to: {0}", usernameSaved);
                         
                         // Retrieve back entity saved by identityManager and set additional values
                         
                         UserAccount userAccount = userAccountDAO.findUser(usernameSaved, false, false);
                         
                         userAccount.setActivationCode(activationCode);
                         userAccount.setActivated(isActivated);
                         
                         this.getEntityManager().persist(userAccount);
                         
                         this.clearInstance();
                         
                             return "success";
                      }
                      
                      return "failure";
                       
                  }
              ....
              



              Example of UserAccountEdit.xhtml


              ....
                              <s:decorate id="usernameField" template="/layout/edit.xhtml">
                                  <ui:define name="label">Username</ui:define>
                                  <h:inputText id="username" value="#{userAccountHome.instance.username}" readonly="#{identityManager.userExists(userAccountHome.instance.username)}"/>
                              </s:decorate>
              
                              <s:decorate id="passwordField" template="/layout/edit.xhtml">
                                  <ui:define name="label">Password</ui:define>
                                  <h:inputSecret id="password" value="#{userAccountHome.password}"/>
                              </s:decorate>
              
                              <s:decorate id="confirmPasswordField" template="/layout/edit.xhtml">
                                  <ui:define name="label">Confirm Password</ui:define>
                                  <h:inputSecret id="confirm" value="#{userAccountHome.confirm}"/>
                              </s:decorate>
                              
                              <s:decorate id="rolesField" template="/layout/edit.xhtml">
                                  <ui:define name="label">Member of roles</ui:define>
                                  <div class="selectMany">
                                      <h:selectManyCheckbox id="roles" value="#{userAccountHome.roles}" layout="pageDirection" styleClass="roles">
                                          <s:selectItems value="#{identityManager.listGrantableRoles()}" var="_role" label="#{_role}"/>
                                      </h:selectManyCheckbox>
                                  </div>
                              </s:decorate>
              
                              <s:decorate id="enabledField" template="/layout/edit.xhtml">
                                  <ui:define name="label">Account enabled</ui:define>
                                  <h:selectBooleanCheckbox id="enabled" value="#{userAccountHome.instance.enabled}"/>
                              </s:decorate>            
              ....
              
              <h:commandButton id="save"
              value="Save"
              action="#{userAccountHome.save}"
              rendered="#{!identityManager.userExists(userAccountHome.instance.username)}"/>
              



              I hope this will save someone time...