Saturday, September 1, 2012

Encrypted Fields in Apex- one gotcha

I've been doing some work integrating Salesforce with a credit card processor and hit upon a issue with encrypted fields in Apex that I haven't found documented anywhere.  It may actually be entirely intentional, but without documentation it's confusing and I did see a couple other people hitting the same problem.  According to Salesforce documentation, when you work with an encrypted field in Apex, the code will always see the unmasked value of the field.  But there's an exception, if you pass an Sobject into a method, you'll find that you'll be retrieving the masked value of the field.   I've only tested with static methods so far, and it might be specific to those.

More concrete examples.  You have an Opportunity that has already been saved with a value in the Credit Card Number field, which is encrypted.  You pass that Opportunity record into the following method.


public static void EncryptedExample(Opportunity opp){
String strCC = opp.Credit_Card_Number__c;
System.debug('Can the code see the masked number 9 in this field? '     
                     +strCC.contains('9'));
//No, it can't!
}

This is only an issue if the SObject you're passing in has been saved already.  If you pass in an SObject that either hasn't been inserted or if the value of the encrypted field has been updated but not committed to the database, then that field hasn't been encrypted and masked yet and the code therefore sees the actual value.

The solution?  You'll have to query for the record within your method and then all works as expected-


public static void EncryptedExample(Id idOpp){
Opportunity opp = [Select Amount, Payment_Type__c, Deposit__c, Credit_Card_Number__c, Credit_Card_Exp__c from Opportunity where Id =: idOpp];
String strCC = opp.Credit_Card_Number__c;
System.debug('Can the code see the masked number 9 in this field? ' 
                     +strCC.contains('9'));
//Yes it can!
}
Hope this helps someone, I know I spent a couple hours baffled (at first I thought it was a mistake in my webservice callout).

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi, thanks for your valuable post.
    appUsers = [SELECT LastName, Contact_Type__c, Title, Email , IsAppAccess__c,Password__c,Access_Level__c, FirstName,PasswordClearText__c FROM contact WHERE AccountId = :opportunity.account.Id AND Contact_Type__c = 'App User' ];
    if(!appUsers.isEmpty()){
    for(Contact c: appUsers){
    Contact con = [SELECT Password__c,PasswordClearText__c FROM contact WHERE Id = :c.Id];
    c.PasswordClearText__c = con.Password__c;
    }
    }
    I always see masked values

    ReplyDelete