-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7565fdb
commit 4742532
Showing
8 changed files
with
289 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Secure Auth. Provider Secrets | ||
*How to store secrets securely in custom Auth. Providers* | ||
|
||
|
||
--- | ||
# Article | ||
|
||
In this article, I will try to explain how Auth. Provider secrets can be stored securely in Salesforce. | ||
|
||
## The Problem | ||
When we create and configure custom Auth. Provider, according to Salesforce documentation, we will create a new custom metadata to store all parameters. | ||
Typically, these parameters would like this: | ||
- Authorization Endpoint Url | ||
- Token Endpoint Url | ||
- Consumer Key / Client ID | ||
- Consumer Secret / Client Secret | ||
- Scope | ||
|
||
The result of such configuration will be Auth Provider page, which will look like this: | ||
![img_1.png](/img/auth-provider-1.png) | ||
|
||
Now, the problem is that all the above fields are text fields - Custom Metadata does not have a concept of secret field. | ||
Any Salesforce Admin or anyone | ||
with `Customize Application` permission can look up Client Id | ||
and Client Secret and use them for malicious purposes. Even worse if that person leaves the company knowing these secrets. There's no telling who knows these | ||
secrets. | ||
|
||
## Solution | ||
To circumvent this situation, we will move these secrets to different storage: External Credential. | ||
|
||
### External Credential | ||
First, we will create an External Credential with Custom authentication protocol. This will be our safe storage for secrets - what's stored here is not | ||
visible to anyone. | ||
![img_2.png](/img/auth-provider-2.png) | ||
|
||
### Note! | ||
External Credential Principal has to be added in Permission Set or Profile to use it. | ||
|
||
### Named Credential | ||
Secondly, we will create a Named Credential connected to External Credential. It is essential to check `Allow Formulas in HTTP Body`. We don't | ||
need `Generate Authorization Header` though. | ||
![img_3.png](/img/auth-provider-3.png) | ||
|
||
### Auth. Provider | ||
Thirdly, we will change Auth. Provider to use Named Credential. Secrets use special merge field that will be replaced by Named | ||
Credential - `{!$Credential.Microsoft.ClientSecret}`. | ||
- `.Microsoft.` is Developer Name of External Credential. It has to be External Credential linked to our Named Credential | ||
- `.ClientSecret` is the name Authentication Parameter on our Principal | ||
![img_4.png](/img/auth-provider-4.png) | ||
*Note: I left Authorization Endpoint Url, because it is returned to the browser. * | ||
|
||
And we are done! | ||
|
||
Our Http Request body should now look like this: | ||
``` | ||
code=XXX | ||
&grant_type=authorization_code | ||
&redirect_uri={{redirectURI | ||
&client_id=c8cd6366-bdcc-4f25-8370-532a52054c76 | ||
&client_secret={!$Credential.Microsoft.ClientSecret} | ||
``` | ||
|
||
## Deployment Tips | ||
At last, just a few pointers for deploying Auth. Providers. This type of metadata usually has different configurations on different sandboxes, so it requires | ||
some flexibility. | ||
|
||
|
||
#### 1. Don't deploy fields you don't want to overwrite | ||
If you don't want to have your values overwritten on deployment, just remove them from the repository. You can deploy blank Auth. Provider to org, fill the | ||
details once and never touch it again. Or don't include metadata record at all. | ||
|
||
The tip inside a tip here is to not make any of the fields required. Just save yourself trouble. | ||
|
||
No substitutions, no CI/CD environments, no trouble. | ||
```xml | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||
<label>MyAuthProvider</label> | ||
<protected>false</protected> | ||
<values> | ||
<field>Authorization_Endpoint_Url__c</field> | ||
<value xsi:type="xsd:string">https://login.microsoftonline.com/693ad9ee-7efd-43d0-a0ab-2fd666808a42/oauth2/v2.0/authorize</value> | ||
</values> | ||
<!--These fields will not be overwritten--> | ||
<!-- <values>--> | ||
<!-- <field>Client_Id__c</field>--> | ||
<!-- <value xsi:type="xsd:string">cfd291af-99e7-48b9-abd1-7616368b2a1c</value>--> | ||
<!-- </values>--> | ||
<!-- <values>--> | ||
<!-- <field>Client_Secret__c</field>--> | ||
<!-- <value xsi:type="xsd:string">{!$Credential.Microsoft.ClientSecret}</value>--> | ||
<!-- </values>--> | ||
<values> | ||
<field>Scope__c</field> | ||
<value xsi:type="xsd:string">openid offline_access</value> | ||
</values> | ||
<values> | ||
<field>Token_Endpoint_Url__c</field> | ||
<value xsi:type="xsd:string">callout:MicrosoftLogin/693ad9ee-7efd-43d0-a0ab-2fd666808a42/oauth2/v2.0/token</value> | ||
</values> | ||
</CustomMetadata> | ||
``` | ||
|
||
#### 2. SFDX Substitutions | ||
You may find it useful to use substitutions, which are now inbuilt in SF CLI. In that case, you set environment variable in CI/CD runner for each environment. | ||
|
||
In our example, we can set `AAD_TENANT_ID` as global variable in GitHub and have it replaced in Auth. Provider metadata: | ||
|
||
```xml | ||
|
||
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||
<values> | ||
<field>Authorization_Endpoint_Url__c</field> | ||
<value xsi:type="xsd:string">https://login.microsoftonline.com/AAD_TENANT_ID/oauth2/v2.0/authorize</value> | ||
</values> | ||
<values> | ||
<field>Token_Endpoint_Url__c</field> | ||
<value xsi:type="xsd:string">callout:MicrosoftLogin/AAD_TENANT_ID/oauth2/v2.0/token</value> | ||
</values> | ||
</CustomMetadata> | ||
``` | ||
|
||
sfdx-project.json: | ||
```json | ||
{ | ||
"replacements": [ | ||
{ | ||
"filename": "force-app/main/default/customMetadata/MicrosoftAuthProvider.MyAuthProvider.md-meta.xml", | ||
"stringToReplace": "AAD_TENANT_ID", | ||
"replaceWithEnv": "AAD_TENANT_ID" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
[Link to Documentation](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_string_replace.htm) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><meta name="description" content="Open source library for Salesforce. Salesforce Frameworks, Accelerators, Components, Utilities."><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/cloud.svg"><link rel="stylesheet" href="/salesforce-lightning-design-system.min.css"><title>Apex Libra - Library of Salesforce Accelerators, Frameworks, Utilities</title><script type="text/javascript">!function(n){if("/"===n.search[1]){var a=n.search.slice(1).split("&").map((function(n){return n.replace(/~and~/g,"&")})).join("?");window.history.replaceState(null,null,n.pathname.slice(0,-1)+a+n.hash)}}(window.location)</script><script defer="defer" src="/static/js/main.2d530ebc.js"></script><link href="/static/css/main.daa7645d.css" rel="stylesheet"><script defer="defer" src="/static/js/main.fa12e836.js"></script><link href="/static/css/main.daa7645d.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div style="display:none"><h1>Apex Commons</h1><h1>Salesforce Frameworks</h1><h1>Salesforce Accelerators</h1><h2>Trigger Handler</h2><h2>Lambda</h2><h2>Collection</h2><h2>XML</h2><h2>Selectors</h2><h2>Selector Layer</h2><h1>LWC</h1></div><div id="root" class="fullHeight"></div></body></html> | ||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><meta name="description" content="Open source library for Salesforce. Salesforce Frameworks, Accelerators, Components, Utilities."><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/cloud.svg"><link rel="stylesheet" href="/salesforce-lightning-design-system.min.css"><title>Apex Libra - Library of Salesforce Accelerators, Frameworks, Utilities</title><script type="text/javascript">!function(n){if("/"===n.search[1]){var a=n.search.slice(1).split("&").map((function(n){return n.replace(/~and~/g,"&")})).join("?");window.history.replaceState(null,null,n.pathname.slice(0,-1)+a+n.hash)}}(window.location)</script><script defer="defer" src="/static/js/main.2d530ebc.js"></script><link href="/static/css/main.daa7645d.css" rel="stylesheet"><script defer="defer" src="/static/js/main.fa12e836.js"></script><link href="/static/css/main.daa7645d.css" rel="stylesheet"><script defer="defer" src="/static/js/main.ca2a4e68.js"></script><link href="/static/css/main.daa7645d.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div style="display:none"><h1>Apex Commons</h1><h1>Salesforce Frameworks</h1><h1>Salesforce Accelerators</h1><h2>Trigger Handler</h2><h2>Lambda</h2><h2>Collection</h2><h2>XML</h2><h2>Selectors</h2><h2>Selector Layer</h2><h1>LWC</h1></div><div id="root" class="fullHeight"></div></body></html> |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
object-assign | ||
(c) Sindre Sorhus | ||
@license MIT | ||
*/ | ||
|
||
/*! | ||
Copyright (c) 2018 Jed Watson. | ||
Licensed under the MIT License (MIT), see | ||
http://jedwatson.github.io/classnames | ||
*/ | ||
|
||
/*! | ||
Copyright (c) 2015 Jed Watson. | ||
Based on code that is Copyright 2013-2015, Facebook, Inc. | ||
All rights reserved. | ||
*/ | ||
|
||
/*! | ||
* Adapted from jQuery UI core | ||
* | ||
* http://jqueryui.com | ||
* | ||
* Copyright 2014 jQuery Foundation and other contributors | ||
* Released under the MIT license. | ||
* http://jquery.org/license | ||
* | ||
* http://api.jqueryui.com/category/ui-core/ | ||
*/ | ||
|
||
/*! | ||
* Determine if an object is a Buffer | ||
* | ||
* @author Feross Aboukhadijeh <https://feross.org> | ||
* @license MIT | ||
*/ | ||
|
||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ | ||
|
||
/** | ||
* @license React | ||
* react-dom.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* @license React | ||
* react-is.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* @license React | ||
* react-jsx-runtime.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* @license React | ||
* react.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* @license React | ||
* scheduler.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* @remix-run/router v1.7.2 | ||
* | ||
* Copyright (c) Remix Software Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE.md file in the root directory of this source tree. | ||
* | ||
* @license MIT | ||
*/ | ||
|
||
/** | ||
* Prism: Lightweight, robust, elegant syntax highlighting | ||
* | ||
* @license MIT <https://opensource.org/licenses/MIT> | ||
* @author Lea Verou <https://lea.verou.me> | ||
* @namespace | ||
* @public | ||
*/ | ||
|
||
/** | ||
* React Router DOM v6.14.2 | ||
* | ||
* Copyright (c) Remix Software Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE.md file in the root directory of this source tree. | ||
* | ||
* @license MIT | ||
*/ | ||
|
||
/** | ||
* React Router v6.14.2 | ||
* | ||
* Copyright (c) Remix Software Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE.md file in the root directory of this source tree. | ||
* | ||
* @license MIT | ||
*/ | ||
|
||
/** @license React v17.0.2 | ||
* react-jsx-runtime.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** @license React v17.0.2 | ||
* react.production.min.js | ||
* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ |