3

I started reading about the RegistrationHandler interface but that is designed to allow the overall authentication and User creation process to be varied.

In a Community, users can self-register (where they are tied to an Account and Profile as part of the self-registration process) and I want to assign several permission sets when they do. Based on the Profile and Permission Objects ERD it looks like adding PermissionSetAssignment records in a User trigger would do the job. Are there any gotchas with that approach?

Here is one inconclusive post on the subject Apex to Assign Skuid License and Permission Set.

PS

Duh access rights may get in the way: hard to know what profile the self registration is running under...

1

For self registration without SSO

Try ConfigurableSelfRegHandler Interface

After the visitor fills out the sign-up page and submits it, the handler is invoked to create a community member with the information that the visitor supplies. If the registration process requires email or phone verification, the verification process finishes before the Auth.ConfigurableSelfRegHandler.createUser is invoked. If verification isn’t required, createUser is invoked when the visitor submits the page.

Return Value Type: Id

Returns an identifier for the created User object. Auth.ConfigurableSelfRegHandler inserts a user and then returns the ID of that user.

So you can create the user assign the permission set and return the user Id.

For SSO via SAML

Check out the SamlJitHandler Interface.

While provisioning the user, you can add the necessary permission sets.

createUser(samlSsoProviderId, communityId, portalId, federationId, attributes, assertion) Returns a User object using the specified Federation ID. The User object corresponds to the user information and may be a new user that hasn’t t been inserted in the database or may represent an existing user record in the database.

The bolded text indicates that you can insert the user in your own method, add the perm set and then return the user you created.

For SSO Via Facebook etc.

As you pointed out, RegistrationHandler is very similar but it works for third party login apis:

Salesforce provides the ability to use an authentication provider, such as Facebook© or Janrain©, for single sign-on into Salesforce

4
  • Didn't know about that but seems to be only SAML and similar to a RegistrationHandler? – Keith C Mar 11 '20 at 14:48
  • @KeithC sorry didn't realize you wanted the non-sso version. Updated my answer. – gNerb Mar 11 '20 at 14:56
  • I don't want to do anything related to the User but rather leave the platform to do its thing. So wile it is cool to know about these interfaces, they don't seem directly suited to this purpose. Now if they could delegate back to the platform's implementation they would be good for this purpose. – Keith C Mar 11 '20 at 15:08
  • @KeithC I don't believe you can assign a permission set without a user Id. The only thing that I know of that does provide a user Id without manually creating one is the trigger so I would think that if you want to do as little as possible, the trigger is the place to do it. I don't personally like this approach because it means that you will be running at least some code (checking to see if it is a community user) that is unnecessary. Working in many orgs with bloated triggers, I do my best to avoid adding unnecessary code to the triggers. – gNerb Mar 11 '20 at 15:50
0

I've coded up the trigger handler as below. I'll see how I get on in the next few days in real scenarios.

public inherited sharing class UserHandler {

    private static Set<String> LICENSED_PRODUCT_NAMESPACES = new Set<String>{...};

    @TestVisible private static final String PROFILE_LIKE = '%...%';
    @TestVisible private static final String PERMISSION_SET_LIKE = '%...%';

    private static Set<Id> portalProfileIds {
        get {
            if (portalProfileIds == null) {
                portalProfileIds = new Map<Id, Profile>([
                    select Id
                    from Profile
                    where Name like :PROFILE_LIKE
                ]).keySet();
            }
            return portalProfileIds;
        }
        set;
    }

    private static Set<Id> portalPermissionSetIds {
        get {
            if (portalPermissionSetIds == null) {
                portalPermissionSetIds = new Map<Id, PermissionSet>([
                    select Id
                    from PermissionSet
                    where Name like :PERMISSION_SET_LIKE
                ]).keySet();
            }
            return portalPermissionSetIds;
        }
        set;
    }

    private static Set<Id> productLicenseIds {
        get {
            if (productLicenseIds == null) {
                productLicenseIds = new Map<Id, PackageLicense>([
                    select Id
                    from PackageLicense
                    where NameSpacePrefix in :LICENSED_PRODUCT_NAMESPACES
                    and Status != 'Expired'
                ]).keySet();
            }
            return productLicenseIds;
        }
        set;
    }

    // Trigger calls this
    public static void handle(TriggerOperation op, User[] newUsers) {

        switch on op {
            when AFTER_INSERT {
                handleAfterInsert(newUsers);
            }
        }
    }

    private static void handleAfterInsert(User[] newUsers) {

        PermissionSetAssignment[] assignments = new PermissionSetAssignment[] {};
        UserPackageLicense[] licenses = new UserPackageLicense[] {};

        for (User u : newUsers) {

            // 0 queries for non-portal Users
            if (u.IsActive && isPortalEnabledFor(u)) {

                // 1 query for portal Users
                if (portalProfileIds.contains(u.ProfileId)) {

                    // 2 queries for this portal Users
                    for (Id psId : portalPermissionSetIds) {
                        assignments.add(new PermissionSetAssignment(
                            AssigneeId = u.Id,
                            PermissionSetId = psId
                        ));
                    }

                    // 3 queries for this portal Users
                    for (Id plId : productLicenseIds) {
                        licenses.add(new UserPackageLicense(
                            UserId = u.Id,
                            PackageLicenseId = plId
                        ));
                    }
                }
            }
        }

        // 2 inserts for this portal Users
        insert assignments;
        insert licenses;
    }

    // Assuming this is quicker than doing a decribe to see if the field exists
    private static Boolean isPortalEnabledFor(User u) {
        try {
            return u.get('IsPortalEnabled') == true;
        } catch (SObjectException e) {
            // Communities or portals not turned on
            return false;
        }
    }
}

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.