User Tools

Site Tools


development:applications:singlesignon

Single Sign On (CAS) Configuration

Configuration of the CAS Infrastructure on the Errigal IDMS is outlined on the bitbucket repo

https://bitbucket.org/errigal/cas-overlay-template/overview


Overview

Errigal's Single Sign On Implementation uses https://www.apereo.org/projects/cas, the WAR overlay project is used and Errigal's modifications are stored in bitbucket.

CAS authenticates selected Services against a number of Authentication Handlers. The configuration of these are outlined in the Configuration section.

From a high level, the authentication process is:

  • If the user is not logged into the NocPortal or have a Single Sign on Session active, they are redirected to https://domain.com/cas
    • The CAS URL is defined in Config.groovy for example
  • A user enters their user name and password, if it is successful against any one of the authentication handlers, the user logs into the SSO service and a Ticket Granting Ticket (TGT) is created. This is stored in a Session cookie.
  • The user is now redirected to https://domain.com/NocPortal/shiro-cas and CAS realm is invoked
    • This mapping is done by the shiro-cas-plugin
  • A redirect no occurs to https://domain.com/cas to generate a Service Ticket (ST)
  • The ST is then verified against CAS and the TGT to ensure the user can login
  • The user is then logged into the NocPortal with a normal session and the NocPortal now uses its Roles to authorise the user to their allowed functionality
    • If a user does not have an account in the NocPortal, the local ShiroDbRealm will notify them that they do not have permission

This process is described here https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol.html but the main points are copied below.

The CAS protocol is a simple and powerful ticket-based protocol developed exclusively for CAS. A complete protocol specification may be found here.

It involves one or many clients and one server. Clients are embedded in CASified applications (called “CAS services”) whereas the CAS server is a standalone component:

The CAS server is responsible for authenticating users and granting accesses to applications The CAS clients protect the CAS applications and retrieve the identity of the granted users from the CAS server. The key concepts are:

The TGT (Ticket Granting Ticket), stored in the CASTGC cookie, represents a SSO session for a user The ST (Service Ticket), transmitted as a GET parameter in urls, stands for the access granted by the CAS server to the CASified application for a specific user. Specification versions

The current CAS protocol specification is 3.x. The actual protocol specification is available at CAS-Protocol-Specification, which is hereby implemented by the Apereo CAS Server as the official reference implementation. It’s mainly a capture of the most common enhancements built on top of the CAS protocol revision 2.0. Among all features, the most noticeable update between versions 2.0 and 3.0 is the ability to return the authentication/user attributes through the new /p3/serviceValidate response (in addition to the /serviceValidate endpoint, already existing for CAS 2.0 protocol).


Troubleshooting

Exception "javax.net.ssl.SSLException: Received fatal alert: protocol_version" (SnmpManager)

Exception:

2018-11-30 07:32:06,013 [ajp-bio-8012-exec-37] ERROR util.CommonUtils  - Received fatal alert: protocol_version
 javax.net.ssl.SSLException: Received fatal alert: protocol_version
        at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:328)
        at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:305)
        at org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:50)
        at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:207)
        at com.errigal.snmpmanager.ShiroCasRealm.authenticate(ShiroCasRealm.groovy:26)
        at org.apache.shiro.grails.RealmWrapper.getAuthenticationInfo(RealmWrapper.groovy:59)
        at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doMultiRealmAuthentication(ModularRealmAuthenticator.java:219)
        at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:269)
        at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
        at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
        at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:270)
        at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:256)
        at org.apache.shiro.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java:53)
        at org.apache.shiro.cas.CasFilter.onAccessDenied(CasFilter.java:85)
        at org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(AccessControlFilter.java:133)
        at org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:162)
        at org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java:203)
        at org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:178)
        at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:131)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
        at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:76)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
        at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
        at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
        at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
        at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
2018-11-30 07:32:06,013 [ajp-bio-8012-exec-37] INFO  app.realm  - Unable to authenticate with com.errigal.snmpmanager.ShiroCasRealm - javax.net.ssl.SSLException: Received fatal alert: protocol_version
 2018-11-30 07:32:06,506 [ajp-bio-8012-exec-33] INFO  snmpmanager.AuthController  - SSOFAILURE - check the grails and cas server logs, redirecting to fallback login

Resolution:

  • Add the -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 line to the java_opts of the startup.sh script - script location: var/tomcat/{app_name}/bin/
  • Consult with the rest of the dev team regarding the env_configuration repository update.

*Config.groovy Changes

The following parameters are required in the deployed *Config.groovy, e.g. SnmpManagerConfig.groovy, for SSO to work

grails.serverURL='https://nocportal.extenetsystems.com/SnmpManager'
enableSingleSignOn = true
security.shiro.cas.serverUrl = 'https://nocportal.extenetsystems.com/cas'

Accessing Specific Handlers

To access an application on a specific handler, you need to instantiate the fallback URL

http://qaapps1.err:8082/SnmpManager/auth/login?fallback=true

You are then free to access the application handler as normal

Disabling SSO

SSO can be disabled via *Config.groovy, set

enableSingleSignOn = false

and restart the application. Note if restarting in production, the customer needs to be notified, alarms acknowledge etc.

JMX (Visual VM)

Accessible via port 9418

Distributed Ticket Cache

The distributed ticket cache is an in memory, distributed hazelcast instance, please see the bitbucket configuration page.

All logging is prepended with com.hazelcast., for example, when you start up the second handler in the cluster, you should see logging like

2016-08-16 05:38:33,721 INFO [com.hazelcast.nio.tcp.TcpIpConnectionManager] - [ccicerrigalapps1]:5701 [dev] [3.6.2] Established socket connection between /10.30.95.51:5701 and /10.30.95.52:57788

2016-08-16 05:38:40,710 INFO [com.hazelcast.cluster.ClusterService] - [ccicerrigalapps1]:5701 [dev] [3.6.2]

Members [2] {
        Member [ccicerrigalapps1]:5701 this
        Member [ccicerrigalapps2]:5701
}

Authentication is failing

  • If you are working in dev with a CAS server on QA, the authentication will actually happen on the QA server. This means the user will need to exist in the QA database, the authorisation will take place on your local dev box, that is, the verification of roles and permissions
  • If you are using a self signed certificate in your cas server (as is the case for QA) you need to ensure this cert is added to your cacerts of your jdk
    • Export the cert using Firefox
    • Add this cert to your jdk using keytool (the default keystore password is changeit)
      • sudo keytool -importcert -file certs/qalb1.crt -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/security/cacerts -alias qalb1
  • If the certificate on the production system is not recognised by Java, you will need to add the cert to the production JDKs
    • Export the cert using Firefox
    • Add this cert to your jdk using keytool (the default keystore password is changeit)
      • sudo /usr/java/jdk1.7.0_80/bin/keytool -importcert -file scnoc.crowncastle.com -keystore /usr/java/jdk1.7.0_80/jre/lib/security/cacerts -alias scnoc.crowncastle.com
      • sudo /usr/java/jdk1.6.0_30/bin/keytool -importcert -file scnoc.crowncastle.com -keystore /usr/java/jdk1.6.0_30/jre/lib/security/cacerts -alias scnoc.crowncastle.com
      • sudo /usr/java/jdk1.6.0_30/bin/keytool -importcert -file nocportal.extenetsystems.com -keystore /usr/java/jdk1.6.0_30/jre/lib/security/cacerts -alias nocportal.extenetsystems.com
  • Ensure the time on all CAS handlers is the same

Application Not Authorized to Use CAS

If you attempt to log into a CAS managed service and you receive the error

Application Not Authorized to Use CAS The application you attempted to authenticate to is not authorized to use CAS

This means that the application you are trying to access is not configured as a service. The service is defined in as the service parameter of the URL

https://qalb1.err/cas/login?service=https://qalb1.err/SnmpManager/shiro-cas

These services are configured as JSON files in /usr/local/conf/cas/services. Before adding any more files here

If you are adding a service you should note :

  • serviceId needs to be unique
  • Services reload at runtime, tail cas.log to see this
  • Service file will need to be added on all handlers

Ticket Logging

When a Ticket Granting Ticket is created, the following logging is expected

2016-08-16 05:46:50,466 INFO [org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - Audit trail record BEGIN
=============================================================
WHO: admin
WHAT: Supplied credentials: [admin]
ACTION: AUTHENTICATION_SUCCESS
APPLICATION: CAS
WHEN: Tue Aug 16 05:46:50 EDT 2016
CLIENT IP ADDRESS: 212.17.60.121
SERVER IP ADDRESS: scnoc.crowncastle.com
=============================================================


2016-08-16 05:46:50,474 INFO [org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: TGT-**********************************************R3CSks5QLN-ccicerrigalapps1
ACTION: TICKET_GRANTING_TICKET_CREATED
APPLICATION: CAS
WHEN: Tue Aug 16 05:46:50 EDT 2016
CLIENT IP ADDRESS: 212.17.60.121
SERVER IP ADDRESS: scnoc.crowncastle.com
=============================================================

A Service Ticket for the same user looks like:

2016-08-16 05:46:50,502 INFO [org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - Audit trail record BEGIN
=============================================================
WHO: admin
WHAT: ST-3-bOuFCpfRHx926yFSR7UD-ccicerrigalapps1 for http://localhost:8080/NocPortal/shiro-cas
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Tue Aug 16 05:46:50 EDT 2016
CLIENT IP ADDRESS: 212.17.60.121
SERVER IP ADDRESS: scnoc.crowncastle.com
=============================================================

Self Signed Certs

If you are setting up a CAS instance on QA for example, you will need a self signed cert. If your system is publicly accessible, a cert from a CA like godaddy is recommended as there should be less configuration or trouble shooting, as used in https://idmsqa.errigal.com/

For information on creating self signed certs see

    • openssl genrsa -des3 -out server.key 1024
    • openssl req -new -key server.key -out server.csr
    • cp server.key server.key.org
    • openssl rsa -in server.key.org -out server.key (remove passphrase from key)
    • openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
    • If you are installing certs in Apache (load balancer or web server), typically in ssl.conf (after installing mod_ssl)
      • Note you will also need /etc/httpd/modules/mod_ssl.so file else ssl will not work
      • Note you may need to create the ssl.conf file which should be located : /etc/httpd/conf.d
      • SSLCertificateFile <path>/server.crt
      • SSLCertificateKeyFile <path>/server.key
    • If you are installing certs on tomcat
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" 
                scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="/home/john/.keystore" keystorePass="n******1"
           clientAuth="false" sslProtocol="TLS"
        />

Integrate Single Sign On in Grails 3

Dependencies

Used in Support Page project using Grails 3.2.6 on March 2017

  compile 'org.grails.plugins:spring-security-core:3.1.1'
  compile 'org.grails.plugins:spring-security-cas:3.0.0'

Documentation

Create User Domain

You need to create User Domain using Spring Security.

Run following command

grails s2-quickstart com.yourapp User Role

Bootstrap


@Secure on your controllers

By default, you have to specify @Secure annotation to all controller.

You can change this by editing staticRules in application.groovy http://grails-plugins.github.io/grails-spring-security-core/v3/index.html#requestMappings

Application.yml

CAS Plugin document mentions that proxyCallbackUrl and proxyReceptorUrl should be set but It isn't in our Single Sign On Implementation

---
grails:
   plugin:
      springsecurity:
         cas:
            loginUri: /login
            serviceUrl: http://10.5.5.8:8088/Support/login/cas
            serverUrlPrefix: http://10.5.5.8:8080/cas

Update CAS Login Page

If you need to change Logo and Poweredby Image, open cas-overlay-template and edit top.jsp which is located in src/main/webapp/WEB_INF/view/default/ui/includes


Exposing Grails Application On Domain

On the load balancer:

/etc/httpd/conf/mod-jk.conf

add:
JkMount /search/ SnmpManagerLoadBalancer
JkMount /search/* SnmpManagerLoadBalancer
JkMount /search SnmpManagerLoadBalancer
/etc/httpd/conf/workers.conf

add the SnmpManagerLoadBalancer to worker.list

At the end:
worker.SnmpManagerLoadBalancer.balance_workers=SnmpManagerWorker1

And where the workers are:
worker.SnmpManagerLoadBalancer.type=lb
worker.SnmpManagerLoadBalancer.sticky_session=1
worker.SnmpManagerWorker1.reference=worker.ajptemplate
worker.SnmpManagerWorker1.host=qaapps1.err
worker.SnmpManagerWorker1.port=8096
worker.SnmpManagerWorker1.reply_timeout=600000

Finally, restart the HTTPD so that the new settings take effect:

sudo service httpd restart

To debug, tail the following logs:

/var/log/httpd/error_log
/var/log/httpd/mod_jk.log
development/applications/singlesignon.txt · Last modified: 2021/06/25 10:09 by 127.0.0.1