4

I use the Financial Force Metadata API Apex Wrapper to simplify an app setup using a custom UI. Part of the setup is the creation of a Self-Signed Certificate and its usage in a Single Sign-On Setting.

What an Admin could do in the native setup filling out those screens

Create Self-Signed Certificate

enter image description here

Single Sign-On Settings

enter image description here

should be performed based on a few values which change per app by the following Apex code.

public with sharing class SetupConnection {

    private void createConnectedApp() {
            MetadataService.Certificate cert = createSelfSignedCert();
            MetadataService.SamlSsoConfig sso = createSamlSsoConfig();

            MetadataService.ConnectedApp app = new MetadataService.ConnectedApp();
            app.fullName = 'MyApp';
            ...
            app.samlConfig.certificate = // WHAT TO PUT IN HERE;

            save(new List<MetadataService.Metadata>{ app });
        }
    }

    private MetadataService.Certificate createSelfSignedCert() {
        MetadataService.Certificate result = new MetadataService.Certificate();
        result.fullName = 'MyCert';
        ...
        save(new List<MetadataService.Metadata>{ result });
        return result;
    }

    private createSamlSsoConfig() {
        MetadataService.SamlSsoConfig result = new MetadataService.SamlSsoConfig();
        result.name = 'MySso';
        result.decryptionCertificate = // WHAT TO PUT IN HERE
        result.requestSigningCertId = // WHAT TO PUT IN HERE
        result.validationCert = // WHAT TO PUT IN HERE
        ...
        save(new List<MetadataService.Metadata>{ result });
        return result;
    }

    ...
}

My major challenges are (marked in code by // WHAT TO PUT IN HERE):

  1. How to get the Id of the cert for SamlSsoConfig.decryptionCertificate and SamlSsoConfig.requestSigningCertId?
  2. How to get the PEM-encoded certificate string for ConnectedAppOauthConfig.certificate?
  3. How to download the Certificate CRT and pass its content to SamlSsoConfig.validationCert?
2
+50

Taking the summary out of comments for everyone's benefit: the screens you reference are for implementation of a scenario where an external service/app is acting as a SAML identity provider, SF is a service provider.

SamlSsoConfig is the metadata object that corresponds to the Single Sign-On Settings screen, it captures a configuration of the (external) identity provider.

SSO Settings Screen -> SamlSsoConfig

  1. Identity Provider Certificate -> validationCert
  2. Request Signing Certificate -> requestSigningCertId
  3. Assertion Decryption Certificate -> decryptionCertificate

requestSigningCertId and decryptionCertificate are record IDs of a keypair in Certificates. The certs are surfaced in admin UI via the Certificate and Key Management screen. The value of validationCert is PEM-encoded identity provider's public key.

Signing of a SAML authentication request is done by the service provider (SF in this case). Service provider signs with private key, identity provider verifies with public key. Decryption: identity provider encrypts some elements of the SAML response with service provider's public key, service provider decrypts with their private key. Regardless of how it's created or signed (self-signed vs CA-signed), the same keypair can be used for both signing the authentication request and decryption.

Needed: one keypair (private + public key) in Certificates. Salesforce does not allow import or export of the private key via the API, this makes sense from a security perspective. Our recommendation would be to instruct the admin to generate a self-signed keypair via web UI (Certificate and Key Management screen), then on your custom setup screen prompt the admin for the name of the cert. To list all available certs, you call the Tooling REST API and grab all certs in the org, then create a list of certs in (for example) a pulldown menu. Tooling REST resource:

/services/data/<api version>/tooling/query?q=Select+Id,MasterLabel,DeveloperName+FROM+Certificate

Redacted response with api version = v46.0

{
   "size": ...,
   "totalSize": ...,
   "done": true,
   "queryLocator": null,
   "entityTypeName": "Certificate",
   "records": [
      {
         "attributes":
         {
            "type": "Certificate",
            "url": "/services/data/v46.0/tooling/sobjects/Certificate/0P1..."
         },
         "Id": "0P1...",
         "MasterLabel": "Foo",
         "DeveloperName": "Bar"
      }
   ]
}

The value of MasterLabel is NOT unique, you can have two certs with "Foo" as the master label. Thus our recommendation is to use the DeveloperName as the "display name" and the record ID as the value of the list item when rendering a list of certs in a pulldown menu:

<select>
  <option value="0P1...">Bar</option>
</select>

Once the admin selects the desired cert from the list of available certs, the record ID of this cert is known.

Last but not least, you need the identity provider certificate. The cert has to be uploaded by the user. With PEM encoding, the cert is rendered in ASCII plaintext. You can ask the user to copy and paste the cert into a text field/area in your custom setup screen, then extract the needed parts. PEM-encoded X.509 cert:

-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIOAUqIA1GrAAAAAC3/B7cwDQYJKoZIhvcNAQEFBQAwgZQx
...
r0o2LRns1VoDkkxMaA==
-----END CERTIFICATE-----

Between the BEGIN/END lines (aka "encapsulation boundaries") is base64-encoded data. PEM refers to this data as the "encapsulated text portion". Your code should remove the first and last marker lines (BEGIN/END) and extract the encapsulated text portion by joining the remaining lines into a single string. End result should look like this:

MIIEuTCCA6GgAwIBAgIOAUqIA1GrAAAAAC3/B7cwDQYJKoZIhvcNAQEFBQAwgZQx...r0o2LRns1VoDkkxMaA=

Then stick this string into validationCert and voila! You've automated the setup of an identity provider.

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.