Application multi-tenancy is supported from the SAS Viya LTS 2021.2 release. In this blog we will look at configuring SAML authentication in a multi-tenant (M-T) environment. We will examine some general concepts and dive into the details of how the authentication mechanism can be configured. For the discussions our SAS Viya environment will have the M-T provider and two tenants: a marketing tenant and a sales tenant.
There are two parts to the SAS Viya SAML configuration. The first part configures SAS Logon Manager as a SAML Service Provider, and is configured with the settings under sas.logon.saml. The SAML Service Provider settings are configured only in the M-T provider.
The second part of the SAS Viya SAML configuration is the link to the third-party SAML Identity Provider, and is configured with the settings under sas.logon.saml.providers. The sas.logon.saml.providers settings can be configured for the M-T provider and apply to the provider and all tenants. Or the sas.logon.saml.providers settings can be configured for an individual tenant and apply to that tenant only.
For our discussions here we will configure the sas.logon.saml settings in the M-T provider. Then we will configure the sas.logon.saml.providers settings in both the M-T provider and the marketing tenant.
Remember in a SAS Viya Multi-Tenant environment SAS Logon Manager will automatically prepend the tenant’s name in front of the two key identifying properties for the Service Provider. This means that the values of sas.logon.saml.entityBaseURL and sas.logon.saml.entityID within the tenant automatically have the tenant name added. For example, if in the M-T provider these are entered as:
When SAML is used from the marketing tenant i.e., by accessing https://marketing.{{INGRESS_NAME}}/SASDrive the values used in the authentication request to the Identity Provider will be:
This means that when the Identity Provider is configured for an individual tenant, such as the marketing tenant, care must be taken with the following properties:
Within the sas.logon.saml.providers settings you provide the metadata for the third-party SAML Identity Provider (IdP). This can either be a URL to download the metadata or the actual XML content itself. The third-party SAML IdP is uniquely defined by its own entityID. The entityID of the third-party SAML IdP must be unique within either the M-T provider or an individual tenant. This means that you cannot have multiple sas.logon.saml.providers settings targeting the same third-party IdP within the M-T provider or an individual tenant.
With SAS Viya 2021.2 (and later) to be able to specify the specific tenant which we want to apply the configuration to, we must use the SAS Viya CLI. With the SAS Viya CLI you can create a separate profile for the provider and each tenant. For example, to create a profile for the marketing tenant you would use the following:
INGRESS_URL=https://marketing.{{INGRESS_NAME}} ;\
/opt/sas/viya/home/bin/sas-viya --profile marketing profile set-endpoint "${INGRESS_URL}"
/opt/sas/viya/home/bin/sas-viya --profile marketing profile toggle-color true
/opt/sas/viya/home/bin/sas-viya --profile marketing profile set-output fulljson
In the examples that follow the default SAS Viya CLI profile will target the M-T provider, and the two tenants marketing, and sales, will have their own profiles.
Before we can construct the configuration settings for SAS Logon Manager to be the SAML Service Provider we need to generate a private key and an associated TLS certificate containing the public key. This public/private key pair will be used to digitally sign the SAML objects, requests, and responses. The TLS certificate containing the public key does not need to be signed by a commercial Certificate Authority since it is only used for validating the digital signatures.
You can use OpenSSL to generate the private key and a self-signed certificate. For example, you might use the following commands:
mkdir -p ~/SAML_Certs
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 \
-subj "/ST=SelfSigned/CN=SASLogonSigningKey" \
-keyout ~/SAML_Certs/SASLogonSigning.key \
-out ~/SAML_Certs/SASLogonSigning.cert
openssl rsa -in ~/SAML_Certs/SASLogonSigning.key -out ~/SAML_Certs/SASLogonSigningRSA.key
Then use the following commands to create files with the correctly escaped newline characters that can be read into our JSON configuration files correctly:
sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' ~/SAML_Certs/SASLogonSigningRSA.key > ~/SAML_Certs/JSON.key
sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' ~/SAML_Certs/SASLogonSigning.cert > ~/SAML_Certs/JSON.crt
For the example configuration provided in this blog we will use RedHat Keycloak as the third-party SAML Identity Provider. Therefore, any links to the SAML Identity Provider shown in the sample configuration used here will reference our implementation of Keycloak.
With the certificate and private key required for the SAML Service Provider configuration created we can now configure SAS Logon Manager. You will create several different JSON files containing the configuration. These are:
So, the first four will be applied to the M-T provider using the SAS Viya CLI and only the last one will be applied to the marketing tenant using the SAS Viya CLI. For example, you can use the following command to create the JSON files containing the configuration for the M-T provider and marketing tenant:
logon_host={{INGRESS_NAME}}
mkdir -p $deploy/site-config/JSON
tee $deploy/site-config/JSON/SAML_ServiceProvider.json > /dev/null << EOF
{
"name": "addSAML",
"items": [
{
"version": 1,
"metadata": {
"allowUserProperties": true,
"isDefault": false,
"mediaType": "application/vnd.sas.configuration.config.sas.logon.saml+json;version=4"
},
"entityBaseURL": "https://${logon_host}/SASLogon",
"setProxyParams": false,
"entityID": "SAML_ServiceProvider",
"serviceProviderKey": "$(<~/SAML_Certs/JSON.key)",
"serviceProviderCertificate": "$(<~/SAML_Certs/JSON.crt)", "wantAssertionSigned": true, "signMetaData": true, "signRequest": true } ] } EOF tee $deploy/site-config/JSON/SAML_IDP_Provider.json > /dev/null << EOF { "name": "add_SAML_Provider", "items": [ { "version": 1, "metadata": { "allowUserProperties": true, "isDefault": false, "tenant": "provider", "mediaType": "application/vnd.sas.configuration.config.sas.logon.saml.providers+json;version=1" }, "name": "saml_idp_provider", "idpMetadata": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/saml/descriptor", "emailDomain": "gellab.net", "linkText": "SAML Provider", "addShadowUserOnLogin": true, "showSamlLoginLink": true } ] } EOF tee $deploy/site-config/JSON/LogonCORS.json > /dev/null << EOF { "name": "addLogonSecurity", "items": [ { "version": 1, "metadata": { "services": ["SASLogon"], "isDefault": false, "mediaType": "application/vnd.sas.configuration.config.sas.commons.web.security.cors+json;version=2" }, "allowedOrigins": "https://gellabdc1.gellab.net", "allowedHeaders": "*", "allowedMethods": "*", "allowCredentials": true } ] } EOF tee $deploy/site-config/JSON/LogonCOOKIE.json > /dev/null << EOF { "name": "addLogonSecurity", "items": [ { "version": 1, "metadata": { "services": ["SASLogon"], "isDefault": false, "mediaType": "application/vnd.sas.configuration.config.sas.commons.web.security.cookies+json;version=2" }, "sameSite": "None" } ] } EOF tee $deploy/site-config/JSON/SAML_IDP_marketing.json > /dev/null << EOF
{
"name": "add_SAML_marketing",
"items": [
{
"version": 1,
"metadata": {
"allowUserProperties": true,
"isDefault": false,
"tenant": "marketing",
"mediaType": "application/vnd.sas.configuration.config.sas.logon.saml.providers+json;version=1"
},
"name": "saml_idp_marketing",
"idpMetadata": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/saml/descriptor",
"emailDomain": "gellab.net",
"linkText": "SAML marketing",
"addShadowUserOnLogin": true,
"showSamlLoginLink": true
}
]
}
EOF
Then you can use the following commands to use the SAS Viya CLI to load the configuration in the M-T provider:
/opt/sas/viya/home/bin/sas-viya auth login -u sasboot
/opt/sas/viya/home/bin/sas-viya configuration configurations create \
--file $deploy/site-config/JSON/SAML_ServiceProvider.json
/opt/sas/viya/home/bin/sas-viya configuration configurations create \
--file $deploy/site-config/JSON/SAML_IDP_Provider.json
/opt/sas/viya/home/bin/sas-viya configuration configurations create \
--file $deploy/site-config/JSON/LogonCORS.json
/opt/sas/viya/home/bin/sas-viya configuration configurations create \
--file $deploy/site-config/JSON/LogonCOOKIE.json
/opt/sas/viya/home/bin/sas-viya auth logout
Here we have authenticated using the default SAS Viya CLI profile against the M-T provider using the sasboot user. You will be prompted for the password and the configuration will be loaded into the M-T provider. Next you can use the following commands to use the SAS Viya CLI to load the configuration in the marketing tenant:
/opt/sas/viya/home/bin/sas-viya --profile marketing auth login -u sasprovider
/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations create \
--file $deploy/site-config/JSON/SAML_IDP_marketing.json
/opt/sas/viya/home/bin/sas-viya --profile marketing auth logout
Here we have authenticated using the marketing SAS Viya CLI profile against the marketing tenant using the sasprovider user. You will be prompted for the password and the configuration will be loaded into the marketing tenant.
With this complete SAS Logon Manager should be restarted. Once SAS Logon Manager has restarted you can obtain the metadata XML document describing the SAML Service Provider from SAS Logon Manager. This metadata XML document can then be used to configure the third-party SAML Identity Provider, in our case Keycloak.
The metadata XML document can be obtained from the /SASLogon/saml/metadata endpoint. On the M-T provider this would be https://{{INGRESS_NAME}}/SASLogon/saml/metadata. While for the marketing tenant it would be https://marketing.{{INGRESS_NAME}}/SASLogon/saml/metadata. Fetching the metadata XML from the marketing tenant will ensure the values for entityID, SingleLogoutService Location URL, AssertionConsumerService HTTP-POST Location URL, and AssertionConsumerService URI Location URL all correctly contain the tenant’s name.
Accessing the SAS Viya multi-tenant environment, we will have:
Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.
One way to prevent the marketing tenant from displaying the M-T provider SAML link is to ensure the configuration within the marketing tenant has the same name as the configuration within the M-T provider. This means in the SAML_IDP_marketing.json file changing the value "name": "saml_idp_marketing" to "name": "saml_idp_provider" to match the value we used in the SAML_IDP_Provider.json file. To do this you will need to first remove the SAML configuration within the marketing tenant.
We need to remove the existing saml_idp_marketing configuration from the marketing tenant. This involves both removing the configuration using the SAS Viya CLI and cleaning up one of the database tables used by SAS Logon Manager. You could attempt to clean-up the database table directly; a better approach is to use the SAS Logon Manager API to perform this clean-up.
In a future release we expect that removing the configuration with the SAS Viya CLI will be sufficient and no other clean-up will be required.
You can use the following commands to delete the existing SAML configuration from the marketing tenant using the SAS Viya CLI:
/opt/sas/viya/home/bin/sas-viya --profile marketing auth login -u sasprovider
my_id=`/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations list |grep -A 1 sas.logon.saml| awk -F\" '{print $4}'|tail -1`
/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations delete --id ${my_id}
/opt/sas/viya/home/bin/sas-viya --profile marketing auth logout
Then use the following commands to use the SAS Logon Manager API to remove the saml_idp_marketing internal reference:
/opt/sas/viya/home/bin/sas-viya auth login -u sasboot
myToken=`cat ~/.sas/credentials.json |jq -r '.Default."access-token"'`
myTenant="marketing"
myHost={{INGRESS_NAME}}
myID=`curl https://${myHost}/SASLogon/identity-providers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${myToken}" \
-H "X-Identity-Zone-Id: ${myTenant}" | jq -r '.[] | select(.originKey == "saml_idp_marketing").id'`
curl -X DELETE https://${myHost}/SASLogon/identity-providers/${myID} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${myToken}" \
-H "X-Identity-Zone-Id: ${myTenant}"
/opt/sas/viya/home/bin/sas-viya auth logout
Notice that we are using the SAS Viya CLI to authenticate to the M-T provider as the sasboot user. We then use the internal token that this authentication provides to call the SAS Logon Manager API. But when we call the /identity-providers API we include the X-Identity-Zone-Id header that identifies the marketing tenant. First, we use the /identity-providers API to find the ID of the saml_idp_marketing definition. Then we use the DELETE method of the /identity-providers API to remove that specific ID.
With these two steps complete, SAS Logon Manager should be restarted. Once SAS Logon Manager has been restarted the SAML configuration can be loaded for the marketing tenant using the SAS Viya CLI. However, this time the name of the configuration will be saml_idp_provider.
Since the name of the configuration loaded to the marketing tenant matches the name loaded to the M-T provider the values from the marketing tenant will supersede those from the M-T provider. This means that the marketing tenant SAS Logon Manager login form will now only display a single link.
Our desired configuration of the SAS Viya multi-tenant environment is almost complete. The M-T provider only uses the M-T provider configuration, and the marketing tenant now only uses the marketing tenant configuration. However, the sales tenant is still using the M-T provider configuration.
This might be a desired outcome if we want to share the SAML configuration between the M-T provider and the sales tenant. However, remember that the entityID will be different for the M-T provider and the sales tenant so you will probably need two separate registrations in the third-party SAML Identity Provider.
Instead, let’s look at how we can prevent the sales tenant using the M-T provider SAML configuration. This will leave the sales tenant displaying the standard login form with no additional authentication options. Again, we can leverage the SAS Logon Manager API. We will use the SAS Logon Manager API to set the propagated M-T provider configuration as not active in the sales tenant.
Use the following commands to update the propagated configuration in the sales tenant using the SAS Logon Manager API:
/opt/sas/viya/home/bin/sas-viya auth login -u sasboot
myToken=`cat ~/.sas/credentials.json |jq -r '.Default."access-token"'`
myTenant="sales"
myHost={{INGRESS_NAME}}
myID=`curl https://${myHost}/SASLogon/identity-providers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${myToken}" \
-H "X-Identity-Zone-Id: ${myTenant}" | jq -r '.[] | select(.originKey == "saml_idp_provider").id'`
myConf=`curl https://${myHost}/SASLogon/identity-providers/${myID} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${myToken}" \
-H "X-Identity-Zone-Id: ${myTenant}"`;\
myConf=`echo $myConf|sed 's/"active":true/"active":false/'`
curl -X PUT https://${myHost}/SASLogon/identity-providers/${myID} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${myToken}" \
-H "X-Identity-Zone-Id: ${myTenant}" \
-d "${myConf}"
/opt/sas/viya/home/bin/sas-viya auth logout
As before, we authenticate using the SAS Viya CLI as sasboot in the M-T provider. The header X-Identity-Zone-Id then identifies which tenant we are operating in.
These commands are using the SAS Logon Manager API to find the ID for the SAML configuration internally in SAS Logon Manager for the sales tenant. Next we fetch that configuration and update the value "active":true to "active":false. Finally, the updated configuration is uploaded using the SAS Logon Manager API. Setting "active":false within the sales tenant will prevent the configuration being used.
Our SAS Viya multi-tenant environment is now showing what we expect on the SAS Logon Manager login form for the M-T provider and the two tenants. The M-T provider page has a link to use the M-T provider configured SAML Identity Provider, the marketing tenant also has a link but to use the marketing configured SAML Identity Provider, and the sales tenant does not display any additional links.
But what if we want our end-users of the marketing tenant to be automatically redirected to the third-party SAML Identity Provider. So, we don’t want to display the SAS Logon Manager login page for just the marketing tenant. Obviously, the end-users accessing the sales tenant must be able to still access the SAS Logon Manager login page as they have no other way to authenticate.
SAS already provides a sample transformer that enables automatic redirect of sign-ins to the configured third-party SAML Identity Provider. This can be found in your deployment assets in the directory $deploy/sas-bases/examples/sas-logon-app/. We will just change the provided sample slightly to target the marketing tenant.
You can either copy the sample and edit it or use the following to create the YAML file with the required content:
tee $deploy/site-config/sas-logon-app/marketing-login-hint-transformer.yaml > /dev/null << 'EOF'
---
apiVersion: builtin
kind: PatchTransformer
metadata:
name: sas-ingress-login-hint-transformer
patch: |-
kind: Ingress
metadata:
name: sas-logon-app
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
large_client_header_buffers 4 32k;
if ( $args !~ "login_hint" ) { set $test A; }
if ( $uri = "/SASLogon/oauth/authorize" ) { set $test "${test}B"; }
if ( $request_method = "GET" ) { set $test "${test}C"; }
if ( $host ~ "marketing." ) { set $test "${test}D"; }
if ($test = ABCD ) { set $args $args&login_hint=gellab.net; rewrite $uri uri?$args; }
target:
kind: Ingress
name: sas-logon-app
EOF
These annotations that are added to the Ingress rule for SAS Logon Manager do the following:
This means if the GET request to `/SASLogon/oauth/authorize` on the marketing tenant does not have a `login_hint` it will be added. While if the request is not a GET, or already has a `login_hint`, or is not to `/SASLogon/oauth/authorize` on the marketing tenant nothing will happen. Remember the login_hint value is just used as a string match against the text in the emailDomain property and does not have to be an actual email address domain.
Next you need to add the reference to the file site-config/sas-logon-app/marketing-login-hint-transformer.yaml to your kustomization.yaml in the transformers section. Then follow the documented commands to rebuild your site.yaml and apply the updated site.yaml.
Once this is complete there will be no change in behaviour for the M-T provider or the sales tenant. However, for the marketing tenant when end-users access a web application like SAS Drive, they will no-longer see SAS Logon Manager. If the end-user already has a session with the third-party SAML Identity Provider, they will just be logged into SAS Drive. Alternatively, if they don’t have a current session with the third-party SAML Identity Provider they will be presented with the SAML Identity Provider’s login form.
In this blog we’ve shown the details of how SAML configuration is applied to the M-T provider and individual tenants in SAS Viya 2021.2 (and later). Through the examples we’ve shown how the M-T provider configuration is propagated to the tenants. We have shown how this might be a target architecture that you want to have, but also provided a couple of ways to deal with this propagation if you want different configuration in the tenants.
Find more articles from SAS Global Enablement and Learning here.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.