User Tools
Table of Contents
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:
- User hits https://domain.com/NocPortal
- 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
- Ensure you are trying to authenticate with the correct server, you don't want to add a service of https://localhost:8082/SnmpManager/shiro-cas to production for example, if it is a QA system, maybe you are ok with this.
- Ensure you are accessing the service through the correct URL, that is https://qalb1.err/SnmpManager/ and not http://ip_address/SnmpManager/
- Check /usr/local/conf/cas/services for the allowed services, should you be accessing your application with one of these instead?
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
- Install generated certs into keystore
-
- keytool -import -alias root -keystore <your_keystore_filename> -trustcacerts -file <filename_of_the_chain_certificate>
- keytool -import -alias tomcat -keystore <your_keystore_filename> -file <your_certificate_filename>
-
- Configure connector in server.xml
<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.
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
