0

for the implementation of Auth.SamlJitHandler I created a person account A and a User account U which are connected using U.RoleId = A.PersonContactId. I can not avoid this step. This makes the automatic insertion happening after the execution of the JIT handler method createUser impossible. So, I created and @future method to include all those fields of User also considered "problematic" (inside my Auth.SamlJitHandler class):

@future  
public static void insertUseratFuture(  string  pFederationIdentifier, 
                                        string  pEmail, 
                                        string  pFirstName,
                                        string  pLastName,
                                        string  pLocaleSidKey,
                                        string  pLanguageLocaleKey,
                                        string  pEmailEncodingKey,
                                        string  pAlias,
                                        string  pUsername,
                                        ID      pProfileId,
                                        ID      pUserRoleId,
                                        ID      pContactId,
                                        Boolean pisActive,
                                        string  pCommunityNickname,
                                        string  pTimeZoneSidKey
                                        )
{
     User U                     = new User();

     U.FederationIdentifier     = pFederationIdentifier;    
     U.Email                    = pEmail;
     U.FirstName                = pFirstName;
     U.LastName                 = pLastName;
     U.LocaleSidKey             = pLocaleSidKey;
     U.LanguageLocaleKey        = pLanguageLocaleKey;
     U.EmailEncodingKey         = pEmailEncodingKey;
     U.Alias                    = pAlias;
     U.Username                 = pUsername;
     U.ProfileId                = pProfileId;
     U.UserRoleId               = pUserRoleId;
     U.ContactId                = pContactId;
     U.isActive                 = pisActive;
     U.CommunityNickname        = pCommunityNickname;
     system.debug('U.CommunityNickname  > ' + U.CommunityNickname);      
     U.TimeZoneSidKey = pTimeZoneSidKey;
     /* ========================================================== */   

     try {      
           system.debug('>>> User to be inserted: ' + U);
           insert U;           
      } catch (System.CalloutException e)
            {
                System.debug('Error while trying to insert an account: ' + e);                  
            }    
  }  

In test mode, calling this method at the end of the createUser() one I am able to insert the user U. But out of the test mode insertUseratFuture() is not executed in this way so the automatic insertion done after createUser() is complete takes over and after trying to insert the same user U returned by the createUser() command the system hangs giving me a SAML error message.

a) Is it possible to change the behavior of salesforce after the createUser method is over? I wish it cold be possible to make it @future one or to do something to have no problems inserting U. b) Is it possible to delay the execution of whatever comes after createUser() is over to allow insertUseratFuture() to insert U? c) Any other alternatives?

Thanks

This the method I am using to create the account. It is in the same class that implements Auth.SamlJitHandler. We are not using update at all. Per requirements, we are forced to create and update User and PersonAccount objects

  private Id handleAccount(boolean create, User u, Map<String, String> attributes) {

    RecordType personAccountRecordType =  [SELECT Id FROM RecordType WHERE Name = 'Person Account' and SObjectType = 'Account'];

    Account a;

    boolean newAccount = false;

    if(create) {

          system.debug('In HanldeAccount, inserting a new account');

          a = new Account();
          newAccount = true;

    } else {

    }

     if (attributes.containsKey('User.firstname')){
        a.firstName = attributes.get('User.firstname');
     }


     if (attributes.containsKey('User.lastname')){
       a.LastName = attributes.get('User.lastname');
     } 


     a.RecordType = personAccountRecordType;
     system.debug('RecordType : ' + a.RecordType);



    if(newAccount) {

      try {      
           system.debug('Account to be inserted: ' + a);
           insert(a);
           system.debug('Account inserted: ' + a);
           system.debug('isPersonAccount = ' + a.IsPersonAccount);
           system.debug('Person Contact Id : ' + a.PersonContactId);
           system.debug('Recortype again: ' + a.recordtype);
           system.debug('Queried record: ' + [select isPersonAccount, PersonContactId  FROM account where ID =: a.Id]);

      } catch (System.CalloutException e)
            {
                System.debug('Error while trying to insert an account: ' + e);  

            }

    } else {
      // update(a);
    }
    return a.Id;
  }

I am adding the two methods I use to define a user. We have just one community:

  private void handleUser(boolean create, User u, Map<String, String> attributes,
    String federationIdentifier, boolean isStandard) {
    System.debug('In handleUser');
    if(create) {
      if(attributes.containsKey('User.FederationIdentifier')) {
        u.FederationIdentifier = attributes.get('User.FederationIdentifier');
        system.debug('Assigned FedID if key in SAML = ' + u.FederationIdentifier);  
      } else {
        u.FederationIdentifier = federationIdentifier;
         system.debug('Assigned FedID if key NOT in SAML = ' + u.FederationIdentifier);
      }
    }

    if(attributes.containsKey('User.email')) {
      u.Email = attributes.get('User.email');

      System.debug('User email: ' + u.Email);
    }
    if(attributes.containsKey('User.firstname')) {
      u.FirstName = attributes.get('User.firstname');
      System.debug('User FirstName: ' + u.FirstName);
    }
    if(attributes.containsKey('User.lastname')) {
      u.LastName = attributes.get('User.lastname');
      System.debug('User LastName: ' + u.LastName);
    }    

    String uid = UserInfo.getUserId();
    User currentUser = 
      [SELECT LocaleSidKey, LanguageLocaleKey, TimeZoneSidKey, EmailEncodingKey FROM User WHERE Id=:uid];
    if(attributes.containsKey('User.LocaleSidKey')) {
      u.LocaleSidKey = attributes.get('User.LocaleSidKey');
    } else if(create) {
      u.LocaleSidKey = currentUser.LocaleSidKey;
    }
    if(attributes.containsKey('User.LanguageLocaleKey')) {
      u.LanguageLocaleKey = attributes.get('User.LanguageLocaleKey');
    } else if(create) {
      u.LanguageLocaleKey = currentUser.LanguageLocaleKey;
    }
    if(attributes.containsKey('User.Alias')) {
      u.Alias = attributes.get('User.Alias');
    } else if(create) {
      String alias = '';
      if(u.FirstName == null) {
        alias = u.LastName;
      } else {
        alias = u.FirstName.charAt(0) + u.LastName;
      }
      if(alias.length() > 5) {
        alias = alias.substring(0, 5);
      }
      u.Alias = alias;
    }

    System.debug('Alias = ' + u.Alias);

    if(attributes.containsKey('User.TimeZoneSidKey')) {
      u.TimeZoneSidKey = attributes.get('User.TimeZoneSidKey');
    } else if(create) {
      u.TimeZoneSidKey = currentUser.TimeZoneSidKey;
    }
    if(attributes.containsKey('User.EmailEncodingKey')) {
      u.EmailEncodingKey = attributes.get('User.EmailEncodingKey');
    } else if(create) {
      u.EmailEncodingKey = currentUser.EmailEncodingKey;
    }

    /*
     * If you are updating Contact or Account object fields, you cannot update the following User fields at the same time.
     * If your identity provider sends these User fields as attributes along with Contact 
     * or Account fields, you must modify the logic in this class to update either these 
     * User fields or the Contact and Account fields.
     */


    //Handle custom fields here

    system.debug('User' + u);

    if(!create) {
      update(u);
    }
  }

The other method is:

  private void handleUserConflictingData(boolean create, User u, Map<String, String> attributes, 
                                         String federationIdentifier, boolean isStandard,
                                         Id communityId)
  {
        /*
     * If you are updating Contact or Account object fields, you cannot update the following User fields at the same time.
     * If your identity provider sends these User fields as attributes along with Contact 
     * or Account fields, you must modify the logic in this class to update either these 
     * User fields or the Contact and Account fields.
     /*
       Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing:
        [Username, CommunityNickname, ProfileId]: [Username, CommunityNickname, ProfileId]    

     */

       // It was created an account JOSECCZJIT FORJIT to gather the information of the profileId and UseroleID as
       // the role is dynamically created depending on the user that this script will be running on

      u.username = attributes.get('User.email');  /*  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ 

      user qU = new User(); 
      qU = [select name, UserRoleId, profileId from user where name = 'JOSECCZJIT FORJIT'];

      u.ProfileId  = qU.profileId;      
      system.debug('Profile Id: ' + u.ProfileId);

      u.UserRoleId = qU.UserRoleId;
      system.debug('Role Id: ' + u.UserRoleId);

      u.isActive = true;  
      u.CommunityNickname = '' + communityId; 

      // system.debug('User License ID: ' + [select userlicenseid from Profile where id=: u.ProfileId]);

  }

Here it is the function that established the relationship between user and personAccount:

 private void handleJit(boolean create, User u, Id samlSsoProviderId, Id communityId, Id portalId,
    String federationIdentifier, Map<String, String> attributes, String assertion) {
    if(communityId != null || portalId != null) {

      Id accountId = handleAccount(create, u, attributes);

      system.debug('Queried record again: ' + [select FirstName, LastName, isPersonAccount, CTSC_Sponsored_Biostats_Hours__c, PersonContactId  FROM account where ID =: accountId]);

      u.ContactId = [select PersonContactId  FROM account where ID =: accountId].PersonContactId;     
      // Notice the use of PersonContactId at the end of the previous command. I had Id instead and getting
      // the  
      //  10:34:29:496 FATAL_ERROR System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, Contact ID: id value of incorrect type: 0015500000Es8udAAB: [ContactId]
      // error


      system.debug('u.ContactId: ' + u.ContactId);



      // handleContact(create, account, u, attributes);
      System.debug('----------- community or portal');
      System.debug('User = ' + u);
      System.debug('federationId = ' + federationIdentifier);
      System.debug('attributes = ' + attributes);  
      System.debug('Create = ' + create);

      handleUser(create, u, attributes, federationIdentifier, false);



      handleUserConflictingData(create, u, attributes, federationIdentifier, false, communityId);  /* ******Conflicts? ********* */


      System.debug('---------- end of community or portal');  
    } else {
      //System.debug('not community and not portal');  
      //  handleUser(create, u, attributes, federationIdentifier, true);
    }
  }
  • How are you creating the Person Account? Are you creating the contact first. the account first or all in one step using a RecordType of person account? What kind of user are you creating? Customer Community users don't have a Role. That could be the source of your issue unless perhaps this a Community Plus or Partner Community License. – crmprogdev May 12 '16 at 15:34
  • Ok, so you've shown me how you're creating your person acct. You've still not answered the questions about the type of user and community. – crmprogdev May 13 '16 at 15:03
  • Please, see the code I added, We use just one community – Jose Cabrera Zuniga May 13 '16 at 16:04
  • Again, what Community License Type do you have? Without that information, no one here can help you. For example, a customer community DOES NOT use Roles for its Users but needs to be created by a Salesforce User that does have a Role! A Community User should be connected to Contact via a ContactId which will have an AccountId field on it. That's how you can traverse the relationships. – crmprogdev May 13 '16 at 16:34
  • We have Customer Community Plus login... thanks a lot!! – Jose Cabrera Zuniga May 13 '16 at 16:46
0

Well, this is a solution I found... kind of orthodox one. The createUser function will return an object W that has its federation id equal to the one of the new truly user. W will be one kind of dummy user that is already in the database. This will allow me to bypass the SAML error. After this is done, the database will run the @future method to save the information of the truly new user U (with some modifications in its federationId and/or other needed fields). Later, I will update W and U so they have the correct information like proper federationId. W will be a dummy user all the time.Any other suggestions or comments are welcome! Thanks Jose

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.