BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Edoedoedo
Pyrite | Level 9

We are on Viya 3.4. Suppose this scenario:

  • A user access https://site/SASReportViewer
  • He is redirected to /SASLogon for authentication
  • He autenticates himself (with LDAP credentials)
  • He is redirected to /SASReportViewer
  • He opens the report Report1
  • The Report1 opens
  • Inside the Report1, among sas graphs, there is a data driven content object
  • (*) This DDC begins to execute some async calls to the CAS REST API to perform some operations (i.e. it begins to call "POST: /cas/sessions" to create a session id on CAS)
  • The CAS REST API returns 403 Unauthenticated

The problem is, of course, that since the APIs are stateless I need to provide the oauth token in the http request. If I request a token to /SASLogon/oauth/token (I have already registered a new clientid on consul), and the use this token to execute (*), it works.

However, in order to request a token I need the user to input his credential again! And this is where the problem is.

 

I need a way to call the CAS API reusing somehow the authentication the user has already provided in the standard SASLogon form when he accessed https:/site/SASReportViewer for the first time.

 

How would I accomplish that? What am I missing?

 

Thanks a lot

Regards

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Edoedoedo
Pyrite | Level 9

Hi Deva,

 

taking inspiration from your quote I found a way to do what i need! The problem in fact is:

  • The user is authenticated on SASReportViewer, which uses a session-based authentication
  • The user wants to access the CAS APIs, which use a token-based authentication

So basically knowing this I would say that there is no way to recycle the session auth to get a token. And this problem happens the same on restaf of course, the user must insert his credentials twice.

 

I found out a "dirty" way Smiley Very Happy

 

  • I created a new oauth client on /SASLogon/oauth/clients with this config:

 

{
	"scope": [
                "openid",
                "*"
            ],
            "client_id": "xxx",
            "client_secret": "yyy",
            "resource_ids": [
                "none"
            ],
            "authorized_grant_types": [
                "authorization_code",
                "password",
                "refresh_token"
            ],
            "redirect_uri": [
                "/fake"
            ],
            "autoapprove": [
                "true"
            ],
            "authorities": [
                "uaa.resource",
                "sasapp"
            ],
            "use-sessions": "true"
}

(note the "/fake" redirect uri)

 

 

So:

  • The user authenticates himself on SASReportViewer, and gets a session auth cookie
  • After that, my js sends a request to /SASLogon/oauth/authorize asking for a 'code' response_type, and sends together the session auth cookie the user has already got
  • My js gets a response with a redirect to /fake which in turns gets 404 not found (of course, it's fake!)
  • But, in the /fake redirect url there is the valid response code!
  • My js grabs this response code, and sends a request to /SASLogon/oauth/token with the oauth client_id and client_secret, and the response code, without sending the session auth cookie (it would not work, that's the main problem of this topic)
  • My js gets a response with a valid auth token!
  • My js can now use this token to post /cas/sessions and so on

So in this way the user authenticates himself only once on the standard SASLogon form to get to SASReportViewer, and with the "/fake" trick I recycle its session auth cookie to get a valid auth token. (Just to point out, XSRF is not needed in any of these steps, while is needed on the standard SASLogon form of course but this is handled directly by the form).

 

If someone has a better way to accomplish this without the "/fake" trick please share!

 

References I used to study this topic:

https://docs.cloudfoundry.org/api/uaa/version/4.30.0/index.html#overview

https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2018/1737-2018.pdf

https://blogs.sas.com/content/sgf/2019/01/25/authentication-to-sas-viya/

 

Thank you

Regards

 

 

View solution in original post

7 REPLIES 7
kumardeva
SAS Employee

 . My first WAG is that you have run into XSRF issue. To be absolutely sure it would be useful to see the code you where you are making the api call.

 

Cheers...
Deva


Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF

View now:

Edoedoedo
Pyrite | Level 9

Hi Deva,

 

the code is pretty strightforward: there is a Report with a DDC, the DDC is linked to test.html, this page contains just a button which when is pressed calls this javascript function, i.e. using jquery:

 

 

$.post("https://viyasite/cas/sessions", function(data) {
  console.log(data); // Have I got a new cas session id?
});

This call gives:

 

 

 

{
  "error": "HTTP/1.1 403 Forbidden",
  "code": "HTTP_403",
  "details": null,
  "disposition": null
}

 

Of course I am authenticated, otherwise I would not see the Report (and I have an admin profile).

 

(Don't know if it may be useful, but note that in order to comply with corporate firewall rules our sas admin has created a reverse proxy rule to map "https://viyasite:8777/cas" to "https://viyasite/cas")

 

If I manually ask for a token (using i.e. Postman) on "/SASLogon/oauth/token" with my credential, and the use this token to access "https://viyasite/cas", it works correctly.

 

What am I missing?

kumardeva
SAS Employee

SAS Viya supports protection against Cross-site Request Forgery(XSRF) - you can see the gory details of what it is here.

 

So the fact your POST call failed with 403 is a good sign. SAS Viya is working as intended - although a current pain point for you 🙂

 

At an high level SAS sends a XSRF token to the client and expects it back for PUT and POST. This requires the client to track the tokens by service and send it back. This can be done by you but it is a non-trivial exercise - depends on your willingness to take on a project that size.

 

Note all GET calls will get through - the server only cares that you are authenticated.

 

If you are not into "rolling your own" solution, you can use the restaf  library that handles this scenario (and  a lot more). 

 

 

Cheers...
Deva

 

 

 

 


Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF

View now:

Edoedoedo
Pyrite | Level 9

Hi Deva,

 

yes I have already checked out restaf and I will surely use it since it has everything covered!

 

However before to use it I want to fully understand what happens at low level.

 

About XSRF: I am well aware of XSRF mechanism, in fact I used it for instance to automate the execution of jobs on /SASJobExecution.

However in this case, for CAS API, documentation says nothing about XSRF (https://developer.sas.com/apis/cas/rest/current/apidoc.html), and in any case I can't find to which endpoint should I request the xsrf token and also where in the /cas/sessions POST request should I supply the xsrf token.

 

Moreover, when I simulate an auth token request with oauth2 on Postman with my credentials, and I use this auth token to access /cas/sessions, it works very well without supplying any xsrf token. So I think the CAS APIs don't make use of XSRF protection, and it makes sense since REST APIs are stateless and do not use cookies (so there is no risk that a malicious user would forge a fake request with session based authentication).

 

Also, a GET request to /cas/sessions (to get the list of active sessions) does not work either (same response: 403 Unauthorized) but it work in Postman with the oauth token, exactly the same way as the POST request. And as you say, GET requests doesn't use XSRF.

 

Hence I believe XSRF is not the problem in this case. Does it make sense to you?

 

Thanks

Regards

kumardeva
SAS Employee

 

 

  • You cannot create session with a GET – it should fail since you have to use POST method.

 

  • The XSRF protection occurs at the http server that fronts all incoming requests and not at the cas level. 

 

  • Since I was quickly getting into deep waters when I can barely swim I got the final word from the developer who handles such esoteric things for SAS Viya:

 

CSRF is in play when using HTTP sessions.   If you’re calling services with an access token and no HTTP session cookie, you won’t see CSRF.  Web apps like VA run in the browser and use HTTP sessions. If the browser is calling a service with an HTTP session (and no token), and it is doing a POST/PUT/DELETE, it must pass a CSRF token along with the request.  The CSRF tokens really only applies to an app running in the browser, using HTTP sessions instead of access tokens.

 

That pretty much exhausts my knowledge on this topic 🙂

Cheers...
Deva


Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF

View now:

Edoedoedo
Pyrite | Level 9

Hi Deva,

 

taking inspiration from your quote I found a way to do what i need! The problem in fact is:

  • The user is authenticated on SASReportViewer, which uses a session-based authentication
  • The user wants to access the CAS APIs, which use a token-based authentication

So basically knowing this I would say that there is no way to recycle the session auth to get a token. And this problem happens the same on restaf of course, the user must insert his credentials twice.

 

I found out a "dirty" way Smiley Very Happy

 

  • I created a new oauth client on /SASLogon/oauth/clients with this config:

 

{
	"scope": [
                "openid",
                "*"
            ],
            "client_id": "xxx",
            "client_secret": "yyy",
            "resource_ids": [
                "none"
            ],
            "authorized_grant_types": [
                "authorization_code",
                "password",
                "refresh_token"
            ],
            "redirect_uri": [
                "/fake"
            ],
            "autoapprove": [
                "true"
            ],
            "authorities": [
                "uaa.resource",
                "sasapp"
            ],
            "use-sessions": "true"
}

(note the "/fake" redirect uri)

 

 

So:

  • The user authenticates himself on SASReportViewer, and gets a session auth cookie
  • After that, my js sends a request to /SASLogon/oauth/authorize asking for a 'code' response_type, and sends together the session auth cookie the user has already got
  • My js gets a response with a redirect to /fake which in turns gets 404 not found (of course, it's fake!)
  • But, in the /fake redirect url there is the valid response code!
  • My js grabs this response code, and sends a request to /SASLogon/oauth/token with the oauth client_id and client_secret, and the response code, without sending the session auth cookie (it would not work, that's the main problem of this topic)
  • My js gets a response with a valid auth token!
  • My js can now use this token to post /cas/sessions and so on

So in this way the user authenticates himself only once on the standard SASLogon form to get to SASReportViewer, and with the "/fake" trick I recycle its session auth cookie to get a valid auth token. (Just to point out, XSRF is not needed in any of these steps, while is needed on the standard SASLogon form of course but this is handled directly by the form).

 

If someone has a better way to accomplish this without the "/fake" trick please share!

 

References I used to study this topic:

https://docs.cloudfoundry.org/api/uaa/version/4.30.0/index.html#overview

https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2018/1737-2018.pdf

https://blogs.sas.com/content/sgf/2019/01/25/authentication-to-sas-viya/

 

Thank you

Regards

 

 

kumardeva
SAS Employee

Hi EduxEdux:

 

Interesting approach to solving the problem . Kudos to you..

 

Just to complete the discussion I am including a simple example of using restaf to run a cas action(echo in this case) when using the DDC or the web content component in VA.

 

If you are satisfied with your solution can you mark the issue as solved?

 

Cheers..

Deva

 


Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF

View now:

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!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 7 replies
  • 4630 views
  • 7 likes
  • 2 in conversation