User Tools
Writing /app/www/public/data/meta/development/applications/singlesignon.meta failed
development:applications:singlesignon
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| development:applications:singlesignon [2017/05/26 12:24] – mmcc | development:applications:singlesignon [2021/06/25 10:09] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Single Sign On (CAS) Configuration ====== | ||
| + | |||
| + | Configuration of the CAS Infrastructure on the Errigal IDMS is outlined on the bitbucket repo | ||
| + | |||
| + | https:// | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ====== Overview ====== | ||
| + | |||
| + | Errigal' | ||
| + | |||
| + | CAS authenticates selected **Services** against a number of **Authentication Handlers**. | ||
| + | |||
| + | From a high level, the authentication process is: | ||
| + | |||
| + | * User hits https:// | ||
| + | * If the user is not logged into the NocPortal or have a Single Sign on Session active, they are redirected to https:// | ||
| + | * 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:// | ||
| + | * This mapping is done by the shiro-cas-plugin | ||
| + | * A redirect no occurs to https:// | ||
| + | * 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:// | ||
| + | |||
| + | 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, | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ====== Troubleshooting ====== | ||
| + | |||
| + | ===== Exception " | ||
| + | Exception: | ||
| + | <code java> | ||
| + | 2018-11-30 07: | ||
| + | | ||
| + | at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java: | ||
| + | at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java: | ||
| + | at org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java: | ||
| + | at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java: | ||
| + | at com.errigal.snmpmanager.ShiroCasRealm.authenticate(ShiroCasRealm.groovy: | ||
| + | at org.apache.shiro.grails.RealmWrapper.getAuthenticationInfo(RealmWrapper.groovy: | ||
| + | at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doMultiRealmAuthentication(ModularRealmAuthenticator.java: | ||
| + | at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java: | ||
| + | at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java: | ||
| + | at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java: | ||
| + | at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java: | ||
| + | at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java: | ||
| + | at org.apache.shiro.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java: | ||
| + | at org.apache.shiro.cas.CasFilter.onAccessDenied(CasFilter.java: | ||
| + | at org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(AccessControlFilter.java: | ||
| + | at org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java: | ||
| + | at org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java: | ||
| + | at org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java: | ||
| + | at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java: | ||
| + | at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: | ||
| + | at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java: | ||
| + | at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java: | ||
| + | at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java: | ||
| + | at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java: | ||
| + | at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java: | ||
| + | at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java: | ||
| + | at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java: | ||
| + | at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java: | ||
| + | at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java: | ||
| + | at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: | ||
| + | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: | ||
| + | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java: | ||
| + | at java.lang.Thread.run(Thread.java: | ||
| + | 2018-11-30 07: | ||
| + | | ||
| + | </ | ||
| + | |||
| + | Resolution: | ||
| + | * Add the **-Dhttps.protocols=TLSv1, | ||
| + | * 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, | ||
| + | |||
| + | < | ||
| + | grails.serverURL=' | ||
| + | enableSingleSignOn = true | ||
| + | security.shiro.cas.serverUrl = ' | ||
| + | </ | ||
| + | |||
| + | ===== Accessing Specific Handlers ===== | ||
| + | |||
| + | To access an application on a specific handler, you need to instantiate the fallback URL | ||
| + | |||
| + | < | ||
| + | http:// | ||
| + | </ | ||
| + | |||
| + | You are then free to access the application handler as normal | ||
| + | |||
| + | ===== Disabling SSO ===== | ||
| + | |||
| + | SSO can be disabled via *Config.groovy, | ||
| + | |||
| + | < | ||
| + | enableSingleSignOn = false | ||
| + | </ | ||
| + | |||
| + | and restart the application. | ||
| + | |||
| + | ===== 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 // | ||
| + | |||
| + | < | ||
| + | 2016-08-16 05: | ||
| + | |||
| + | 2016-08-16 05: | ||
| + | |||
| + | Members [2] { | ||
| + | Member [ccicerrigalapps1]: | ||
| + | Member [ccicerrigalapps2]: | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Authentication is failing ===== | ||
| + | |||
| + | * If you are working in dev with a CAS server on QA, the authentication will actually happen on the QA server. | ||
| + | * 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/ | ||
| + | * 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 / | ||
| + | * sudo / | ||
| + | * sudo / | ||
| + | * 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 | ||
| + | |||
| + | // | ||
| + | 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. | ||
| + | |||
| + | https:// | ||
| + | |||
| + | These services are configured as JSON files in / | ||
| + | |||
| + | * Ensure you are trying to authenticate with the correct server, you don't want to add a service of https:// | ||
| + | * Ensure you are accessing the service through the correct URL, that is https:// | ||
| + | * Check / | ||
| + | |||
| + | |||
| + | 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: | ||
| + | ============================================================= | ||
| + | WHO: admin | ||
| + | WHAT: Supplied credentials: | ||
| + | ACTION: AUTHENTICATION_SUCCESS | ||
| + | APPLICATION: | ||
| + | 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: | ||
| + | ============================================================= | ||
| + | WHO: audit: | ||
| + | WHAT: TGT-**********************************************R3CSks5QLN-ccicerrigalapps1 | ||
| + | ACTION: TICKET_GRANTING_TICKET_CREATED | ||
| + | APPLICATION: | ||
| + | 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: | ||
| + | ============================================================= | ||
| + | WHO: admin | ||
| + | WHAT: ST-3-bOuFCpfRHx926yFSR7UD-ccicerrigalapps1 for http:// | ||
| + | ACTION: SERVICE_TICKET_CREATED | ||
| + | APPLICATION: | ||
| + | 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:// | ||
| + | |||
| + | For information on creating self signed certs see | ||
| + | |||
| + | * http:// | ||
| + | * 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 | ||
| + | * 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 / | ||
| + | * Note you may need to create the ssl.conf file which should be located : / | ||
| + | * SSLCertificateFile < | ||
| + | * SSLCertificateKeyFile < | ||
| + | * If you are installing certs on tomcat | ||
| + | * Install generated certs into keystore | ||
| + | * https:// | ||
| + | * keytool -import -alias root -keystore < | ||
| + | * keytool -import -alias tomcat -keystore < | ||
| + | * Configure connector in server.xml | ||
| + | |||
| + | < | ||
| + | < | ||
| + | | ||
| + | | ||
| + | scheme=" | ||
| + | | ||
| + | | ||
| + | /> | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ====== Integrate Single Sign On in Grails 3 ====== | ||
| + | |||
| + | ===== Dependencies ===== | ||
| + | Used in Support Page project using Grails 3.2.6 on March 2017 | ||
| + | |||
| + | < | ||
| + | compile ' | ||
| + | compile ' | ||
| + | </ | ||
| + | |||
| + | ===== Documentation ===== | ||
| + | |||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | |||
| + | ===== Create User Domain ===== | ||
| + | You need to create User Domain using Spring Security. | ||
| + | |||
| + | [[http:// | ||
| + | < | ||
| + | |||
| + | ==== Bootstrap ==== | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ===== @Secure on your controllers ===== | ||
| + | |||
| + | By default, you have to specify [[http:// | ||
| + | |||
| + | You can change this by editing staticRules in application.groovy | ||
| + | http:// | ||
| + | |||
| + | ===== Application.yml ===== | ||
| + | |||
| + | CAS Plugin document mentions that proxyCallbackUrl and proxyReceptorUrl should be set but **It isn't in our Single Sign On Implementation** | ||
| + | |||
| + | < | ||
| + | --- | ||
| + | grails: | ||
| + | | ||
| + | springsecurity: | ||
| + | cas: | ||
| + | loginUri: /login | ||
| + | serviceUrl: http:// | ||
| + | serverUrlPrefix: | ||
| + | </ | ||
| + | |||
| + | ===== 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/ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ===== Exposing Grails Application On Domain ===== | ||
| + | On the load balancer: | ||
| + | < | ||
| + | / | ||
| + | |||
| + | add: | ||
| + | JkMount /search/ SnmpManagerLoadBalancer | ||
| + | JkMount /search/* SnmpManagerLoadBalancer | ||
| + | JkMount /search SnmpManagerLoadBalancer | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | / | ||
| + | |||
| + | 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: | ||
| + | < | ||
| + | / | ||
| + | / | ||
| + | </ | ||
| + | |||