Many times, when developing a custom Salesforce application, there are settings unique to the application that need to be stored somewhere. A common solution is a dedicated Salesforce object with the fields necessary to support these options; there will probably be Checkboxes and Picklists that control and shape how the app works. If an external system is involved, you'll probably have additional fields for things like a Username, Password, Token/Cookie, and an Expiration Date of sorts.
While this may work for some orgs (in a rush, don't know any better, or just don't care), there are some improvements that can be made. Minimally, this involves making sure that your Profile permissions are in check (you always do, right?). A step up would be the use of an Encrypted Text Field to store your Password. However, if you're developing an Application for the AppExchange, you need a solution that will pass the AppExchange Security review.
Before we start building, check out Secure Coding Storing Secrets, particularly the Apex and Visualforce Applications section.
It says that when included in a Managed Package, a "Protected" Custom Setting is "only accessible programmatically via Apex code that exists within your package."
For this blog post, we'll use a Custom Object to store our Application specific settings as referred to above. To maintain usability, we'll keep the Password field, but create a trigger to take the user inputted value, store it in a Custom Setting (as recommended by the Salesforce page), and then mask the Password field on the Custom Object.
We'll start out by building a Custom Object to hold our application specific settings, including the expected fields for calling out to our external system.
|"I'd don't always use the Schema Builder, but when I do..."|
|"... it looks like this."|
Next, let's define our App's Custom Setting, where in this post, we'll store our Password securely. You can expand on this and store more or all of your credential details if you desire.
Browse to Setup --> App Setup --> Develop --> Custom Settings and click on the "New" button.
Provide the basic details for your Custom Settings (like a name that applies to your package and a suitable description). Make sure that you select "List" for the Setting Type and "Protected" for the Visibility settings, then click on the "Save" button.
If you've never used Custom Settings before, you should be getting the feeling that they are very similar to Custom Objects. So much like them, that you can even retrieve their records via SOQL queries.
We're done with schema changes, so let's take a look again at the process we're building.
- A User will create/update an Application Setting (the Custom Object we built above) record with a new Password
- A trigger will look for a row within our Package Custom Settings that matches the Username
- If found, the Custom Setting's Password will be updated
- If not found, a new Custom Setting will be created
- The trigger will then replace the Application Setting's Password field with 8 asterisks (********).
Let's see what happens when you create a new Application Setting:
After clicking on "Save" the first thing I should notice is my password will be replaced with "********."
So far so good! Now let's check on our Custom Settings. We should have one record, with the password I provided.
Let's update the Password and make sure that it changes the Custom Setting and continues to replace the Password in the Custom Object.
The Custom Setting:
Great! Now from any Apex code, I can query my Custom Setting for the applicable username and end up with my password. Within a Managed Package, the Custom Settings created won't be visible to an Org that installs it. Like they Salesforce page said, the Custom Settings will only be retrievable by the Apex code included in my package. You can use a SOQL similar to this to get the applicable settings:
Notice the LIMIT? That's to avoid another red flag that may occur on your AppExchange Security Review findings report. All queries will need either a WHERE or a LIMIT.
That's all there is to it! Adapt, clean, and condense this code to fit your needs and enjoy!