BookmarkSubscribeRSS Feed

SAS 9.4 Authenticating as a Custom Application to SAS Viya

Started ‎08-02-2023 by
Modified ‎04-13-2024 by
Views 1,594

In the last post we discussed defining a custom application within SAS Viya and using the client_credentials grant type to authenticate. One of the use cases we presented in that post was connecting from SAS 9.4 to SAS Viya. I want to explore this use case in more detail in this post. As such, we will define a new custom application with SAS Logon Manager in SAS Viya and use the client_credentials grant type to obtain an Access Token. We will then use this Access Token to connect from SAS 9.4 to SAS Viya. This use case is a good fit for SAS 9.4 batch sessions that need to interact with SAS Viya when the end-user for the SAS 9.4 batch session does not exist in the Identity provider of our SAS Viya environment. Which could easily be the case when our SAS 9.4 environment is running on-premises and our SAS Viya environment is running in the cloud with more modern cloud-native Authentication and Identity providers such as OpenID Connect and SCIM.

 

Defining the Custom Application

 

To be able to register the custom application with SAS Logon Manager you need to first obtain an Access Token as a member of the SAS Administrators group. You can do this by calling the SAS Logon Manager API. Or you can obtain an Access Token using the SAS Viya CLI.

 

Once you have this Access Token you can register the custom application using the following call to the SAS Logon Manager API:

 

curl -k -X POST "${INGRESS_URL}/SASLogon/oauth/clients" \
   -H "Content-Type: application/json" \
   -H "Authorization: Bearer $BEARER_TOKEN" \
   -d '{
    "client_id": "cust1.app",
    "client_secret": "myclientsecret",
    "scope": ["uaa.none"],
    "authorities": ["CustomApps"],
    "authorized_grant_types": ["client_credentials"],
    "access_token_validity": 900
   }'

 

Note: You should specify a complex random string as the client_secret, a simple value is shown here to make the examples easy to read.

 

You should see something like the following for a successful response, we have split this output onto multiple lines to make it easier to read:

 

{"scope":["uaa.none"],
"client_id":"cust1.app",
"resource_ids":["none"],
"authorized_grant_types":["client_credentials"],
"autoapprove":[],
"access_token_validity":900,
"authorities":["CustomApps"],
"lastModified":1673609094057,
"required_user_groups":[]}

 

Notice that the authorized_grant_types only include client_credentials; this means that this client will never be able to obtain an Access Token for an end-user. Since this custom application will never obtain credentials for an end-user we have also set the scope to uaa.none. In addition, for our example the access_token_validity has been set to 900, which is 10 minutes, so we will need to reauthenticate every 10 minutes. You can define the access_token_validity to whatever value makes sense for your custom application, the value is the number of seconds that the Access Token will be valid for.

 

When using the client_credentials grant the authorities will represent the custom group, so our custom application will be in the CustomApps custom group.

 

You can then refer to the previous post if you need to update or delete the custom application.

 

Obtaining the Access Token

 

You could obtain the Access Token for the custom application by directly calling the SAS Logon Manager API outside of your SAS 9.4 environment and then provide this as a file to be used by the SAS 9.4 code. For example, you could obtain the Access Token using CURL with the following:

 

APP_TOKEN=`curl -skX POST "${INGRESS_URL}/SASLogon/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-u 'cust1.app:myclientsecret' \
-d 'grant_type=client_credentials' |jq -r '."access_token"'`; \
echo "Custom Application Access Token is: ${APP_TOKEN}"

 

You should see something like the following:

 

Custom Application Access Token is: eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.
eyJqdGkiOiI1MWMyYWEzYTMyY2E0MTI1OGM1OTUxZGM4NmEwYzk2OSIsInN1YiI6ImN1c3QxLmFwcCIsImF1dGhvcml0aWVzIjpbIkN1c3RvbUFwcHMiXSwic2NvcGUiOlsiQ3VzdG9tQXBwcyJdLCJjbGllbnRfaWQiOiJj
dXN0MS5hcHAiLCJjaWQiOiJjdXN0MS5hcHAiLCJhenAiOiJjdXN0MS5hcHAiLCJncmFudF90eXBlIjoiY2xpZW50X2NyZWRlbnRpYWxzIiwicmV2X3NpZyI6IjY3N2U2YWI0IiwiaWF0IjoxNjc0NTc4NjUwLCJleHAiOjE2
NzQ2NjUwNTAsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsiY3VzdDEuKiIsImN1c3QxLmFwcCJdfQ.ULMvGUBnQh_c3SnZCds0ePdq9le8KOcxtUZ2l
S398Fkqmu7cusU46IBFenqsSNYr1OlA5Z1eZT0qaSQQLiWeYVphyXq8EQv0YwLLW0_CaQN-rlhZvf-Thg0H-AmPpL-OFU08GQ8m8g6UboO4KZPR-e17P2qKBo18Rc8QvE2B1hcf-tbod0AN5Q62MkqLBTTajmnxNep4qJ1YP
0b6RhnnoriZsxN_PMm1Wytolq4UU69t0Drmn9s4brrPECG00FNaKV3TWkuwvqzJXB352doZ2-s8NVARELmqyZb5WdzYPL_5GkHsDAlZ76Dt3JBGlvnGWtZEdO9O_2ocH7GispCwTA

 

Alternatively, you could obtain the Access Token inside the SAS code that will be making connections to your SAS Viya environment. This requires that you have network connectivity to the Ingress Controller for your SAS Viya environment. For example, you could create a new group in the SAS 9.4 Metadata, for example "Viya Service Users", and assign the client_id and client_secret as credentials in a new authentication domain. The SAS 9.4 Authentication Domain would be configured for Outbound only.

 

01_SR_SAS9.4_CustomApp_Credentials.png

Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.

 

Then any of your SAS 9.4 users who will need to obtain an Access Token for the custom application would be added to this new group, for example "Viya Service Users".

 

You can then create a SAS Macro which will obtain the Access Token using the credentials from the SAS 9.4 Authentication Domain. You could place something like the following code into a file called get_custom_token.sas:

 

%macro get_custom_token(webauthdomain=);
%global custom_token;
%let ViyaIngress=%sysfunc(getoption(SERVICESBASEURL));

filename resp temp;

PROC HTTP
  url="&ViyaIngress./SASLogon/oauth/token"
  in="grant_type=client_credentials"
  ct="application/x-www-form-urlencoded"
  method='POST'
  WEBAUTHDOMAIN="&webauthdomain"
  AUTH_BASIC
  out=resp;
run;

%put &=SYS_PROCHTTP_STATUS_CODE;

libname auth json fileref=resp;
data _null_;
 set auth.root;
 call symputx('custom_token',access_token);
run;

filename resp clear;

%put &=custom_token;
%mend;

 

For more information on PROC HTTP see the documentation. The PROC HTTP statement is performing a HTTP POST to SAS Logon Manager in SAS Viya using the credentials from the authentication domain in SAS 9.4. This returns the Access Token for the custom application in the JSON response which is then processed to extract the Access Token and make it available as a global variable.

If the macro was placed in a directory such as /opt/sas/macros, you can make this available by using the following either in you SAS Code:

 

options insert=(sasautos=('/opt/sas/macros'));

 

Or in the sasv9_usermods.cfg:

 

-insert sasautos '/opt/sas/macros'

 

For more details on the INSERT System Option see the documentation.

 

Notice, that to make the code in the macro as portable as possible we have used the SERVICEBASEURL System Option. The SERVICEBASEURL System Option specifies the root URL for calls to SAS Viya Services. The SERVICEBASEURL is only valid in the SAS 9.4 configuration file, SAS invocation, or SASV9_OPTIONS environment variable (UNIX only). You cannot specify the SERVICEBASEURL System Option inside a running SAS 9.4 session. Also, the SERVICEBASEURL option can be restricted by a site administrator. For more information, see Restricted Options.

 

With the macro defined, the SAS 9.4 configuration file updated to include the SERVICEBASEURL and addition to the sasautos, and the group defined in the SAS 9.4 Metadata,for example "Viya Service Users"; we can then call the macro with the following:

 

%get_custom_token(webauthdomain=ViyaCustomClient);

 

So long as we have network connectivity between SAS 9.4 and the Ingress Controller for the SAS Viya environment, we should see the Access Token displayed in the SAS 9.4 log. If we want to remove showing the Access Token in the log, we will just remove the final %put statement in the macro code shown above. If there is an issue with the network connectivity the macro will run until the connection times out and the message "ERROR: Unable to connect to Web server" will be returned.

 

Accessing SAS Viya Services

 

Now that the Access Token is available to the SAS 9.4 session, this session can interact with the SAS Viya services as the custom application. For example, PROC HTTP can be used to call the SAS Viya REST APIs. Specifically, using the OAUTH_BEARER option sends the Access Token along with the HTTP call. To demonstrate this, the following code calls the Folders service and obtains the top-level links:

 

%let ViyaIngress=%sysfunc(getoption(SERVICESBASEURL));
filename resp temp;
PROC HTTP
  url="&ViyaIngress./folders/folders/"
  method='GET'
  OAUTH_BEARER="&custom_token."
  out=resp;
run;
data _null_;
   infile resp;
   input;
   put _infile_;
run;
filename resp clear;

 

This is just a very simple example of what can be done by calling the SAS Viya services.

 

If you have assigned a credential in the SAS Viya DefaultAuth Authentication Domain, then the custom application will be able to launch a SAS Compute Server instance in SAS Viya. This requirement to provide a credential for launching the SAS Compute Server was discussed in the previous post. The following example code uses PROC HTTP to do the following:

 

  • Find the Compute Context ID for the SAS Studio compute context.
  • Uses the Compute Context ID to launch a SAS Compute Server session.
  • Submits some sample code to the SAS Compute Server session.
  • Returns the listing for the SAS Compute Server job once it completes.
  • Terminates the SAS Compute Server session.

 

%let ViyaIngress=%sysfunc(getoption(SERVICESBASEURL));
filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/contexts?filter=eq(createdBy,'sas.studio')"
  ct="application/x-www-form-urlencoded"
  method='GET'
  OAUTH_BEARER="&custom_token."
  out=resp;
run;
libname output json fileref=resp;
data _null_;
 set output.items;
 call symput('my_contextID',id);
run;
filename resp clear;
libname output clear;

filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/contexts/&my_contextID/sessions"
  ct="application/vnd.sas.compute.session.request+json"
  method='POST'
  OAUTH_BEARER="&custom_token."
  in='{"version": 1,"name": "MySession","description": "This is my session for doing some simple work.","attributes": {},"environment": {"options": ["memsize=4g","fullstimer"]}}'
  out=resp;
run;
libname output json fileref=resp;
data _null_;
 set output.root;
 call symput('my_ComputeSessionID',id);
run;
filename resp clear;
libname output clear;

filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/sessions/&my_ComputeSessionID/jobs"
  ct="application/vnd.sas.compute.job.request+json"
  method='POST'
  OAUTH_BEARER="&custom_token."
  in='{"version": 2,"name": "MyOptions","description": "Getting the options for my session.",
    "code": ["proc print data=sashelp.class;","run;","%put &SYSUSERID;","cas mysession;",
    "proc cas; action listnodes result=res;print res;run;","data _null_;call sleep(10,1); run;",
    "cas mysession terminate;"],"attributes": {"resetLogLineNumbers": false}}'
  out=resp;
run;
libname output json fileref=resp;
data _null_;
 set output.root;
 call symput('my_jobID',id);
run;
filename resp clear;
libname output clear;

filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/sessions/&my_ComputeSessionID/jobs/&my_jobID/state?wait=60"
  ct="application/vnd.sas.compute.job.request+json"
  method='GET'
  OAUTH_BEARER="&custom_token."
  out=resp;
  headers "If-None-Match"="completed";
run;
data _null_;
   infile resp;
   input;
   put _infile_;
run;
filename resp clear;

filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/sessions/&my_ComputeSessionID/jobs/&my_jobID/listing"
  ct="application/vnd.sas.compute.job.request+json"
  method='GET'
  OAUTH_BEARER="&custom_token."
  out=resp;
run;
libname output json fileref=resp;
proc print data=output.items;
 var line;
run;
filename resp clear;
libname output clear;

filename resp temp;
PROC HTTP
  url="&ViyaIngress./compute/sessions/&my_ComputeSessionID"
  ct="application/vnd.sas.compute.job.request+json"
  method='DELETE'
  OAUTH_BEARER="&custom_token."
  out=resp;
run;
filename resp clear;

 

This demonstrates what can be easily achieved once the Access Token is available to the SAS 9.4 session. This code sample was produced based on the examples provided at https://developer.sas.com.

 

Accessing SAS Cloud Analytic Services

 

As well as interacting with the SAS Viya services the SAS 9.4 session can use the Access Token to directly interact with SAS Cloud Analytic Services. So long as the SAS 9.4 environment is running maintenance release 5 or higher the CAS client is built into SAS 9.4. Leveraging the Access Token with the CAS client requires the following:

 

The SAS_VIYA_TOKEN environment variable can be defined either during SAS invocation, or during the session with an OPTIONS statement. For example, using the following allows us to set the value of SAS_VIYA_TOKEN to the Access Token obtained using the macro code given above:

 

options set=SAS_VIYA_TOKEN="&custom_token";

 

The SERVICEBASEURL system option is required since the CAS client in SAS 9.4 will pre-validate the Access Token before attempting to use it. To pre-validate the Access Token the CAS client will obtain the public key from SAS Logon Manager in SAS Viya. The public key is used to validate the signature on the Access Token. If network connectivity is not correctly configured to allow SAS 9.4 to access the SERVICEBASEURL the CAS client will error and the connection to SAS Cloud Analytic Services will not be attempted. In such case, the only error will be presented in the SAS 9.4 session. There will be no error in the SAS Cloud Analytic Services logs since the connection is never attempted.

 

Putting all these parts together means that we can launch a CAS session using the custom application from a SAS 9.4 session with the following code:

 

%get_custom_token(webauthdomain=ViyaCustomClient);

options set=CASCLIENTDEBUG=1;
options set=CAS_AUTH_METHOD=oauth;
options set=SAS_VIYA_TOKEN="&custom_token";

cas mysession host="SAS_VIYA_LOADBALANCER_HOSTNAME" port=5570 ;

 

Which will result in the following information in the SAS 9.4 log, since the CASCLIENTDEBUG is set to 1:

 

 NOTE: The session MYSESSION connected successfully to Cloud Analytic Services SAS_VIYA_LOADBALANCER_HOSTNAME using port 5570. 
       The UUID is 6939b748-9ec3-3d42-9c83-5c6ebfabc45e. The user is cust1.app and the active caslib is CASUSER(cust1.app).
 NOTE: The SAS option SESSREF was updated with the value MYSESSION.
 NOTE: The SAS macro _SESSREF_ was updated with the value MYSESSION.
 NOTE: The session is using 2 workers.
 NOTE: Forcing oauth authentication.
 NOTE: Client is using the oauth identity provider
 NOTE: Sent challenge length 968
 NOTE: Received response length 57
 NOTE: User cust1.app connected to CAS using OAuth 2.

 

This shows that we have successfully launched a SAS Cloud Analytic Services session as the custom application from the SAS 9.4 session.

 

Conclusion

 

In this post we have delved into more details on the specific use case of connecting to SAS Viya from SAS 9.4 using an Access Token for our custom client. This scenario is a good fit for SAS 9.4 batch sessions that need to interact with SAS Viya when the end-user for the SAS 9.4 batch session does not exist in the Identity provider of our SAS Viya environment. Which could easily be the case when our SAS 9.4 environment is running on-premises and our SAS Viya environment is running in the cloud with more modern cloud-native Authentication and Identity providers such as OpenID Connect and SCIM.

 

In the post we have presented a methodology for obtaining the Access Token without needing to set an extreme lifetime for the Access Token. Using an Authentication Domain in SAS 9.4 to hold the client_id and client_secret means that an Access Token can be obtained only by the designated users and only when necessary. This means that we do not leave an Access Token exposed for more time than it is needed. It also means that it is easier for whoever is administrating the environments to update the client_secret.

 

If you want to explore this topic in more detail, you can refer to Course: Advanced Topics in Authentication on SAS Viya.

 

 

Find more articles from SAS Global Enablement and Learning here.

Version history
Last update:
‎04-13-2024 02:02 AM
Updated by:
Contributors

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags