Securing Custom Settings in a Managed Package

Custom settings that have public visibility provide a good way of offering configuration options for a managed package. But the security mechanisms of normal objects do not apply and there is no “password” data type that masks the characters entered. So where secure values such as authorization keys to external web services need to be configured, more work needs to be done.

The solution is described in Secure Coding Storing Secrets – Apex and Visualforce Applications but it is only thanks to some feedback I got as part of a security audit that this finally made sense to me. The approach is to use protected custom settings instead of public ones as these are not visible or editable from the org that has the managed package installed. (Watch out: this public/protected visibility choice cannot be changed once the custom setting is created so think hard up front…) And then create a Visualforce page and controller to provide the access as these can have the necessary security measures applied such as limiting which profiles can access them and making use of apex:inputSecret that provides “password” style input. So instead of the free custom settings UI, you will need to spend several hours of work creating custom UI.

I had some difficulty getting the programmatic manipulation of the custom settings to work for the case where there was no instance already defined with an INVALID_CROSS_REFERENCE_KEY error being thrown on the id field. The code below is what I ended up with to support both creating the custom settings instance or editing an existing custom settings instance. (This code is only manipulating one field in one custom setting – ProtectedLicenseKeys__c.MDGuidelines__c – but in the product there are multiple fields and multiple custom settings handled by the one page.) There is extra ugliness because I wanted to give some feedback in the form of the length of the value saved as any entered values are deliberately not echoed back after “Save” is clicked.

public with sharing class SecureSettingsController {
    private void initLicenseKeys() {
        ProtectedLicenseKeys__c instance = ProtectedLicenseKeys__c.getInstance();
        licenseKeys = instance != null
                ? instance
                : new ProtectedLicenseKeys__c(SetupOwnerId = UserInfo.getOrganizationId());
        lengthOfMDGuidelines = licenseKeys.MDGuidelines__c != null ? licenseKeys.MDGuidelines__c.length() : 0;
        // Ensure secret value not in the view state
        licenseKeys.MDGuidelines__c = null;
    }
    public ProtectedLicenseKeys__c licenseKeys {
        get {
            if (licenseKeys == null) {
                initLicenseKeys();
            }
            return licenseKeys;
        }
        set;
    }
    public Integer lengthOfMDGuidelines {
        get {
            if (lengthOfMDGuidelines == null) {
                initLicenseKeys();
            }
            return lengthOfMDGuidelines;
        }
        set;
    }
    public PageReference saveLicenseKeys() {
        upsert licenseKeys;
        licenseKeys = null;
        return null;
    }
}

The following page is simple enough, and uses apex:inputSecret. To make the page a bit easier to access, I added an additional tab called “Security Settings” that displays the page and is accessed via the “All Tabs” tab. This is only available to “System Administrator” profile users.

<apex:page controller="SecureSettingsController">
    <apex:form id="mainForm">
        <apex:sectionHeader title="Secure Settings" />
        <apex:panelGrid columns="1">
            <apex:outputText >
                For the secure values, existing values are not displayed and characters entered are masked when echoed.
                So the length of the currently saved value is displayed to show where values are set.
            </apex:outputText>
            <apex:outputText > </apex:outputText>
        </apex:panelGrid>
        <apex:pageMessages />
        <apex:pageBlock title="License Keys" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!saveLicenseKeys}" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1">
                <apex:pageBlockSectionItem >
                    <apex:outputLabel value="MDGuidelines"/>
                    <apex:outputPanel >
                        <apex:inputSecret value="{!licenseKeys.MDGuidelines__c}" size="50" />
                        <apex:outputText value=" ({!lengthOfMDGuidelines} characters)"/>
                    </apex:outputPanel>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Advertisements

6 thoughts on “Securing Custom Settings in a Managed Package

  1. What I’m confused about with these protected custom settings is that they are effectively cached custom objects… and what gets deployed into the target org is just the definitions of the objects right? The actual data your application is relying on doesn’t get installed… hence the requirement to build a custom UI?

    • Yes the editing UI allows the values to be changed but only by users of certain profiles. But if you provide default values for each field those are deployed as part of the definition of the custom setting. The initialization pattern in the code above automatically instantiates the custom setting and so those defaults are applied, allowing the application to operate with the default values if the editing UI is never used.

  2. Any ideas how to use this technique to effectively “vault” the secret but have it available to code running outside your managed package? The only reason I would create the package would be to make the setting invisible to admins but need it accessible to non-packaged code.

  3. Hi,

    Just wanted to add to this (nice) article that if you want a non-Administrator user to be able to edit a “Protected Custom Settings” through your custom UI, he/she will need the “Customize Application” checked in his/her profile.

    Else, your custom UI will only show the values in Read-Only or (if it’s a picklist) upon saving it Salesforce will throw a “noAccess” security exception.

    So it’s not “just” Salesforce Administrators that can use your custom UI to update a Protected Custom Settings, but anyone with the “Customize Application” permission.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s