CAS server in Angular JS + spring REST API architecture

3,630 views
Skip to first unread message

Filip Majernik

unread,
Jul 7, 2017, 12:17:02 PM7/7/17
to CAS Community
I have a following architecture:

1.) CAS 5.1 authentication server 
2.) Angular JS single page client which is accessing a REST API for the data
3.) Spring REST API

I need to secure the REST API calls from the angular JS client. I.e. only authenticated users should be able to communicate with the REST API through the angular JS application.

At the beginning, I thought I could solve this with an OAuth server support in CAS, but this would mean that every call to the REST API would require to check the access token against CAS if it is still valid.

According to the documentation it should be possible to do this with proxy tickets. Is my assumption here correct? So it would work like this:
1.) The Angular JS application requests a PROXY GRANTING TICKET by providing the username/password to the CAS
2.) Then it calls any REST API method with this PGT
3.) The spring security in the REST API would request a proxy ticket with this PGT.
4.) All the subsequent calls to the REST API would be done with the PROXY TICKET and the REST API would not need to check the ticket validity against the CAS again.

The only thing I do not understand here (coming from this http://docs.spring.io/spring-security/site/docs/3.1.6.RELEASE/reference/cas.html#cas-pt-client) is, that it requires to set the proxyReceptorUrl  . Does this mean that the proxy ticket cannot be obtained in some synchronous way, but rather it is sent to that URL?

Thanks.

Colin Wilkinson

unread,
Jul 7, 2017, 5:25:44 PM7/7/17
to cas-...@apereo.org
Hi,

I am looking at intergrating CAS with angular not angularjs. I came across this website during my travels and unsure if it helps.

https://github.com/fedon/spring-cas-auth

Regrads,
Colin

--
- CAS gitter chatroom: https://gitter.im/apereo/cas
- CAS mailing list guidelines: https://apereo.github.io/cas/Mailing-Lists.html
- CAS documentation website: https://apereo.github.io/cas
- CAS project website: https://github.com/apereo/cas
---
You received this message because you are subscribed to the Google Groups "CAS Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cas-user+unsubscribe@apereo.org.
To view this discussion on the web visit https://groups.google.com/a/apereo.org/d/msgid/cas-user/64bc9900-7305-4769-9f31-f4e1303b5ef8%40apereo.org.

Pascal Rigaux

unread,
Jul 8, 2017, 12:39:57 PM7/8/17
to cas-...@apereo.org
Hi,

Do you really need the handle username/password? Most CAS applications
avoid this since it breaks SSO.

A simple solution for AngularJS application is to do as many other
apps: require a valid session an all html pages [*]

Example : https://github.com/fedon/spring-cas-auth .

SPA allows relogging without loosing "browser" activity (eg: textarea
content). Here is a tutorial application with phpCAS that shows
various ways to handle CAS relog in a SPA :
https://github.com/prigaux/angular-seed

* forked from "angular-seed" (an old version)
added some php pages
kept index.html, but the app really is index.php

* every commits shows a different functionality. To understand them,
start from the first one, then have a look at the more advanced
features:
- CAS example : minimal casification
- CAS example using http-auth-interceptor : same but using a module
intercepting every $http calls
- use ngRoute "resolve" : avoid displaying page "view1" until the user
is authenticated
- replace alert with modal window from angular UI Bootstrap : prepares
the next commit
- add transparent relog using jsonp + CAS gateway : if app session is
expired, try transparent login on CAS using JSONP
- add relog using window.open+postMessage : if transparent relog
failed, instead of restarting application, use window.open+postMessage

* to make it work:

git clone --depth 4 https://github.com/prigaux/angular-seed.git
angular-seed-phpCAS
cd angular-seed-phpCAS
bower install

You need phpCAS :
https://wiki.jasig.org/display/CASC/phpCAS+installation+guide

Happy CAS,
cu


[*] if your first page is static AND CAS protected, you must ensure it
is not browser cached


--
Pascal Rigaux

Filip Majernik

unread,
Jul 10, 2017, 3:34:41 AM7/10/17
to CAS Community
Hi Pascal,
the reason why I need this is, that the REST API calls can also be performed only by an authorized user. This means that the AngularJS app must send some token alongside with the request to my REST API and the REST API must be able to validate that token.

So the main problem for me is not to login (this can be done with a redirect, or with posting the username/password, I do not really mind), but to validate the token in my REST API. Because I do not want to create another http request to the CAS server everytime the Angular app makes a request.

Bye,
Filip

Pascal Rigaux

unread,
Jul 10, 2017, 7:35:23 AM7/10/17
to cas-...@apereo.org
Hi,

With CAS protocol, your API MUST create its own token/session:
CAS ticket is a one time token, no way to rely on it.

Another solution is to use OpenID Connect, it should work with CAS >= 5.1 :
- enable OpenID Connect
- use implicit flow to obtain CAS generated JWT
- send JWT to your API
- REST API checks JWT signature against jwks_uri

Example : https://area51.univ-paris1.fr/prigaux/test-oidc.html (you
must logged on google first)

Drawbacks:
- no easy single logout (major pb for us)

French presentation on this: https://prigaux.frama.io/JwtProxyService/

cu


Filip Majernik <filip.m...@gmail.com> a écrit :

Filip Majernik

unread,
Jul 10, 2017, 8:16:48 AM7/10/17
to CAS Community
Still, the PROXY TICKETs should be possible for my scenario (according to this - http://docs.spring.io/spring-security/site/docs/3.1.6.RELEASE/reference/cas.html#cas-pt-client). But I do not understand why does it have to be obtained via a callback URL. Also from some reason the CAS REST API provides method for obtaining the tickets, etc... but not PROXY TICKETs, which sucks. 

But anyway, what is then the best solution to user for this scenario (if I want to have CAS as the authentication server):
1.) AngaluarJS GUI - served by some apache server - it does not contain any sensitive data, just forms
2.) REST API - deployed as a spring resource server
3.) CAS server

I need a way (some security protocol) where user authenticates in cas and would be able to access the protected stateless REST resources and be authenticated.

Julien Gribonvald

unread,
Jul 10, 2017, 8:33:56 AM7/10/17
to cas-...@apereo.org
Hi Filip,

Did you watch on what is possible with spring security ? there are
several possibilities to secure your REST API, and in my mind jwt is a
good option.

I developped an angular app and used spring-security, I didn't used the
jwp protocol as it was not well documented when I developped my app but
I think I would you use it now.
My app can be found here : https://github.com/EsupPortail/esup-publisher
Or if you prefer you can find a POC of the auth mecanism here :
https://github.com/jgribonvald/demo-spring-cas-angular or someone made a
documented and more advanced example here :
https://github.com/rohajda/casdemo (he used my POC).

For jwt example you can rely on Pascal's explanations, or maybe on web
you can find easily somes well explaned documentations (search on
"spring security jwt").

Thanks
Julien

Filip Majernik

unread,
Jul 10, 2017, 9:15:36 AM7/10/17
to CAS Community, julien.g...@recia.fr
First of all, thank you all for the responses, it helps me very much. I will take a look on that example with Angular.

However, I think I've found a solution (or at least going to try that way). I will go away from the OpenID or OAuth (imho I don't really think that they are well suited for what I need. Almost all the examples in spring are using the same app for the resource server as for the oauth server). I have reviewed the CAS protocol and I am going to try to implement it in this way:

1.) The angluarJS will redirect to the login page.
2.) After successful login the user is redirected to the angular app again but with a SERVICE TICKET
3.) When the first call is made to the REST API, the SERVICE TICKET would be validated and if valid, then it creates a session cookie.
4.) All the other REST API calls would get authorized unless the session cookie expires (without validating the SERVICE TICKET again).

Somehow I got fixed on the word "stateless", because the REST API is stateless. But if I really would like to be stateless, this would indeed require to contact the CAS server every time with an ACCESS TOKEN and validate if it.

So feel free to correct me if I am wrong, but I think the above described solution with the CAS protocol is fine.

Julien Gribonvald

unread,
Jul 10, 2017, 9:33:35 AM7/10/17
to Filip Majernik, CAS Community
What you described is good, and it's how work my app and examples provided.

After requesting on each request a CAS ACCESS TOKEN isn't needed, but at least on your REST server managing a token is needed or you need to manage a session cookie (or a map token/session), so the jwt token is a way to secure your app, even in my mind it's better than a cookie.
--
Julien Gribonvald

Jitendra Patil

unread,
Jan 10, 2020, 3:58:37 PM1/10/20
to CAS Community
Hi Filip,

I'm also having a similar Architecture. The approach you have mentioned worked for you ?
If yes, then please let me know what exactly you did.

Thank you

Filip Majernik

unread,
Jan 15, 2020, 3:50:06 AM1/15/20
to CAS Community
Hi Jitendra,
yes it has worked for me. I have configured it exactly like described. My application architecture is:
1.) Spring REST Api
2.) Angular JS frontend
3.) CAS Server

The configuration for CAS:
- I have not really made anything special here. Just configured the service, which is actually the URL, where the service ticket will be sent.

Spring REST API:
- I have used the Spring's CasAuthenticationFilter

The workflow is like this:
1.) The login button on the page redirects to <server-host>/cas/login?service=<SERVICE-URL>
2.) After the successful login in the CAS, it will redirect to <SERVICE-URL>?ticket=<SERVICE-TICKET>
3.) The AngularJS application on the <SERVICE-URL> then sends the ST to the Spring REST API
4.) The CasAuthenticationFilter on the REST API validates the service ticket against the CAS server
5.) If the service ticket is valid it will create an authenticated session, i.e. JSESSIONID cookie in my case.

Marc BOUVIER

unread,
May 5, 2020, 8:34:48 AM5/5/20
to CAS Community
Hi Filip,

I am in the exact same situation than you were.

I have a question though. My Angular JS Frontend and my Spring REST API are not on the same domain. I don't know if it is the same for you.

When you mention the <SERVICE-URL>, is it the Spring API or the Angular JS Frontend (or both are on the same domain?)

Do you have by any chance some example that can inspire me?

cheers :)

Jitendra Patil

unread,
May 5, 2020, 12:23:40 PM5/5/20
to CAS Community
Hi Marc,

<SERVICE-URL> is Spring API url. Please find below steps which can be followed to secure APIs and make entire flow work.

1. Open/Load frontend Application
Login: username / password

2. Click on a Sign-in and control will get redirected to CAS for Authentication

3. Enter Credentials and on a success the control will be redirected to Front-end Application with a Service Ticket

4. Call CAS API to check the Service Ticket status with proxy callback Url

- On Success, Cas returns pgtIou an xml format
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    <cas:authenticationSuccess>
        <cas:user>username</cas:user>
        <cas:proxyGrantingTicket>PGTIOU-3-64o7WGazmX-9r2lC2LTCo7mlNGh5xu07mBevm93vei-jhJWo8lsviL-aHRNcI-MHK04-49f49b7e1211</cas:proxyGrantingTicket>
        <cas:attributes> // as of now we are not using below parameters so we can ignore them
            <cas:credentialType>UsernamePasswordCredential</cas:credentialType>
            <cas:isFromNewLogin>true</cas:isFromNewLogin>
            <cas:authenticationDate>2020-01-30T13:12:06.215Z[Etc/UTC]</cas:authenticationDate>
            <cas:authenticationMethod>LdapAuthenticationHandler</cas:authenticationMethod>
            <cas:successfulAuthenticationHandlers>LdapAuthenticationHandler</cas:successfulAuthenticationHandlers>
            <cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>
        </cas:attributes>
    </cas:authenticationSuccess>
</cas:serviceResponse>

- On Failure
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    <cas:authenticationFailure code="INVALID_TICKET">Ticket &#39;ST-56-EenPWIje1NG-GcI3TjAxoDOpKlQ-49f49b7e1211&#39; not recognized</cas:authenticationFailure>
</cas:serviceResponse>

- here API server receives a PgtIn & PgtOut ids in call-back api and in next step UI should make a call to return PgtId with the help of proxyGrantingTicket

5. Call Services API to get the pgtId using "<cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket>"
- On Success
{
    "pgtId": "PGT-32-RlLIQhAkXISAqouOO2qyoTCYkYkTQSmJQueUoZdjHiCVJLuF8Nvx6Yf6pDka-iFO5Fo-49f49b7e1211"
}

- On Failure, redirect a user to CAS login page
{
    "timestamp": "2020-01-30T13:15:44.702+0000",
    "status": 404,
    "error": "Not Found",
    "message": "pgtIou not found",
    "path": "/validate-pgt"
}


6. Call CAS API using pgtId to generate a Proxy Ticket
- On Success
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    <cas:proxySuccess>
        <cas:proxyTicket>PT-57-XDtbTbI9GH3pVZr3qltelIE3kPk-49f49b7e1211</cas:proxyTicket>
    </cas:proxySuccess>
</cas:serviceResponse>

- On Failure
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    <cas:proxyFailure code="INVALID_TICKET">Ticket &#39;PGT-2-RlLIQhAkXISAqouOO2qyoTCYkYkTQSmJQueUoZdjHiCVJLuF8Nvx6Yf6pDka-iFO5Fo-49f49b7e1211&#39; not recognized</cas:proxyFailure>
</cas:serviceResponse>


7. Call Services API with proxy ticket 
- here you have to call a cas server to check the validity of a proxy-ticket 
Response from CAS 
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas"> 
    <cas:authenticationSuccess>
      <cas:user>username</cas:user>
      <cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket>
      <cas:proxies>
        <cas:proxy>https://proxy2/pgtUrl</cas:proxy>
        <cas:proxy>https://proxy1/pgtUrl</cas:proxy>
      </cas:proxies>
    </cas:authenticationSuccess> 
  </cas:serviceResponse>

8. Once 7th steps gets verified then you can go with cookies or JWT mechanism OR follow the 6 & 7th steps to secure each and every api. choice is yours.

Thank you.

Marc BOUVIER

unread,
May 6, 2020, 10:27:55 AM5/6/20
to CAS Community
Hi Jitendral, 

Thank you for your very detailled answer.

I will try to rephrase to make sure I understood well.


1. Open https://ui-domain.com/
2. Click on <Sign In> -> Redirect from https://ui-domain.com/ to https://cas-domain.com (credential input form)
3. On https://cas-domain.com type user credentials : Redirection from https://cas-domain.com to https://ui-domain.com (with Service Ticket)
4. Call from https://ui-domain.com/ to https://cas-domain.com to validate ST and provide callback for https://ui-domain.com/ and PGT URI for https://services.com. Get back a response with PGTIOU
5. Call from  https://ui-domain.com/ to https://services.com with PGTIOU to get a PGTID (or redirect to https://cas-domain.com if not found)
  • Here, I am a bit confused, are the PGT values in your example the same or different values?
    • (4.) [...] <cas:proxyGrantingTicket>     PGTIOU-3-64o7WGazmX-9r2lC2LTCo7mlNGh5xu07mBevm93vei-jhJWo8lsviL-aHRNcI-MHK04-49f49b7e1211 [...]
    • (5.) [...] get the pgtId using "<cas:proxyGrantingTicket>PGTIOU-84678-8a9d... [...]
    • (5.) [...] "pgtId": "PGT-32-RlLIQhAkXISAqouOO2qyoTCYkYkTQSmJQueUoZdjHiCVJLuF8Nvx6Yf6pDka-iFO5Fo-49f49b7e1211" [...]
6. Call from https://ui-domain.com/ to https://cas-domain.com with PGTID from (5.). Get back a PT on success or an error if invalid ticket.
7. Call from https://ui-domain.com/ to https://services.com with PT from (6.)
  • Call from https://services.com to https://cas-domain.com  with PT to check PT validity and get username + PGT (will it be used?)
  • From here I can get additional informations about the user by querying the CAS annuary.
8. Create a session or use JWT to allow API to know who is connected when the API is called by the UI.

Filip Majernik

unread,
May 6, 2020, 10:50:39 AM5/6/20
to cas-...@apereo.org
Hi Marc,
what Jitendral has written sounds correct to me, with one small change. In my environment the SERVICE_URL is actually the UI-url not the Spring API. The Spring API is then called with the Service-Ticket to log in and the Spring API validates the ST against a CAS instance. If everything is fine it issues a SESSION ID cookie so the UI can communicate with the API.

--
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
---
You received this message because you are subscribed to a topic in the Google Groups "CAS Community" group.
To unsubscribe from this topic, visit https://groups.google.com/a/apereo.org/d/topic/cas-user/VSrkz58Z9EE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to cas-user+u...@apereo.org.
To view this discussion on the web visit https://groups.google.com/a/apereo.org/d/msgid/cas-user/92c98a04-9ac0-4c92-b466-6438757cecd6%40apereo.org.

Jitendra Patil

unread,
May 6, 2020, 10:57:14 AM5/6/20
to CAS Community

Hi Marc, 

My example is has wrong/non matching PGT values, Please ignore the values. For clarity. 

- In step 4, UI try to generate a PGT using ST from CAS server. CAS server will return the PGTOU to UI and (PGTID + PGTOU) to call-back(REST API Server) url. 
- In step 5, UI request for a PGTID from a REST API with the help of PGTOU. 
- In step 6, UI try to generate a PT using PGTID from CAS Server and forward the same to REST API.
- In step 7, REST API validates the PT from CAS server and in response receives user attributes. 
- after step 7 you can generate your own JWT token to secure all APIs or can perform step 6 & 7 for all APIs to secure  


Marc BOUVIER

unread,
May 6, 2020, 11:42:52 AM5/6/20
to CAS Community
Hi Filip,

Thank you again for your answer.

Are your Backend and Frontend on the same domain?

Do you have something like the following: 


or do you have something more like


Le mercredi 6 mai 2020 16:50:39 UTC+2, Filip Majernik a écrit :
Hi Marc,
what Jitendral has written sounds correct to me, with one small change. In my environment the SERVICE_URL is actually the UI-url not the Spring API. The Spring API is then called with the Service-Ticket to log in and the Spring API validates the ST against a CAS instance. If everything is fine it issues a SESSION ID cookie so the UI can communicate with the API.

To unsubscribe from this group and all its topics, send an email to cas-...@apereo.org.
Reply all
Reply to author
Forward
0 new messages