GoodData PGP Single Sign-On
This Single Sign-On (SSO) implementation is a custom proprietary implementation provided by GoodData. This implementation is based on the PGP keypair exchange. It allows your application to sign in an existing GoodData user. The authentication is done not by username and password but by generating a session-specific token using a pair of PGP keys.
Depending on your current situation and use case, the GoodData PGP SSO is sometimes easier to implement than SAML SSO.
Access the API endpoints through your GoodData subdomain https://{your-subdomain-name}.gooddata.com
. For example, https://example.gooddata.com
. If your workspaces use whitelabeling, use your own domain address. For example, https://example.com
.
Implementation Process
As a domain administrator, you can configure SSO for your workspaces and users through the SSO Providers API.
Follow these steps:
Configure the
ssoProvider
parameter by modifying the following template according to your site parameters and submit a POST request to the endpointhttps://{your-subdomain-name}.gooddata.com``/gdc/domains/{domainId}/authentication/providers
:{ "pgpProvider": { "name": "string", "publicKey": "string" } }
Where:
name (String) Specifies the name of the SSO provider. This value becomes a possible value for the
ssoProvider
{style=“text-align: left;"} parameter. The SSO provider name must be lowercase and can contain only letters, numbers, dots, and dashes. For example:example.com pgp-my.example.com
publicKey *(String)*Specifies the value of the public key for your SSO service. If you need to generate a new PGP key pair, see How to Generate a Public-Private Key Pair. The key will look similar to the following example:
-----BEGIN PGP PUBLIC KEY BLOCK----- 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 =gOqe -----END PGP PUBLIC KEY BLOCK-----
Do not delete the PGP header and footer (BEGIN/END) from the public key that you are sending. You will need to escape and erase all of the new lines with \n to make one line. For example:
"publicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n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\n=gOqe\n-----END PGP PUBLIC KEY BLOCK-----"
Use the
ssoProvider
parameter when provisioning users through the API for managing users.Only a domain administrator can create a user with thessoProvider
parameter specified or modify thessoProvider
parameter for an existing user.You set up your SSO environment.
Example Use Case: Embedding GoodData
In the following example, you are embedding a dashboard into your application. To do so, you are doing the following:
- Posting the PGP login request form parameters to the PGP login URL
- Posting the result target to an iframe
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Prevent content caching -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="0"/>
<title>Example GoodData PGP SSO Login</title>
</head>
<body>
<form id="helperForm" target="embeddedGoodDataIframe" method="post" action=" https://{your-subdomain-name}.gooddata.com/gdc/account/customerlogin">
<input id="targetUrl" type="hidden" name="targetUrl" value=""/>
<input id="ssoProvider" type="hidden" name="ssoProvider" value=""/>
<input id="encryptedClaims" type="hidden" name="encryptedClaims" value=""/>
</form>
<iframe name="embeddedGoodDataIframe"></iframe>
<script type="text/javascript">
let targetUrl = "/dashboards/embedded";
let ssoProvider = "sso-provider-name";
let pgpMessage = "-----BEGIN PGP MESSAGE-----\n" +
"\n" + "hQIOA3sav0dr/91SEAf+IzO38qQ9TBnUz2YRtHCgAX7sOwG8v/KdXNJa3TMC7Ed/\n" +
"zoZDIzJnZHaAT+h356XX+f2lAFbJHqs1HUGoOMM1XwRShrC2tSiNdHTh14bZk3MS\n" +
"PN52RyoNHEWa6A8d0Ptsx9vhMbPVfRVmOJHiRaKmxZMw5i4OUvj2nDgPXtzDGGDD\n" +
... "zW1FkFtZpE0bEHSrMEpKCKy68E4yRyFKo7CUIgmTn1EC59WMJ0a+ERt1YgRVn1fb\n" +
"O8VPB/H6a4zyO8Q1/MnRfS++YlRHdzjT/f+cKstGrEjPAFYpW3GPkN0LI+xo/JQY\n" +
"S/TpYhp3+Cghb0O9rusiTRnJ88dQ07aysqpB6Xs=\n" +
"=DkmC\n" +
"-----END PGP MESSAGE-----";
document.getElementById('targetUrl').value = targetUrl;
document.getElementById('ssoProvider').value = ssoProvider;
document.getElementById('encryptedClaims').value = pgpMessage;
document.getElementById('helperForm').submit();
</script>
</body>
</html>
Disable Caching
We recommend that you serve the page with HTTP headers which disable caching because it is more reliable than meta tags. For more information, see https://www.mnot.net/cache_docs/#META.
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Post the PGP Login Request Form Parameters
No encoding is needed when posting the parameters.
- API resource:
https://{your-subdomain-name}.gooddata.com``/gdc/account/customerlogin
- Method:
POST
- Parameters:
targetUrl
defines the URL of the dashboard, report or any other page that you want to embed. The URL is relative to the GoodData server starting with a slash (/
).ssoProvider
corresponds to thessoProvider
parameter used in the API for managing users.encryptedClaims
must be dynamically generated based on the user who you want to authenticate (see Create Encrypted Claims).
For more information about the API call, see the API documentation for SSO PGP login.
Do not use the PGP SSO GET
method. This method is no longer supported and stopped working on February 15, 2019 (see PGP SSO GET Method).
Create Encrypted Claims
You have to dynamically generate an encryptedClaims
parameter.
Steps:
Create a JSON file in the following format:
{ "email": "end.user@domain.com", "validity": 123456789, "notBefore": 11515111, "notOnOrAfter": 11515211 }
email
(mandatory) corresponds to the user account set up in GoodData with SSO permissions. This email is used for logging in through the SSO login resource. The email is case-sensitive:User@domain.com
anduser@domain.com
are not the same.validity
(mandatory) is a date in the UTC timezone (UNIX timestamp format andINTEGER
data type) when the generated token expires. It must be set from a minimum of +10 minutes from present up to a maximum of 36 hours from present.We recommend that you set the validity to be less than 36 hours. Setting the validity to 36 hours precisely may lead to user requests being rejected due to the local times on the application servers not synchronized. Typically, the validity that is 5-10 minutes less than 36 hours is sufficient to avoid such issues.notBefore
(optional) is a UNIX timestamp (in seconds) that specifies the earliest instant in time when the SSO login link begins being valid.notOnOrAfter
(optional) a UNIX timestamp (in seconds) that specifies the instant in time when the SSO login link expires.
Though the
notBefore
andnotOnOrAfter
parameters are optional, we strongly recommend that you use them because they minimize a potential abuse of a login session. These parameters ensure that the SSO login link is valid within the specified period only (and it must not last longer than few minutes).For example, you want to configure a login session in the following way: if a user accesses the SSO link within the next 10 minutes, a valid session will be created for them. This session will last for 12 hours. If not used, the link will expire in 10 minutes.
To achieve this, set the parameters as follows:
validity
to +12 hours from nownotOnOrAfter
to +10 minutes from nownotBefore
to now
Sign the JSON file using the private part of your key. Do not use the
--clearsign
option.gpg --armor -u pgpOwner.user@domain.com --output signed.txt --sign json.txt
Encrypt the result using the GoodData public PGP key.
gpg --armor --output enc.txt --encrypt --recipient security@gooddata.com signed.txt
Use the encrypted message as the
encryptedClaims
parameter in the PGP login request (see Post the PGP Login Request Form Parameters).
Authentication Process
The following picture shows the whole authentication process:
PGP-based SSO Security
Supported Encryption Algorithms
Public key | RSA, RSA-E, RSA-S, ELG-E, DSA, ECC |
Cipher | 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH |
SSO Session Duration
When an SSO session is initiated via login, the initiating application can define the length of the session token in the JSON.
This session duration is defined using the validity
parameter. The validity
parameter must be set as a UNIX time code that is a minimum of +10 minutes from present up to a maximum of 36 hours from present.
We recommend that you set the validity to be less than 36 hours. Setting the validity to 36 hours precisely may lead to user requests being rejected due to the local times on the application servers not synchronized. Typically, the validity that is 5-10 minutes less than 36 hours is sufficient to avoid such issues.
The header of the response to the login request contains a SuperSecured Token (SST), which defines how long the session can last regardless of whether a user is active or not. If the SSO user is still logged in to the GoodData platform at the moment when the SST expires, the GoodData application stops responding.
To renew the token, refresh the parent page. This lets you log in back to the GoodData platform, and starts a new GoodData session over SSO.
You must control your PGP key validity and update it before it expires.
Troubleshooting
Problem:
I cannot load a dashboard.
Reason:
The SSO handshake failed.
Solution:
This may be due to an improper SSO configuration or using a wrong SSO integration method. If you are not sure what is wrong, contact GoodData Support.