7 Replies Latest reply on May 28, 2014 12:37 PM by vwjugow

    IDM not persisting. Custom Authenticator and model.

    vwjugow

      Hi,

      I am trying to get picketlink working in my application. It uses Errai, so I'm using the picketlink jar provided by Errai Security.

      I've implemented a custom Authenticator, and it authenticates ok, and when I do identity.getAccount() it returns me the logged in user.

      But I would like to use Roles as well, and I figured that for that I need the IDM (correct me if I'm wrong in anything please, I don't quite understand how best to implement picketlink and what exactly needs to be done.)

       

      I'm not using Picketlink default Entities like User, because I wanted to maintain my model. So I've extended some of the entities with custom ones.

      For instance:

       

      package com.magick.models.shared;
      
      public class UserImpl extends  org.picketlink.idm.model.basic.User {
      
      
          private com.magick.models.shared.User user; //My model User
      
      
          public UserImpl() {}
      
      
          public UserImpl(com.magick.models.shared.User user){ 
              this.user = user;
              setEnabled(true); // True! as we don't have the notion of enabled account right now
              setLastName(user.getLastName());
              setFirstName(user.getFirstName());
              setEmail(user.getId());//hack to have the id.
              setId(user.getId());//we can't retrieve this later..
              setLoginName(user.getUsername());
          }
      
      
          public com.magick.models.shared.User getUser(){
             return user;
          }
      }
      

       

      I've done the same as above for Role class.

       

      Then I've copied all these classes from Picketlink to my project:

      AbstractCredentialTypeEntity, AccountTypeEntity, AttributedTypeEntity, AttributeTypeEntity, DigestCredentialTypeEntity, GroupTypeEntity, IdentityTypeEntity, OTPCredentialTypeEntity, PartitionTypeEntity, PasswordCredentialTypeEntity, RelationshipIdentityTypeEntity, RelationshipTypeEntity, RoleTypeEntity, X509CredentialTypeEntity

      And added them to my persistence.xml like this:

       

      <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
                   version="2.0">
      
         <persistence-unit name="pu-magick" transaction-type="RESOURCE_LOCAL"> <!-- TODO: JTA -->
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            
           <jta-data-source>java:jboss/datasources/magick</jta-data-source>
      
            <class>com.magick.models.shared.User</class>
      ...
           <class>com.magick.models.shared.Symbol</class>
      
             <class>com.magick.models.security.AttributedTypeEntity</class>
             <class>com.magick.models.security.AccountTypeEntity</class>
             <class>com.magick.models.security.RoleTypeEntity</class>
             <class>com.magick.models.security.GroupTypeEntity</class>
             <class>com.magick.models.security.IdentityTypeEntity</class>
             <class>com.magick.models.security.RelationshipTypeEntity</class>
             <class>com.magick.models.security.RelationshipIdentityTypeEntity</class>
             <class>com.magick.models.security.PartitionTypeEntity</class>
             <class>com.magick.models.security.PasswordCredentialTypeEntity</class>
             <class>com.magick.models.security.AttributeTypeEntity</class>
      
      

       

      Then I have this class:

       

      public class PicketlinkResources {
        @Produces
        @PicketLink
        @PersistenceContext(unitName = "pu-magick")
        private EntityManager em;
      
      
      }
      

       

      And finally, my custom authenticator:

       

       

      @PicketLink
      public class MagickAuthenticator extends BaseAuthenticator {
      
      @Inject
          DefaultLoginCredentials loginCredentials;
      
          @Inject
          private PartitionManager partitionManager;
      
          @Inject
          private UserDAO userDAO;
      
          @Override
          public void authenticate() {
              String userId = loginCredentials.getUserId();
              String password = loginCredentials.getPassword();
              User user = userDAO.fetchUserByName(userId);
              if (!BCrypt.checkpw(password, user.getPasswordHash())) {
                  setStatus(AuthenticationStatus.FAILURE);
              } else {
                  UserImpl account = new UserImpl(user);
                  setStatus(AuthenticationStatus.SUCCESS);
                  setAccount(account); //sets the account to identity
      
                  //HERE I TRY TO ADD USER TO IDM
      
                final IdentityManager identityManager = partitionManager.createIdentityManager();
      
                IdentityQuery<UserImpl> query = identityManager.createIdentityQuery(UserImpl.class);
                
                query.setParameter(UserImpl.LOGIN_NAME, user.
      
      
                List<UserImpl> result = query.getResultList();
                org.picketlink.idm.model.basic.Role trial = new org.picketlink.idm.model.basic.Role("TRIAL");
                
                if (result.isEmpty()){
                     identityManager.add(account); //SHOULDN't THIS PERSIST SOMETHING TO DB ?
                     identityManager.updateCredential(account, new Password(password));
      
                     //final RelationshipManager relationshipManager = partitionManager.createRelationshipManager();
                }
      
      
                //Since I've added the user to IDM, let's try if it would authenticate using IDM and not cheking password manually          
                Credentials creds = new UsernamePasswordCredentials(user.getUsername(), new Password(password));
                identityManager.validateCredentials(creds);
                if (Credentials.Status.VALID.equals(creds.getStatus())) {
                     logger.info("YUUUUUUUUUUUUUWHOOOOOOOOOOOOOOOOOOOOOOO");//NEVER GETS CALLED
                }
      
      
           }
      
      
      
      

       

      So after running that code, nothing get's persisted to my database, though the tables were created automatically.

       

      One last detail, the persistence.xml, authenticator, PicketlinkResources reside in my UI project, and all the Entities in a separate jar.

       

      I'm pretty sure I'm doing several things wrong, could you point me in the right direction ? I tried reading documentation, but I get a little lost.

        • 1. Re: IDM not persisting. Custom Authenticator and model.
          pcraveiro

          Hi,

           

               Would like to understand better your use case first.

           

              First of all, why you need a custom authenticator for what you're doing ? Asking because most of your code is already provided OOTB by PicketLink's IdmAuthenticator.

           

             Another thing you should look at is how your custom model is mapped with the PicketLink JPA Annotations. If you just copied the classes from picketlink-idm-simple-schema, please make sure that you changed each entity class to reflect their corresponding IdentityType. You can do that by looking the @IdentityManaged annotation defined on each of them. For example, your AccountTypeEntity, would probably have a @IdentityManaged(UserImpl.class) definition.

           

          Regards.

          • 2. Re: IDM not persisting. Custom Authenticator and model.
            vwjugow

            Hi Pedro,

            we made a custom Authenticator so we could use our own User class and to check the password with BCrypt.

             

            I've already fixed the mappings, thanks for that. However it's still not persisting anything.

            • 3. Re: IDM not persisting. Custom Authenticator and model.
              pcraveiro

              Hey Victor,

               

              If that is the only reason, you don't need to write a custom authenticator. The IdmAuthenticator still can be used.

               

              In order to get your custom type recognized, you just need to set this credential property when building the configuration:

               

              {code}

              builder

                   .named("default.config")

                     .stores()

                          .jpa()

                           .setCredentialHandlerProperty(PasswordCredentialHandler.SUPPORTED_ACCOUNT_TYPES_PROPERTY, MyUser.class)

              {code}

               

              If you want a example, check here picketlink-quickstarts/picketlink-angularjs-rest/src/main/java/com/gr/project/security/SecurityConfiguration.java at tok….

               

              Regarding BCrypt, you can also provide different encoders for passwords. Take a look here for all available properties: 4.4. Built-in Credential Handlers.

               

              Regards.

              • 4. Re: Re: IDM not persisting. Custom Authenticator and model.
                vwjugow

                Pedro,

                So I've added this:

                 

                   @Produces
                    IdentityConfiguration createConfig() {
                        if (identityConfig == null) {
                            initConfig(null);
                        }
                        return identityConfig;
                    }
                

                 

                public void initConfig(IdentityConfigurationBuilder builder){
                      if (builder == null){
                        builder = new IdentityConfigurationBuilder();
                       }
                
                builder.named("default.config").stores().jpa().mappedEntity(
                                 PartitionTypeEntity.class,//
                                    AccountTypeEntity.class,
                                    RoleTypeEntity.class,
                                    GroupTypeEntity.class,
                                    IdentityTypeEntity.class,
                                    RelationshipTypeEntity.class,
                                 RelationshipIdentityTypeEntity.class,//
                                    PasswordCredentialTypeEntity.class,
                                    AttributeTypeEntity.class,
                                 UserImpl.class,
                                 UserRoleImpl.class)
                                .supportGlobalRelationship(Relationship.class)
                                .addContextInitializer(this.contextInitializer)
                  .setCredentialHandlerProperty(PasswordCredentialHandler.SUPPORTED_ACCOUNT_TYPES_PROPERTY, UserImpl.class)
                                .supportAllFeatures();
                
                identityConfig = builder.build();
                
                

                 

                Now I get an exception when authenticating in PicketlinkAuthenticationService:84

                Here's the stacktrace: http://pastebin.com/igprrzr6

                 

                I do have

                @IdentityManaged (UserRoleImpl.class)

                @Entity

                public class RoleTypeEntity extends IdentityTypeEntity {

                 

                So I don't know why it's saying it's not mapped

                • 5. Re: Re: IDM not persisting. Custom Authenticator and model.
                  pcraveiro

                  Hey Victor,

                   

                      Please, remove the UserRoleImpl and UserImpl from the list of mapped entities (jpa().mappedEntity). As they are not JPA entities, but your custom identity types.

                   

                  Regards.   

                  • 6. Re: Re: Re: IDM not persisting. Custom Authenticator and model.
                    vwjugow

                    Ok, I removed it, but I don't understand because in the example you gave it adds the custom entites to the jpa().

                     

                    Anyways, I'm now getting this http://pastebin.com/5mXGP0zd when trying to authenticate.

                     

                    This is my EntityManager producer.

                     

                    @ApplicationScoped
                    public class PicketlinkResources {
                        @PersistenceContext(unitName = "pu-picketlink")
                        private EntityManager em;
                    
                    
                      @Produces
                      @PicketLink
                      public EntityManager getEntityManager(){
                           return em;
                      }
                    }
                    

                     

                    I have this class

                     

                    @IdentityManaged (Partition.class)
                    @Entity
                    public class PartitionTypeEntity extends AttributedTypeEntity {
                    
                    
                        private static final long serialVersionUID = -3619372498444894118L;
                    
                    
                        @AttributeValue
                        private String name;
                        @PartitionClass
                        private String typeName;
                    
                        @ConfigurationName
                        private String configurationName;
                    
                    
                    

                     

                    And I've added that to jpa()

                     

                    public void initConfig(IdentityConfigurationBuilder builder){
                          if (builder == null){
                            builder = new IdentityConfigurationBuilder();
                      }
                    
                    builder.named("default").stores().jpa().mappedEntity(
                      PartitionTypeEntity.class,//
                                        AccountTypeEntity.class,
                                RoleTypeEntity.class,
                                        GroupTypeEntity.class,
                                        IdentityTypeEntity.class,
                                        RelationshipTypeEntity.class,
                      RelationshipIdentityTypeEntity.class,//
                                        PasswordCredentialTypeEntity.class,
                                        AttributeTypeEntity.class)
                    
                    
                                    .supportGlobalRelationship(Relationship.class)
                                    .addContextInitializer(this.contextInitializer)
                      .setCredentialHandlerProperty(PasswordCredentialHandler.SUPPORTED_ACCOUNT_TYPES_PROPERTY, UserImpl.class)
                                    .supportAllFeatures();
                            identityConfig = builder.build();
                    

                     

                    Thanks for all the help so far Pedro.

                    • 7. Re: Re: IDM not persisting. Custom Authenticator and model.
                      vwjugow

                      I think I managed to fix the EntityManager errors. Now I'm getting http://pastebin.com/v2AvGd7P  when doing partitionManager.createIdentityManager(); in my MagickAuthenticator. I'm working on getting a simplified project so you can take a look

                       

                      EDIT:

                      here's a sample: https://bitbucket.org/vwjugow/picketlink-issue/

                       

                      There's two maven project there. you first need to compile the "-extra" project with 'mvn clean install'

                      And then the other one with 'mvn install -Dmaven.test.skip=true -Denvironment=dev -Pjetty" //If you preffer jboss use -Pjboss7

                      And then run with 'mvn gwt:run -Denvironment=dev -Dapp.build=333 -Dapp.revision=asd -Pjetty' //If you preffer jboss use -Pjboss7

                       

                      let me know if you can run them and see same exception. Thanks

                       

                      EDIT2:

                      Don't know if you'll have trouble with the datasources, since you don't have the database :/