CAS Developer Documentation

Table of Contents

Overview

UH Login (CAS) is available for University of Hawaiʻi (UH) Web site developers to authenticate users with their UH username and password. It alleviates the problem of having to develop a user authentication system as part of the Web-enabled application (web application) development. It also provides increased security for users by not allowing Web applications to handle their passwords (often using insecure means such as sending it in the clear or unnecessarily storing it).

UH Login (CAS) enhances security by requiring Web application developers to register their applications. This prevents rogue Web applications, phishing Web sites, etc., from misusing this service and misleading UH community members.

In addition to authentication services (AuthN), UH Login (CAS) may also provide other information (attributes) about the authenticated subject. These attributes are released using the the SAML 1.1 protocol. A registered Web application may obtain attributes about the user to implement access control (authorization) decisions, beyond the simple determination that the user has successfully authenticated with their password. For example, if an application is designed to be accessible only to faculty, that app can compare the eduPersonAffiliation attribute to determine if the user is faculty. If you do not perform any access control then anyone in the UH Core LDAP Directory Service will be able to use your Web application. This includes all current people in the UH System as well as visitors allowed by the Visitor Internet Access (VIA).

UH Login also provides Single-Sign On (SSO) capabilities.


The UH Web Login Service is provided via Apereo's Central Authentication Service (CAS).

Currently UH Login is running CAS version 6.3.5.

Please refer to Apereo documentation for authoritative references for CAS client integration and the CAS protocol. The CAS Community mailing list and archives are also valuable sources of information and support.

Additional  info:

Before You Register Your Application URL …

Before you register your application URL there are a few details to first consider:

  1. Will authentication include the release of attributes to your application?
    1. If yes, UH Data Governance guidelines apply.  For each unique application you must submit a separate request.  What that means is that you cannot register a single URL and host multiple applications under it.  
  2. Is your application hosted on a non-UH server?
    1. If yes, your request may be subject to the UH Data Sharing Request process. Please send an inquiry to datagov@hawaii.edu or call (808) 956-7487.

Register Your Application URL

For security purposes, application URLs must be registered in order to prevent unauthorized use.

Web Login process

Web applications registered for UH Login use a link or redirect from their main page to the secure HTML CAS form.

To Authenticate Users

  • A user enters their UH username and password on the UH Login page.
  • After submission, the Web Login Service redirects the user back to your web application along with a service ticket provided by the Web Login Service.
  • Your web application then requests that UH Login validate this ticket.
    • If the user supplied the correct authentication credentials (username/password), UH Login will return a success response to your web application.
    • Otherwise, a failure response is returned.

The specific format and content of these responses are determined by the CAS URI used by your application's request to validate the service ticket.

The service ticket is a one-time use token so any attempt to reuse it will result in a failure response.

This multi-step process should occur within your application; the user will only see that they've authenticated successfully, or a rejection message.

UH Login does not provide session tracking information so it is your Web application's responsibility to handle session tracking. Session tracking will reduce the number of round trips to UH Login to validate the user each time a resource (URL/URI) is requested from your Web application.

If the login step fails repeatedly for the user, they will remain at UH Login's login page. They may need to visit the Account Management page to reset their password or contact the Help Desk for assistance.

CAUTION

After UH Login redirects the user back to your app and you have validated the service ticket, redirect the user to an URL that does not include the service ticket. This reduces the risk of the user bookmarking a URL containing a service ticket. A bookmarked URL containing a service ticket is a problem because the CAS software isn't on guard for this and it results in a looping problem that sends the user back and forth between your application and UH Login, or it may immediately return an unsuccessful authentication result despite the user having provided the correct user password.

Conventions & Definitions

  • "Client" refers to the end user and/or the web browser.
  • "Server" refers to UH Login (CAS).
  • "Service" refers to the application the client is trying to access (i.e., your application).
    • "TARGET" for samlValidate
  • <LF> is a bare line feed (ASCII value 0x0a).

CAS URIs

URIs for CAS use the hostname followed by /cas and ended with the desired service. In the examples that follow, substitute the following for $WEBLOGIN-HOST for the appropriate environment.

  • Production
    • https://authn.hawaii.edu/
  • Test
    • https://cas-test.its.hawaii.edu/ (testing does not require registration of your URL)
  • Future Test
    • https://cas-future-test.its.hawaii.edu/
  • Deprecated Production
    • cas-deprecated.its.hawaii.edu


Test vs. Production, what's the difference?

The primary difference between the Test and Production environments is the source of credentials used for authentication and attributes. The production Web Login instance uses production LDAP, whereas the test Web Login instance uses our test LDAP instance. Data in the test LDAP instance generally represents a (somewhat stale) snapshot of the production LDAP. Developers should verify that the credentials they wish to test are available in test LDAP.

The login page presented to the user in the test environment is also conspicuously identified as being "Not intended for normal use" and a "test-env".

Append the following as needed:

If your service is only interested in authenticating users and will not require a user object of released attributes, you should use either cas/validate or cas/serviceValidate. Their responses

  • indicate whether the user authenticated successfully
  • provide the user's UH Username if the they authenticated successfully

If your service requires additional attributes for the user beyond their UH Username (eg UH Number, First/Last Name, etc), you should use cas/samlValidate.

CAS clients

Note that CAS clients are available that handle many of the login and ticket validation details for you. If your development can make use of one of the available CAS clients (eg, Java, PHP) you will probably want to take advantage of them rather than trying to reinvent the wheel.

Log in Securely

/login

To have a user login securely put a link on your main page to the "login securely" URL with a request parameter named service and having a value that is the Service URL (i.e., the URL of the main page or a page that will be able to handle an HTTP request with a parameter). This link should be labeled with something like "Login Securely" to establish in your user's mind that the password will not be seen by your application and is handled securely. See the next section on ticket validation for information about how your application finds out the username.

Parameters

The /login URI uses the following parameters:

  • service
    • used for AuthN responses
    • validate service ticket with
      • cas/validate
      • cas/serviceValidate
      • cas/samlValidate
  • renew (OPTIONAL)
    • if this parameter is set, single sign-on will be bypassed. In this case, CAS will require the client to present credentials regardless of the existence of a single sign-on session with CAS.
  • other parameters are described on the CAS Protocol wiki page

The service parameter should be set to the URL that the Web Login service will redirect the client to after successful authentication, as well as where the Web Login service will direct success/failure responses.

Successful login:

  • Redirect the client to the URL specified by the "service" parameter with a service ticket in a manner that will not cause the user's credentials to be forwarded to the your web application. The client uses the ticket provided as a parameter to one of CAS's validation methods.

Failed login:

  • Return to /login as a credential requester. The CAS server should display an error message to the user describing why login failed (e.g. bad username/password).
Examples
  • Service/target URL, this is your site's menu page or the page after a user logs in.

    https://myserver/myapp
    
  • "Log in Securely" link:

    Simple AuthN, allow SSO
    <A HREF=
        "https://$WEBLOGIN-HOST.hawaii.edu/cas/login?service=https://myserver/myapp">
        Log in securely
    </A>
    
    Simple AuthN, disallow SSO
    <A HREF=
        "https://$WEBLOGIN-HOST.hawaii.edu/cas/login?service=https://myserver/myapp&renew=true">
        Log in securely
    </A>
    

Notes

  1. The service/target URL must be a real URL. For example, most Web servers have a default page that is returned when you request a URL that ends with a forward slash character, "/". This often results in redirects to index.html, index.htm, or index.jsp while others may use default.htm, default.asp, or something similar.
  2. Since the Service URL is passed as the value of a query parameter, it should be URL-escaped to ensure proper interpretation by UH Login. Please refer to Section 2 and Appendix A of RFC 3986 for details.

Ticket Validation (CAS protocol 1.0, AuthN, simple text response)

/validate

This section describes how your Web application finds out the username of a user that has successfully logged in.

cas/validate checks the validity of a service ticket. cas/validate is part of the CAS 1.0 protocol. When UH Login has authenticated the user, it will redirect the user back to your Web site to the Service URL with an HTTP request parameter named, ticket, added on the end of the Service URL. That Service URL may not be a static page since it must be able to extract the service ticket for validation.

Parameters
  • service (REQUIRED)
    • the identifier of the service for which the ticket was issued
  • ticket (REQUIRED)
    • the service ticket issued by /login
  • renew (OPTIONAL)
    • if this parameter is set, ticket validation will only succeed if the service ticket was issued from the presentation of the user's primary credentials. It will fail if the ticket was issued from a single sign-on session.

      renew will cause UH Login to prompt the user to log in whenever she clicks on the "Log in securely" link but still permits the user to single sign-on to other Web applications using UH Login.

Examples
  • Here's an example of the URL used by UH Login to redirect the request back to the Web site (with a sample ticket):

    https://myserver/myapp?ticket=ST-3-8tkkJbPThesE1cZjVVtc
    
  • The server-side processing of your Service URL must validate the extracted authentication token by sending an HTTP GET request with the following parameters:

    service=<Service URL>
    ticket=<service ticket>
  • Using your URL with ticket, send your request to UH Login:

    https://$WEBLOGIN-HOST/cas/validate?service=https://myserver/myapp&ticket=ST-95-a1kjb6g4Tcdeh17vfy6g
    

    Append &renew=true to disallow SSO.

  • After validating the service ticket, UH Login will return a text document indicating success or failure.

    On ticket validation success:
    yes<LF>
    username<LF>
    
    On ticket validation failure:
    no<LF>
    <LF>
    

Ticket Validation (CAS protocol 2.0, AuthN, XML response)

/serviceValidate

This section describes how your Web application finds out the username of a user that has successfully logged in.

cas/serviceValidate checks the validity of a service ticket and returns an XML-fragment response. cas/serviceValidate is part of the CAS 2.0 protocol. When UH Login has authenticated the user, it will redirect the user back to your Web site to the Service URL with an HTTP request parameter named, ticket, added on the end of the Service URL. That Service URL may not be a static page since it must be able to extract the service ticket for validation.

Parameters
  • service (REQUIRED)
    • the identifier of the service for which the ticket was issued
  • ticket (REQUIRED)
    • the service ticket issued by /login
  • renew (OPTIONAL)
    • if this parameter is set, ticket validation will only succeed if the service ticket was issued from the presentation of the user's primary credentials. It will fail if the ticket was issued from a single sign-on session.

      renew will cause UH Login to prompt the user to log in whenever she clicks on the "Log in securely" link but still permits the user to single sign-on to other Web applications using UH Login.

Examples
  • Here's an example of the URL used by UH Login to redirect the request back to the Web site (with a sample ticket):

    https://myserver.example.edu/myapp?ticket=ST-7655-K6dyN9ystYwdOZynSnak-cas
  • The server-side processing of your Service URL must validate the extracted authentication token by sending an HTTP GET request with the following parameters:

    service=<Service URL>
    ticket=<service ticket>
    
  • Using your URL with ticket, send your request to UH Login:

    https://$WEBLOGIN-HOST/cas/serviceValidate?service=https://myserver.example.edu/myapp&ticket=ST-7655-K6dyN9ystYwdOZynSnak-cas

    Append &renew=true to disallow SSO.

  • After validating the service ticket, UH Login will return an XML-fragment indicating success or failure.

    On ticket validation success:
    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
        <cas:authenticationSuccess>
            <cas:user>joebogus</cas:user>
            </cas:authenticationSuccess>
    </cas:serviceResponse> 
    On ticket validation failure:
    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
        <cas:authenticationFailure code="INVALID_TICKET">
            Ticket ST-7655-K6dyN9ysFOOdOZynSnak-cas not recognized
        </cas:authenticationFailure>
    </cas:serviceResponse>

    Error codes

    The following values may be used as the "code" attribute of authentication failure responses.

    • INVALID_REQUEST
      • not all of the required request parameters were present
    • INVALID_TICKET
      • the ticket provided was not valid, or the ticket did not come from an initial login and "renew" was set on validation. The body of the <cas:authenticationFailure> block of the XML response SHOULD describe the exact details.
    • INVALID_SERVICE
      • the ticket provided was valid, but the service specified did not match the service associated with the ticket. CAS MUST invalidate the ticket and disallow future validation of that same ticket.
    • INTERNAL_ERROR
      • an internal error occurred during ticket validation

Ticket Validation (CAS protocol 3.0, AuthN with attributes, SAML response):

/samlValidate

This section describes how your Web application determines the username and possibly additional attributes for a user that has successfully logged in.

cas/samlValidate checks the validity of a service ticket and returns an SAML1.1-fragment response. When UH Login has authenticated the user, it will redirect the user back to your Web site to the TARGET URL with an HTTP request parameter named ticket (or SAMLart) added on the end of the TARGET URL. That TARGET URL can not be a static page since it won't be able to extract the service ticket for validation.

A SAML 1.1 ticket validation response is obtained by validating a ticket via POST at the cas/samlValidate URI.

If cas/samlValidate is used and your application is authorized to receive attributes, a SAML object is returned with a list of defined attributes for your application.

  • We return the following set of user attributes by default for cas/samlValidate:

    Note: Actual results would be returned as a SAML object. This table is not a complete list and is merely intended to illustrate the type of attributes and their values which may be returned.

    See the examples of actual requests and results below.
    Refer to the official CAS Default Attribute Release Policy documentation for more information on attributes available via CAS and their values.

    AttributeSample valueAttribute notes/description
    uid
    joebogus
    UH Username
    uhUuid
    12345678
    UH Number
    givenName
    Joe
    First Name
    sn
    Bogus
    Last Name
    cn
    Joe Queso Bogus
    Common Name (aka the official Full Name)
    displayName
    Joe Bogus
    Display Name (perhaps a more common nickname, otherwise same as cn, may not be available)
    eduPersonAffiliation
    staff
    Affiliation (User may have multiple affiliations.)
    eduPersonOrgDN
    uhsystem
    Organization (User may have multiple organizations.)
    uhOrgAffiliation
    eduPersonOrgDn=uhsystem,eduPersonAffiliation=staff
    UH Affiliation (combines both Affiliation and Organization, and again the user may have multiple affiliations.)
Parameters
  • TARGET (REQUIRED)
    • the identifier of the TARGET for which the ticket was issued

      HTTPS required

      Since attributes release sensitive information, your web application must use HTTPS to protect the data in transit.

  • ticket (or SAMLart)
    • the service ticket issued by /login. Note that in this case, the service ticket is not provided in the request URL as with the other validation methods, but in the SOAP request
  • renew (OPTIONAL)
    • if this parameter is set, ticket validation will only succeed if the service ticket was issued from the presentation of the user's primary credentials. It will fail if the ticket was issued from a single sign-on session.

      renew will cause UH Login to prompt the user to log in whenever she clicks on the "Log in securely" link but still permits the user to single sign-on to other Web applications using UH Login.

Examples
  • Here's an example of the URL used by UH Login to redirect the request back to the Web site (with a sample ticket):

    https://myserver/myapp?ticket=ST-7655-K6dyN9ystYwdOZynSnak-cas 

    Note that if the login URL used "TARGET=" instead of "service=", the request from the CAS server will use "SAMLart=" instead of "ticket=".  Also, the value will be a base64 string.

  • Your webapp will then validate the ticket by sending a HTTP POST request with the ticket enclosed in a XML SOAP message:

    https://$WEBLOGIN-HOST/cas/samlValidate?TARGET=https://myserver.example.edu/myapp
    

    Append &renew=true to disallow SSO.

    POST /cas/samlValidate?TARGET=https://myserver.example.edu/myapp
    Host: cas.example.com
    Content-Length: 491
    Content-Type: text/xml
    
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Header/>
        <SOAP-ENV:Body>
            <samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" MajorVersion="1" MinorVersion="1"
                           RequestID="17337.2018-05-03T09:50:56Z"
                           IssueInstant="2018-05-03T09:50:56Z">
                <samlp:AssertionArtifact>
                    ST-7655-K6dyN9ystYwdOZynSnak-cas
                </samlp:AssertionArtifact>
            </samlp:Request>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope> 

    Note that in this request, the service ticket is provided as the value for <samlp:AssertionArtifact>, and not as a parameter to the cas/samlValidate URL.

  • After validating the service ticket, UH Login will return a SAML1.1 fragment indicating success or failure.

    On ticket validation success:
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Body>
            <saml1p:Response xmlns:saml1p="urn:oasis:names:tc:SAML:1.0:protocol" InResponseTo="myserver.example.edu" IssueInstant="2018-05-03T19:50:56.390Z" MajorVersion="1" MinorVersion="1" ResponseID="_0044d5b611aac99d82cb9926281bbd30">
                <saml1p:Status>
                    <saml1p:StatusCode Value="saml1p:Success"/>
                </saml1p:Status>
                <saml1:Assertion xmlns:saml1="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="_0b1889b7ce444ecbe8cfd131501c4f59" IssueInstant="2018-05-03T19:50:56.390Z" Issuer="localhost" MajorVersion="1" MinorVersion="1">
                    <saml1:Conditions NotBefore="2018-05-03T19:50:56.390Z" NotOnOrAfter="2018-05-03T19:51:26.390Z">
                        <saml1:AudienceRestrictionCondition>
                            <saml1:Audience>https://myserver.example.edu/myapp</saml1:Audience>
                        </saml1:AudienceRestrictionCondition>
                    </saml1:Conditions>
                    <saml1:AuthenticationStatement AuthenticationInstant="2018-05-03T19:50:56.320Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password">
                        <saml1:Subject>
                            <saml1:NameIdentifier>iam_0108</saml1:NameIdentifier>
                            <saml1:SubjectConfirmation>
                                <saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod>
                            </saml1:SubjectConfirmation>
                        </saml1:Subject>
                    </saml1:AuthenticationStatement>
                    <saml1:AttributeStatement>
                        <saml1:Subject>
                            <saml1:NameIdentifier>joebogus</saml1:NameIdentifier>
                            <saml1:SubjectConfirmation>
                                <saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml1:ConfirmationMethod>
                            </saml1:SubjectConfirmation>
                        </saml1:Subject>
                        <saml1:Attribute AttributeName="mail" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">joebogus@example.edu</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="eduPersonAffiliation" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">staff</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="uhUuid" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">12345678</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="givenName" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">Bogus</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="eduPersonOrgDN" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">uhsystem</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="cn" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">Joe Queso Bogus</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="uid" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">joebogus</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="uhEmail" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">joebogus@example.edu</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="eduPersonPrincipalName" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">joebogus@example.edu</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="sn" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">Bogus</saml1:AttributeValue>
                        </saml1:Attribute>
                        <saml1:Attribute AttributeName="uhOrgAffiliation" AttributeNamespace="http://www.ja-sig.org/products/cas/">
                            <saml1:AttributeValue xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">eduPersonOrgDN=uhsystem,eduPersonAffiliation=staff</saml1:AttributeValue>
                        </saml1:Attribute>
                    </saml1:AttributeStatement>
                </saml1:Assertion>
            </saml1p:Response>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope> 

    Note: it is possible that more than one uid attribute may be returned (it is potentially multi-valued). The "user" that authenticated/logged into CAS may be found in the NameIdentifier element, and should match one of the returned uid attributes.

    <NameIdentifier>joeq</NameIdentifier>
    On ticket validation failure:
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Header/>
        <SOAP-ENV:Body>
            <Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol"
                      xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
                      xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"
                      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                      IssueInstant="2018-05-03T19:50:56.390Z" MajorVersion="1"
                      MinorVersion="1" Recipient="https://myserver.example.com/myapp"
                      ResponseID="_f2a2d3c1d7b451a71a688eb63a3251b9">
                 <Status>
                    <StatusCode Value="samlp:Responder"></StatusCode>
                    <StatusMessage>ticket\'ST-7655-kPThesE1cZjVVtcMANGLED\' not recognized</StatusMessage>
                </Status>
            </Response>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

FERPA laws may apply!

Information about students must be handled carefully and in accordance with University of Hawai?i data governance policies. FERPA laws constrain what may be published about students. Please check with your Admissions and Records Office for details.

Logging Out (SLO)

/logout

Web applications that login a user must handle their own session state and should offer the user the ability to log out of their session. Without the logout service provided by CAS, a user returning to the web application's Service URL, will be automatically logged back in because of the ticket-granting cookie also provided by CAS stored by the client. This is a single sign-on feature across web applications that use UH Login. There are two basic ways to "log out"; logout from application and UH Login single sign-on or logout from application and force re-authentication to UH Login.

cas/logout destroys a client's single sign-on CAS session. The ticket-granting cookie is destroyed, and subsequent requests to /logout will not obtain service tickets until the user again presents primary credentials (and thereby establishes a new single sign-on session).

CAS /logout will affect applications other than your own!

Note that use of /logout may affect any other application that is also using the CAS Single Sign-On (SSO) session. Other applications may share the same CAS SSO session that is terminated by the use of /logout, and their SSO session will likewise be terminated as well when the ticket granting cookie is destroyed.

Please refer to the CAS reference documentation for a more extensive discussion of this issue.

Parameters
  • service (OPTIONAL)
    • the identifier of the service to redirect to after logging out
    • the service parameter must be also be a registered service URL
  • url (DISABLED)

    Although Aperero's CAS protocol documentation describes the use the the url parameter, the Aperero developers have disabled it in recent versions of CAS to prevent potential abuse. Their explanation of the situation may be found in this thread from the cas-users mailing list. The url parameter defined in the former CAS 2.0 specification is not a valid parameter in CAS 3.0 anymore. CAS Servers MUST ignore given url parameters.

Examples
  • To logout a user and prevent her from automatically logging back into a Web application, the Web application can forward the user to the Logout URL of UH Login. That URL will destroy the ticket-granting cookie that enables the single sign-on feature and gives the user a page that informs them that they have logged out of UH Login.

    https://$WEBLOGIN-HOST/cas/logout
    
  • To logout a user and prevent her from automatically logging back into a Web application, the Web application can forward the user to the Logout URL of UH Login. That URL will destroy the ticket-granting cookie that enables the single sign-on feature and redirect the user to the URL identified by the service parameter.

    https://$WEBLOGIN-HOST/cas/logout?service=https://myserver/myapp
    

    The URL provided by the service parameter must be registered to use UH Login.

SLO is not enabled

Because SLO may affect other applications using SSO[*], it has been disabled as of the implementation of CAS 6.3.5.

[*] From the CAS documentation for Single Logout (SLO):

When a CAS session ends, it notifies each of the services that the SSO session is no longer valid, and that relying parties need to invalidate their own session. Remember that the callback submitted to each CAS-protected application is a notification; nothing more. It is theresponsibility of the applicationto intercept that notification and properly destroy the user authentication session, either manually, via a specific endpoint or more commonly via a CAS client library that supports SLO.

Also note that since SLO is a global event, all applications that have an authentication record with CAS will by default be contacted, and this may disrupt user experience negatively if those applications are individually distinct from each other. As an example, if user has logged into a portal application and an email application, logging out of one through SLO will also destroy the user session in the other which could mean data loss if the application is not carefully managing its session and user activity.


Access Control

It is every developer's responsibility to perform any necessary access control (authorization, AuthZ) after a user has logged on to their Web site. This is may be done by using information as attributes for the user. The affiliation, campus, or campus affiliation data should be enough to filter out unauthorized users. Alternatively, you choose explicitly may allow or disallow by username. Ultimately, it is up to each developer to determine how to implement access controls based on available information.

Sample Clients

Java client

Aperero provides an example of SAML 1.1 Ticket Validation Filter.

A deployed instance of this that utilizes our test CAS environment may be found here:

Apereo has taken over CAS from JASIG. The current version of the CAS client may be found here:

To use this client, as with the SAML 1.1 Ticket Validation Filter above, you may need the following jar files:

  • cas-client-core
  • cas-client-support-saml
  • commons-codec
  • commons-logging
  • joda-time
  • log4j
  • opensaml
  • slf4j-api
  • xmlsec

UH CAS Demo in Java

UH ITS' own Frank Duckart wrote the following CAS demo using Java and Servlets:

Probably not a great idea, but it is also possible to create a CAS client login using JSP only:
Project Repo:  https://github.com/fduckart/uh-jsp-casdemo

phpCAS client

The phpCAS module is a PHP library that interacts with CAS and allows you to work with user and authentication objects. It also allows for attribute release. The latest phpCAS version may be obtained from the phpCAS Github page. Documentation for phpCAS can be found here.

It is recommended after you extract the release that you create a symlink in the directory to the CAS folder. For example, if your phpCAS release is located in /usr/lib/php/CAS-1.3.1, you would create the symlink in /usr/lib/php. This allows you to have multiple versions of phpCAS without the need to continually overwrite folders.

% cd /usr/lib/php
% ln -s CAS-1.3.1/CAS CAS

# later if 1.3.2 is released:
% rm CAS
% ln -s CAS-1.3.2/CAS CAS

Below is a sample config file to set constants. This file can be located anywhere, but you must ensure that phpCAS has read permissions to its location. Also verify the hostname for the CAS server you are trying to connect to, as well as the filepath to the CAS folder.

If you are going to require attribute release, you will also need access to intermediate Certificate Authority bundles. On the ITS Red Hat Linux servers, you can set setCasServerCACert() to /etc/pki/tls/certs/ca-bundle.crt. That file is provided by the "ca-certificates" package from the RHEL repo... if you don't have root access, a System Administrator can install that for you using yum.

On Solaris, you can download the file cacert.pem from http://curl.haxx.se/docs/caextract.html and place it somewhere safe, i.e. not writeable by any web scripts, and point setCasServerCACert() to it.

Please note that the CA bundle should be occasionally updated since Certificate Authorities change over time.

 Click to expand: config.php for phpCAS-1.6.0
config.php
<?php

/**
 * The purpose of this central config file is configuring all examples
 * in one place with minimal work for your working environment
 * Just configure all the items in this config according to your environment
 * and rename the file to config.php
 *
 * PHP Version 7
 *
 * @file     config.php
 * @category Authentication
 * @package  PhpCAS
 * @author   Joachim Fritschi <jfritschi@freenet.de>
 * @author   Adam Franco <afranco@middlebury.edu>
 * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 * @link     https://wiki.jasig.org/display/CASC/phpCAS
 */

$phpcas_path = '../../source/';

///////////////////////////////////////
// Basic Config of the phpCAS client //
///////////////////////////////////////

// Full Hostname of your CAS Server
$cas_host = 'cas.example.com';

// Context of the CAS Server
$cas_context = '/cas';

// Port of your CAS server. Normally for a https server it's 443
$cas_port = 443;

// Path to the ca chain that issued the cas server certificate
$cas_server_ca_cert_path = '/path/to/cachain.pem';

//////////////////////////////////////////
// Advanced Config for special purposes //
//////////////////////////////////////////

// The "real" hosts of clustered cas server that send SAML logout messages
// Assumes the cas server is load balanced across multiple hosts
$cas_real_hosts = array('cas-real-1.example.com', 'cas-real-2.example.com');

// Client config for the required domain name, should be protocol, hostname and port
$client_service_name = 'http://127.0.0.1';

// Client config for cookie hardening
$client_domain = '127.0.0.1';
$client_path = 'phpcas';
$client_secure = true;
$client_httpOnly = true;
$client_lifetime = 0;

// Database config for PGT Storage
$db = 'pgsql:host=localhost;dbname=phpcas';
//$db = 'mysql:host=localhost;dbname=phpcas';
$db_user = 'phpcasuser';
$db_password = 'mysupersecretpass';
$db_table = 'phpcastabel';
$driver_options = '';

///////////////////////////////////////////
// End Configuration -- Don't edit below //
///////////////////////////////////////////

// Generating the URLS for the local cas example services for proxy testing
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
    $curbase = 'https://' . $_SERVER['SERVER_NAME'];
} else {
    $curbase = 'http://' . $_SERVER['SERVER_NAME'];
}
if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
    $curbase .= ':' . $_SERVER['SERVER_PORT'];
}

$curdir = dirname($_SERVER['REQUEST_URI']) . "/";

// CAS client nodes for rebroadcasting pgtIou/pgtId and logoutRequest
$rebroadcast_node_1 = 'http://cas-client-1.example.com';
$rebroadcast_node_2 = 'http://cas-client-2.example.com';

// access to a single service
$serviceUrl = $curbase . $curdir . 'example_service.php';
// access to a second service
$serviceUrl2 = $curbase . $curdir . 'example_service_that_proxies.php';

$pgtBase = preg_quote(preg_replace('/^http:/', 'https:', $curbase . $curdir), '/');
$pgtUrlRegexp = '/^' . $pgtBase . '.*$/';

$cas_url = 'https://' . $cas_host;
if ($cas_port != '443') {
    $cas_url = $cas_url . ':' . $cas_port;
}
$cas_url = $cas_url . $cas_context;

// Set the session-name to be unique to the current script so that the client script
// doesn't share its session with a proxied script.
// This is just useful when running the example code, but not normally.
session_name(
    'session_for-'
    . preg_replace('/[^a-z0-9-]/i', '_', basename($_SERVER['SCRIPT_NAME']))
);
// Set an UTF-8 encoding header for internation characters (User attributes)
header('Content-Type: text/html; charset=utf-8');
?>

The example code below would be used in your web app on all pages that require authentication.

 Click to expand: Sample PHP code to authenticate and retrieve attributes
phpcas-test.php
<?php

/**
 * Advanced example for SAML with attributes and single logout
 *
 * PHP Version 7
 *
 * @file     example_advanced_saml11.php
 * @category Authentication
 * @package  PhpCAS
 * @author   Joachim Fritschi <jfritschi@freenet.de>
 * @author   Adam Franco <afranco@middlebury.edu>
 * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 * @link     https://wiki.jasig.org/display/CASC/phpCAS
 */

// Load the settings from the central config file
require_once 'config.php';
// Load the CAS lib
require_once $phpcas_path . '/CAS.php';

// Enable debugging
phpCAS::setLogger();
// Enable verbose error messages. Disable in production!
phpCAS::setVerbose(true);

// Initialize phpCAS
phpCAS::client(SAML_VERSION_1_1, $cas_host, $cas_port, $cas_context, $client_service_name);

// However, if you are only interested in user authentication, you can use
// the following:
// phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context, $client_service_name);

// For production use set the CA certificate that is the issuer of the cert
// on the CAS server and uncomment the line below
phpCAS::setCasServerCACert($cas_server_ca_cert_path);

// For quick testing you can disable SSL validation of the CAS server.
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
// phpCAS::setNoCasServerValidation();

// Handle SAML logout requests that emanate from the CAS host exclusively.
// Failure to restrict SAML logout requests to authorized hosts could
// allow denial of service attacks where at the least the server is
// tied up parsing bogus XML messages.
phpCAS::handleLogoutRequests(true, $cas_real_hosts);

// Force CAS authentication on any page that includes this file
phpCAS::forceAuthentication();

// Renew CAS authentication with renew=true on any page that includes this file
// Use this in place of phpCAS::forceAuthentication();
// phpCAS::renewAuthentication();

// Some small code triggered by the logout button
if (isset($_REQUEST['logout'])) {
    phpCAS::logout();
}
?>
<html>
  <head>
    <title>phpCAS simple client with user attributes</title>
  </head>
  <body>

    Authentication succeeded for user
    <strong><?php echo phpCAS::getUser(); ?></strong>.

    <h3>User Attributes</h3>
    <ul>
    <?php
    foreach ( phpCAS::getAttributes() as $key => $value )
    {
        if ( is_array( $value ) )
        {
            echo '<li>', $key, ':<ol>';
            foreach ( $value as $item )
            {
                echo '<li><strong>', $item, '</strong></li>';
            }
            echo '</ol></li>';
        }
        else
        {
            echo '<li>', $key, ': <strong>', $value, '</strong></li>';
        }
    }
    ?>
    </ul>

    <p><a href="?logout=">Logout</a></p>g
  </body>
</html>

Theoretical examples of using CAS authentication across multiple pages, combined with using custom session variables.

 Click to expand: Example PHP code to retain CAS authentication across multiple pages

To use CAS across multiple pages, there are two ways to go about it:

The first is to include your phpcas-test.php file at the top of each page. This serves to activate the phpCAS client and will determine if the user has authenticated or not. You can modify your phpcas-test.php file by first checking phpCAS::isAuthenticated() which returns a boolean true or false; if false you can forceAuthentication().

The second is if you intend to use custom session variables across your pages. phpCAS has its own session management values that may interfere with whatever you're doing, so the solution I came up with was storing those CAS values into my app's session variables.

Please note that all examples provided here are extremely condensed, as I am only attempting to demonstrate how one can retain CAS session values along with app-specific session values. As such they should be treated more like pseudocode or an algorithm.

index.php
==========================================
index.php (summarized)
This page authenticates the user to my application.  Here I check if the user
is authenticated, and if so, I capture the CAS session values and user
attributes.
==========================================
<?php

include_once( "../../lib/cas.class.inc.php" )  
// This file is similar to the phpcas-test.php example
// The inclusion of this file activates the phpCAS client, and can
// trigger the authentication of the user if they're not logged in.
// My cas.class.inc.php file is below this example.

// Display session values, to double-check what we have
// The value of $DEBUG is set in my app's configuration file.
// You will notice that the session id and name are set by CAS3.
if ( $DEBUG ) {
    if ( isset( $_SESSION ) ) {
        print "<p />SESSION values set<br />";
        print "Session ID: " . session_id() . "<br />";
        print "Session Name: " . session_name(). "<br />";
        print_r( $_SESSION );
        print "<p />";
    }
}

// Save the attributes
$cas_attributes = array();
foreach ( phpCAS::getAttributes() as $key => $value ) {
    $cas_attributes[$key] = $value;
    $DEBUG && print "phpCAS attribute: $key, Value: $value<br />";
}

// Save the token
$cas_token = session_id();

<!-- HTML form to log user into my application.  I've cut out elements like -->
<!-- the text fields  for username and password entry to focus on CAS3 session -->
<!-- Here, I am submitting the user attributes as hidden fields to the -->
<!-- next page that does the app authentication -->
<form action="app_authentication.php" name="logging_in" method="POST">
    <input type="hidden" name="state" value="cas_authenticated" />
    <?php
    foreach ( $cas_attributes as $name => $attribute ) {
        if ( ! is_array($attribute) ) {
            print '<input type="hidden" name="cas_attributes['.$name.']" value="'.$attribute.'" />';
        }
        else {
            // Some CAS user attributes are multi-valued.
            foreach ( attribute as $sub_name => $sub_attr ) {
                print '<input type="hidden" name="cas_attributes['.$name.']['.$sub_name.']" value="'.$sub_attr.'" />';
            }
        }
    }
    ?>
    <input type="hidden" name="cas_token" value="<?php print $cas_token; ?>" />
</form>
?>
cas.class.inc.php
==========================================
cas.class.inc.php
simplified version
==========================================
<?php
require_once "PHPCAS_CONFIG.php";       // this is my config file
require_once $phpcas_path . "CAS.php";  // import phpCAS

phpCAS::setDebug( "/filepath/to/where/i/store/app/logs/cas_debug.log" );
phpCAS::client( SAML_VERSION_1_1, $cas_host, $cas_port, $cas_context, $client_service_name );
phpCAS::setCasServerCACert( $cas_server_ca_cert_path );
phpCAS::handleLogoutRequests( TRUE, $cas_real_hosts );

// If the user isn't authenticated, force authentication
// Here is where we determine if a user has logged in via CAS
if ( ! phpCAS::isAuthenticated() ) {
    phpCAS::forceAuthentication();
}

if ( isset( $_GET['logout'] ) ) {
    phpCAS::logout();
}
?>
app_authentication.php
==========================================
app_authentication.php
This page just handles authenticating my application, as users have passwords
that are not the same as their UH account passwords.
==========================================
<?php

// IMPORTANT!
// Note that I do not include cas.class.inc.php in this page!  If I did,
// phpCAS removes my app's session in order to use its own, and I end up losing
// the user-submitted form in the same process.

// Check if we have the POSTed "state" value of "cas_authenticated" from index.php
if ( (! isset( $_POST['state']) ) || ($_POST['state'] != 'cas_authenticated') ) {
    header( "Location: index.php?error=unauthenticated" );
    exit();
}

// Grab the username, app password, and CAS values
$entered_username   = $_POST[ 'username' ];
$entered_password   = $_POST[ 'password' ];
$cas_attributes     = $_POST[ 'cas_attributes' ];
$cas_token          = $_POST[ 'cas_token' ];

// Start a new session (non CAS session)
session_name( $PHP_SESS_ID );  // This is set in my app's config file so I can reuse and recall anywhere
if ( ! session_start() ) {
    die( "Could not start non-CAS session!" );
}

// Debugging statements, to ensure the values and constants are what I expect them to be.
// Note here that the session id and name should be values that I just set.
$DEBUG && print "
    <p />
    Session Name: ".session_name()."<br />
    Session ID: ".session_id()."<br />
    APP HOST: $APP_HOST<br />
    LDAP: $LDAP_HOST<br />
    Location: ".$_SERVER['PHP_SELF']."
    <p />
";

// Assume I have code to validate the user's name and password.
// Next I store the CAS attributes and token into my currently-active session ($PHP_SESS_ID)
if ( $user_validated ) {
    $_SESSION[ $CAS_ATTRIBUTES  ] = $cas_attributes;
    $_SESSION[ $CAS_TOKEN       ] = $cas_token;
}
?>
other_pages.php
==========================================
all other pages in my application
Now that I have stored the CAS token and attributes, I can access them
in the rest of my application.
==========================================
<?php

// I still do not include the cas.class.inc.php page

# Start a new session (non CAS session)
session_name( $PHPSESSID );
if ( (! isset( $_SESSION)) || (! $_SESSION) ) {
    if ( ! session_start() ) {
        die( "Cannot start non-CAS session!");
    }
}

// Here I check that the user has a CAS token (which was set in app_authentication.php)
if ( (! isset( $_SESSION[$CAS_TOKEN] )) || ($_SESSION[$CAS_TOKEN] == $EMPTY_STR) ) {
    $file->write_log_file( "Unauthenticated access to ".$_SERVER['PHP_SELF'], $LOG_DIR.$LOG_WEBLOG );
    header( "Location: index.php?error=unauthenticated" ); // index.php has an error-handler.
    exit();
}

$cas_attributes         = $_SESSION[ $CAS_ATTRIBUTES ];
$uh_username            = $cas_attributes[ $UID ];
$uh_number              = $cas_attributes[ $UHUUID ];

// session id and name should still be the values I set, not CAS's values.
// You could also include the CAS values in this debug statement if you
// wanted to verify retention and accuracy.
$DEBUG && print "
    <p />
    Session Name: ".session_name()."<br />
    Session ID: ".session_id()."<br />
    APP HOST: $APP_HOST<br />
    LDAP: $LDAP_HOST<br />
    USER: $uh_username<br />
    UHUUID: $uh_number<br />
    Location: ".$_SERVER['PHP_SELF']."
    <p />
";
?>

Note that phpCAS can also provide simple authentication without requesting user attributes. See comments in the code. Below is an example of a successful login using serviceValidate (captured in PHP var_dump):

Array ( [0] => yes [1] => jschmidt [2] => )

cURL client (no attributes requested)

Below is a PHP script using cURL to establish a connection with the CAS server.

Note that this script does not request user attributes and is only interested in authenticating users.

 Click to expand: cas_test.php
<?php
# Test CAS URLs
$CAS_LOGIN_URI      = "https://$WEBLOGIN-HOST/cas/login";
$CAS_VALIDATE_URI   = "https://$WEBLOGIN-HOST/cas/validate";
$CAS_LOGOUT_URI     = "https://$WEBLOGIN-HOST/cas/logout";

$single_signon = TRUE;

# Here is where we check if the user has authenticated.  If we cannot find a ticket,
# redirect the user to the CAS login page.
if ( ! isset($_GET["ticket"]) )
{
    $location = "Location: ".$CAS_LOGIN_URI."?service=".urlencode($_SERVER["SCRIPT_URI"]);

    # If we haven't enabled single sign-on, the user has to renew each time.
    if ( ! $single_signon )
    {
        $location = $location."&renew=true";
    }

    header($location);
    exit();
}
else
{
    # Initialize our CURL session with the CAS validation URL.  Supply the server script and ticket.
    $validate_string    = $CAS_VALIDATE_URI."?service=".urlencode($_SERVER["SCRIPT_URI"])."&ticket=".$_GET["ticket"];

    $ch = curl_init($validate_string);

    # set the option to return the results
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    $cas_return = explode("\n", curl_exec($ch));

    # This dumps out the return values from our cURL request.  Later we check whether or not the user successfully authenticated.
    echo "CAS return via cURL: ";
    print_r($cas_return);
    echo "<br />";

    if ( $cas_return[0] == "yes" )
    {
        echo "User successfully authenticated via CAS<br />";
        for ( $i=0; $i<count($cas_return); $i++ )
        {
            echo "Cas Return #$i: ".$cas_return[$i]."<br />";
        }
    }
    else
    {
        echo "User not validated<br />";
    }
}

?>

Spring Security CAS Authentication

Frequently Asked Questions (FAQ)

Why does my site automatically login a returning user after they logout of their session with my site?

UH Login provides a single sign-on mechanism by default. This is a convenience for the user visiting sites that use UH Login. If you want you make sure your users always authenticate themselves to UH Login before entering your site, you need to add the renew parameter to the /login or /*validate CAS URLs.

Is there a preferred method for logging out users?

Which to use is a judgement call for Web apps. When in doubt, use the Logout URL. It will always force a user to re-authenticate to UH Login. Not having single sign-on is not necessarily a bad thing.

The general user finds it difficult to understand the security implications of the various shades (actually, only two) of logging out. If an app might be used from a kiosk (public use PC and browser) it is safer to set things up to logout completely using the Logout URL.

A future enhancement could make single sign-on an option for the user so the default will be no single sign-on. If the user chooses to enable single sign-on when authenticating to UH Login, only those apps that don't use the renew parameter will permit single sign-on if the user doesn't logout via the Logout URL from a previously visited app.

Why can't I login successfully to the CAS test environment?

There are several reasons for this and one or both may be applicable:

  1. Currently you need to use a UH VPN to access CAS test.  (not a requirement for production CAS, nor will it ever be)
  2. CAS test points to a test LDAP instance that may not have your current password.  Send an email to the IAM team to request a "password sync" if needed.

Can anyone use my Web site?

Anyone that is in the UH Core LDAP Directory Service. In other words, current people in the UH System (ten campuses, system offices, some RCUH employees) and visitors (temporary guest accounts) managed by VIA. See the CAS Developer Documentation#overview above.

Why is the UH CAS Server sending requests to my webapp?

This is caused by the Single Sign Out feature introduced in CAS version 3.1.  It attempts to automatically log users out of webapps that the user accessed via CAS, when either the Logout URL is requested or the TGT expires.

Since this feature is not compatible with our existing business rules, IAM will be disabling this feature during the 2014 calendar year.


Troubleshooting

Often the best place to start if you encounter errors, is a review of your logs for indications as to the nature of the problem. This will often yield productive keywords or strings that may be useful in a search or requests for technical support.

The following issues have been encountered by some of our developers.

Application Not Authorized to Use UH Login

Problem:

Your application cannot successfully authentication against CAS.

Example error message:

The application you attempted to authenticate to is not authorized to use UH Login.

Solutions:

 Click here to expand...
  • If you have requested attributes, make sure you are using https.
  • Check that the URL matches the URL specified in your original CAS URL registration request.
    • Common errors
      • Adding or leaving out "www" not in registered registered URL
      • Using "http" as the protocol rather than "https"

SSL Handshake Errors

Problem:

SSLv3 is being deprecated as a weak encryption protocol. As it is disabled on servers, clients that attempt to use SSLv3 for their connections will fail to do so.

Example error messages:

Java:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

PHP, Python:

error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure


Solutions:

Configure applications to use TLS instead of SSL for encrypted connections. Current versions of SSL/TLS (e.g. OpenSSL, Java) libraries disable SSLv3 by default. However if you are using an older version, you may need to explicitly disable SSLv3 and use TLS instead.

 Java: Click here to expand...

Invoke your app (or include the equivalent in your code) with this option to disable SSL:

-Djsse.enableSNIExtension=false -Dhttps.protocols=TLSv1

 PHP: Click here to expand...

PHP developers may need the following (or equivalent):

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');

Reference: PHP curl_setopt documentation

Until we also expand the available ciphers CURLOPT_SSL_CIPHER_LIST may need to be adjusted as well. Currently only SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA ciphers are enabled.

The PHP reference above suggests "RC4-SHA and TLSv1 are valid cipher lists". If "TLSv1" works for you, that's probably what you want and it should be forward compatible. We have also seen references that suggest that PHP can accept OpenSSL format cipher lists, but this has not been verified.

This page also seems to be a decent overview of using TLS with PHP: Insufficient Transport Layer Security (HTTPS, TLS and SSL)

 Python: Click here to expand...

Python developers may need the following (or equivalent):

ssl_version = self.ssl_module.PROTOCOL_TLSv1

One developer has reported their experience as follows:

System OpenSSL: OpenSSL 0.9.8zc 15 Oct 2014
Python: 2.7
Django: 1.7.1

Solution overview:

I had to modify python's ssl module to use TLSv1 (higher versions aren't available with openssl <1). It was setup to use SSLv23 by default. The system supports TLS but the python module defaulted to sslv23.

I use virtual environments so I was able to isolate the hack to the ssl module in my virtualenv and not the system python.

Hack:

$ cp /usr/lib/python2.7/ssl.py $VIRTUALENV_PATH/lib/python2.7/

Modified ssl_version keyword argument to method wrap_socket in $VIRTUALENV_PATH/lib/python2.7/ssl.py as follows:

ssl.py
def wrap_socket(sock, keyfile=None, certfile=None, server_side=False,
cert_reqs=CERT_NONE, *ssl_version=PROTOCOL_TLSv1*, ca_certs=None,
do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)

SAML Assertions Not Valid Due to Time Synchronization Issues

Problem:

The SAML response may contain assertions subject to conditions such as:

<Conditions NotBefore="2013-04-09T20:29:30.507Z" NotOnOrAfter="2013-04-09T20:30:00.507Z">

If the time on the CAS client and server systems are not sufficiently synchronized, it can result in the tickets or responses being received outside of their window of validity from that system's perspective.

CAS service tickets are single use and expire after 10 seconds.

Example error messages using the Java client:

2009-08-13 16:30:58,313 DEBUG [org.jasig.cas.client.validation.Saml11TicketValidator] - <skipping assertion that's not yet valid...>
2009-08-13 16:30:58,316 WARN [org.jasig.cas.client.validation.Saml11TicketValidationFilter] - <org.jasig.cas.client.validation.TicketValidationException: No valid assertions from the SAML response found.>
org.jasig.cas.client.validation.TicketValidationException: No valid assertions from the SAML response found. 

Solutions:

 Click here to expand...
  • Our CAS servers have their time synchronized via the NTP protocol. Client systems that also use NTP are presumably unlikely to encounter this problem.
    • (info) This should be the preferred approach.
  • The Java client has a tolerance init parameter to specify the a timing tolerance in ms:

    <init-param>
     <param-name>tolerance</param-name>
     <param-value>60000</param-value>
    </init-param>
    
  • The DotNetCasClient 3rd party plugin for .NET projects has an attribute to specify ticket timing tolerance in ms:

    ticketTimeTolerance="30000"

Reference: CAS Users mailing list thread on time synchronization


Reference: CAS Users mailing list thread on time synchronization


Technical Support

There is an active UH community of developers and a good chance that at least one of them has experience with your scenario.  It is well worth joining this community's email list if you've not already done so.  For details, visit App Developers Forum page.  Note that the ITS Identity and Access Management team also participates on this list.