4

We have our huge monolithic 1gp legacy package as well as 2gp extension package. And there are some secret configs (e.g. s3 keys, twillio account creds etc. in protected custom settings) in 1gp package which should be available in 2gp extension but only internally.

The simplest solution is to create global method in 1gp to return these settings. But it would introduce security issue, allowing subscribers to call this method from org level itself and inspect configs.

In case of 2gp-2gp packages relationship we could have used @NamespaceAccessible annotation to open method only to packages inside the same namespace. But what techniques can be used to achieve similar outcome for 1gp-2gp communication across different namespaces?

Unfortunately, it seems like there are no methods in Apex to return current or parent namespaces, i.e. to be able to hardcode checking at code level whether call is coming from allowed namespace etc. Any ideas would be appreciated re how to organize such protection in reliable but still simple way.

1 Answer 1

3

Unfortunately, there's not much you can do. You'd have to be in the same namespace in order to access the values, and you can't have a 1GP and 2GP with the same namespace installed in the same org. The only real path forward is to migrate your 1GP to a 2GP, which, as I understand it, won't be available until at least 2022.

A potential workaround for now would be to use a global method, as you suggest, that accepts an encrypted token that only the 1GP can decrypt, and 2GP can encrypt. Here's a sample implementation:

public class ProtectedAccessAPI {
    public static GlobalAccessAPI.DTO getConfiguration(Blob encryptedConfig) {
        Blob privateKey; // Load the private key here
        String result = Crypto.decryptWithManagedIV('AES256', privateKey, encryptedConfig).toString();
        System.assert(result.equals('Hello World'),'Unauthorized access attempt on getConfiguration');
        GlobalAccessAPI.DTO returnValue = new GlobalAccessAPI.DTO();
        // load returnValue here
        returnValue.value1 = 'Some value';
        returnValue.value2 = 42;
        return returnValue;
    }
}

global inherited sharing class GlobalAccessAPI {
    global class DTO {
        global String value1;
        global Integer value2;
    }
    global static DTO getConfiguration(Blob encryptedConfig) {
        // This prevents them from seeing the internal logic
        return ProtectedAccessAPI.getConfiguration(encryptedConfig);
    }
}

From here, you just need to encrypt the parameter in the 2GP, again using the private key. Since that key should be secure, the 1GP and 2GP will now share that secret.

Alternatively, you could use a publicKey/privateKey pair to use Crypto.sign and Crypto.verify, or another scheme, the point is we will fail an assertion so it would be challenging to brute-force, and we use encryption to make it non-trivial to brute-force.

Your subscribers will be able to look at the 1GP global code and won't get any real "hints" on how to extract the data, and the 2GP, properly secured, will be the only code that can access it.

5
  • 1
    Though sounds like may not be an option for you but you can choose to manually make your 1GP a 2GP and not wait for the "conversion" which is likely at least 1 yr away. We didn't have a large subscriber base so recently chopped our 1GP into a 2GP ourselves.
    – ddeve
    Oct 25, 2021 at 14:55
  • 1
    @ddeve Yeah, it depends on how painful it would be to migrate. In our case, we would have to migrate substantial amounts of data, some of which is hidden behind protected custom settings per org, along with the manual steps we already have to do for each install. It's not viable for us despite our relatively small size. That said, if it is an option, then it is certain something they could do.
    – sfdcfox
    Oct 25, 2021 at 15:07
  • @sfdcfox So we are basically replacing the problem of sharing a lot of secret data with sharing just single secret key to do encryption/decryption. Would it be ok just to hardcode that key at development time in both packages or are there any better alternatives?
    – wesaw
    Oct 25, 2021 at 15:44
  • 1
    @wesaw Don't put secrets in code (see Secure Coding: Storing Secrets). I'd recommend a Custom Metadata Type; they're protectable, don't use a SOQL to query, and can be shipped as part of the package, as opposed to Custom Settings, which are considered "data."
    – sfdcfox
    Oct 25, 2021 at 15:52
  • @ddeve That's what we are doing, i.e. migrating from 1GP to 2GP on our own. But our strategy is to first start creating small and focused 2gp packages as extensions to 1GP for all new functionalities, as well as in parallel slowly moving existent features (with data migrations and clients switching) to new 2GPs. That's why we have this need to be able to access 1GP internals from new 2GP packages while this sort of migration is in the middle.
    – wesaw
    Oct 25, 2021 at 15:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .