Skip to end of metadata
Go to start of metadata

You are viewing an old version of this content. View the current version.

Compare with Current View Version History

« Previous Version 6 Next »

The CAS Server is a Spring Web Application, but it is designed according to standard layers or functional components that can be plugged into a standard J2EE diagram. There are three main components, each of which can be subdivided into subcomponents.

  • The front end is a "Presentation Layer" that handles arriving HTTP requests. In addition to presenting and processing the Login form (containing userid and password), this layer also handles non-interactive forms of login (X.509 Certificates), and the Service Ticket validation and Proxy ticket calls.
  • The Business Layer (where J2EE would have EJBs) validates the login (by verifying the userid/password against a backend system such as Kerberos or LDAP), and it creates Tickets including the Login TGT and Service Tickets.
  • Tickets are stored in a Ticket Cache. Normally this is just an in-memory collection, although it can be replicated (for clustered failover) or stored in a shared database. Since Tickets can be persisted (even though they frequently aren't) they become Entities in a logical Persistence Layer.

 Presentation Layer

CAS 3 uses two different Spring APIs to configure and code the Presentation Layer.

The calls to validate Service Tickets and issue Proxy Tickets are processed by Spring MVC configured in the WEB-INF/cas-servlet.xml file.Spring "Action" Beans are configured that expose a method that receives the Request and Response object of an incoming HTTP operation.

    <bean id="serviceValidateController" class="org.jasig.cas.web.ServiceValidateController"
        p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxyingValidationSpecification"
        p:centralAuthenticationService-ref="centralAuthenticationService"
        p:proxyHandler-ref="proxy20Handler"
        p:argumentExtractor-ref="casArgumentExtractor" />

Action Beans are essentially Servlets, only with a Spring flavor. Parameters from the request are "bound" (used to set the properties of a bean). The Action Bean is inside the ApplicationContext, so it gets dependency injection. It returns an object (ModelAndView) that identifies the response (typically a JSP page although it can be a View Bean) and provides a Map of data that the JSP EL can use to populate variable fields in the response page.

Each Action Bean is called when the end of a request URL contains a string mapped to the Bean (again in cas-servlet.xml):

                <prop
                    key="/serviceValidate">
                    serviceValidateController
                </prop>

The "/login" function is mapped to an entirely separate API called Spring WebFlow. WebFlow is a common computer design pattern called a "State Machine" coded as a sequence of XML elements in the WEB-INF/login-webflow.xml file. In some sense, a WebFlow demonstrates how to replace a dozen lines of Java with a hundred lines of considerably more complex XML (but at least you are not coding).

Each state is represented by an XML element that either performs a simple EL test or else calls a Bean method. The result of the test or return value of the method is "success" or "error" and generates a transition (a GOTO) to another state.

    <action-state id="startAuthenticate">
        <action bean="x509Check" />
        <transition on="success" to="sendTicketGrantingTicket" />
        <transition on="error" to="viewLoginForm" />
    </action-state>

 When the login flow gets to this state, it calls a method of the x509Check Bean (which determines if the Request has a valid X.509 Certificate that can be used to login the user). A return of "success" means the user has logged on and proceeds to a state/bean that generates the Ticket Granting Cookie in the response object. An "error" means that there is no certificate, so the normal interactive Login form is displayed.

The flow continues until there is a transition to an  "end-state" which either displays a JSP page or else redirects the Browser to another page.

Ideally, the Presentation Layer would be the only component that deals with the Servlet API and its Request, Response, and Session objects. That is certainly possible for userid/password, but certain credentials may be inherently tied to the underlying socket and communications layers.

Business Logic

The Business Logic layer of CAS represents a set of services configured by the WEB-INF/deployerConfigContext.xml file. In a normal J2EE design, these would be the EJBs.

The entry to the Business Logic layer is the CentralAuthenticationService Interface. In a real EJB configuration, this would be the local service interface. It defines methods to create a TicketGrantingTicket (by logging on a user if the credentials presented are valid), create and validate ServiceTickets, and log the user off.

The rest of the Business Logic layer consists of secondary internal service interfaces configured in Spring and injected into other beans.

The most important secondary internal service, and the most important Spring configuration element, is the AuthenticationManager. An AuthenticationManager handles login requests, validating the user Credentials and generating (after a sucessful login) the TGT.

Each type of AuthenticationManager accepts as a Spring configuration property some sort of collection of AuthenticationHandlers and CredentialsToPrincipalResolvers. To simplify further documentation, we will call these Handlers and Resolvers.

Credentials are created by the Presentation Layer from something in the HTTP request. In the simple case, the Userid and Password are extracted from the form and combined to create a Credential object. If the container is configured to accept User Certificates, an X.509 Certificate can be extracted from the Request object and presented as a Credential. If SPNEGO is enabled, then the Browser of a client logged into a Kerberos 5 realm (typically an Active Directory Domain) can present a Kerberos 5 Service Ticket as proof of identity.

Each AuthenticationHandler configured to the AuthenticationManager is called in turn. If it supports the type of Credential object, it can claim and validate the Credential. In the case of a Userid/Password from a Form, this means sending these field on to a backend system (a Kerberos 5 KDC, an LDAP directory, a JDBC database) that maintains a list of userids and passwords and can verify that the pair of fields are valid.

However, the container has often already done a lot of the validation. When X.509 User Certificates are enabled to Tomcat or JBoss, then the container has already verified that the Certificate was digitally signed by a Certificate Authority in its list of configured "trusted" CAs. With SPNEGO, all the Kerberos 5 keys and tickets protocol has already been done down in the presentation layer using the Java interface to the system GSSAPI service. So some AuthenticationHandlers really validate the Credentials, while others simply verify that the type of object corresponds to something the container or Presentation Layer has already validated and then returns "true" because such Credentials are implicitly trusted.

A CredentialsToPrincipalResolver extracts the Principal (user) from the Credentials. For a userid/password, the Principal is just the userid. However, an X.509 certificate has a Distinguished Name and various SubjectAltNames from which a Principal may be determined. There is also the question of whether the Principal name should be qualified or not. At Yale, the Netid "gilbert" may also be identified as "yale\gilbert" (AD), "gilbert@YU.YALE.EDU" (Kerberos realm), "Howard.Gilbert@yale.edu" (EMail address and AD Universal Principal Name). Fully qualified principal names become more important when independent organizations join in some sort of Identity Federation.

There is enough flexibility here to get really confused. Words like Subject, Principal, and Realm are used throughout Java Security, JBoss, and CAS to mean roughly the same idea but with slight variations. Sometimes a precise technical needs to be applied at one point to make things work, but then in other places a more general meaning may be required. Consider the idea of a Principal.

  • The user types something into a form. Since he is an end user, it should be as simple as possible. Suppose he types "gilbert".
  • The AuthenticationHandler validates the Credential object containing "gilbert". However, in order to authenticate to a particular back end service, it may be necessary to transform what was typed in to something specific to that particular back end service. At Yale, if you want to use Kerberos 5 protocol to the MIT Kerberos servers you would use Principal name "gilbert@NET.YALE.EDU", while using the same protocol against Active Directory would use the same JaasAuthenticationHandler configuration and simply transfom the typed in userid to "gilbert@YU.YALE.EDU".
  • However, at Yale "gilbert" is a Netid that is maintained across a number of back end system.  Any system protected against unauthorized modification might be used to authenticate this person, and while it may be of administrative interest how the authentication was done, when some CAS Service validates a Service Ticket it expects to get the naked Netid "gilbert". So even though a fully qualified Principal name may be used with the back end service, the unqualified name would be stored by CAS in the Ticket space.
  • That works fine until Yale joins one or more federations of universities and allows cross-institutional login. Now to support legacy systems, the unqualified "gilbert" would be returned to all Yale services that expect that CAS only authenticates local Yale users. New services that are ready to accept fully qualified cross-institutional Principal names might get back "gilbert@harvard.edu" and would realize that this is almost certainly some other person named "gilbert" at a different institution and, therefore, someone completely different from the local Netid "gilbert" at Yale.

CAS can be configured to do all these different things if you know what you are doing. It neither provides nor excludes any complicated Principal naming scheme. Anything is possible, with some Spring configuration and a little coding. However, you have to understand the architecture and put your configuration and code in the right place.

A Handler authenticates or rejects one type of Credential object. The default AuthenticationManager accepts the opinion of the first Handler that recognizes that type of Credential object and it applies Resolvers separately.

However, some institutions may want to resolve the same userid/password against several back end systems (multiple Kerberos realms, LDAP directories, etc.) and accept them if the combination validates to any system. No matter which Handler approves them, a single Resolver could then extract the userid and set it as the accepted Netid in the TGT. So here there would be many Handlers all sharing a single Resolver. In other institutions, however, different back end systems might imply different formats for the CAS Netid, and that creates need for an AuthenticationManager configured in Spring XML with pairs of (Handler, Resolver).

JAAS (Kerberos) Password Handler

       <bean  class="org.jasig.cas.authentication.handler.support.JaasAuthenticationHandler"
             p:realm="CASJAASconfig" />

JAAS is a standard feature of current Java Runtime systems. It can be used directly through an API, or it can be configured for use by other components. In CAS, the JaasAuthenticationHandler uses it directly to validate a userid/password pair against various back end systems.

JAAS is a standard service into which a system administrator can configure pluggable authentication modules. This system model is used widely in Unix under the name "PAM". An application that accepts userids and passwords can simply pass them to JAAS without knowing exactly how they are going to be tested. The Application programmer doesn't have to know about security and authentication. Someone else configures a bundle of authentication parameters that indicate which back end protocols to use and which back end systems to contact.

Internally, JAAS is essentially duplicating the same set of services represented by the AuthenticationManager and AuthenticationHandlers.  In some configuration file the name "CASJAASconfig" is associated with one or more fully qualified Java classnames of classes that implement the JAAS Service Provider interface, but for CAS the only interesting provider class is the one that uses Kerberos 5. There is a JAAS LDAP provider, but CAS has a separate optional LDAP module with a Handler and Resolver that provides a better choice.

That said, it is possible that you will want to authenticate users with some new option (say a smart card) and the vendor of that technology will provide a JAAS Service Provider class and JAR file as the preferred way to use the device. In that case, you use the JaasAuthenticationHandler configured as above, but in the realm property you put the name of a bundle of parameters in the JAAS login config file that selects and configures the vendor JAAS provider module (which in some cases will communicate out through the net to an appliance device that does most of the work).

The one restriction is that the JaasAuthenticationHandler module supplied with CAS 3 only supports Credentials with a userid and password. If some new technology generates one time use passwords, it can be used as is. However, if authentication requires more than these two data items, then it may be necessary to modify this original handler to support any extra fields.

[to be continued]

The JaasAuthenticationHandler uses the JAAS Java API to authenticate a userid and password against an external Kerberos 5 or LDAP system. The realm parameters (set to "K5auth") is just the name of a bundle of configuration parameters in the login configuration file. In normal Java, a login configuration file is specified by the "login.config.url.1" property in the {jre}/lib/security/java.security property file. An application specific configuration file can be provided by the Java code that calls JAAS. Each JAAS login configuration file contains named bundles of configuration parameters designating the name of a class that provides the JAAS login service and a list of parameters needed by that class to connect to the Kerberos KDC, the LDAP server, etc.

When more than one login configuration file is specified, they are concatenated. An exception is thrown if the same named configuration bundle is found more than once, say in the JRE configuration file and the local application configuration file.

JAAS uses the credentials (typically the userid and password) to log the user on to the backend system and generates some standard Java objects (Subject and Principal). If the backend system is a Kerberos 5 KDC, then the generated Principal object can contain a key and a Kerberos TGT. However, the JaasAutheticationHandler does not use artifacts generated by the login. It simply uses JAAS to autheticate the userid/password combination and then logs the user off from the backend system before returning to the AuthenticationManager.

LDAP (AD) Password Handler

                <bean class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler">
                       <property name="filter" value="sAMAccountName=%u" />
                       <property name="searchBase" value="dc=yu,dc=yale,dc=edu" />
                       <property name="contextSource" ref="ldapContextSource" />
                       <property name="ignorePartialResultException" value="yes" /> <!-- fix because of how AD returns results -->
                </bean>

An LDAP AutheticationHandler is one of the distributed optional modules of the CAS 3 distribution. It uses Spring LDAP to authenticate the userid and password. In this example, the bean is configured for Active Directory and uses a separate  LdapContextSource bean not shown.

JAAS can authenticate a userid/password by logging the user on and then off of an external LDAP source. However, the BindLdapAuthenticationHandler shown here is more efficient because it maintains a pool of existing LDAP connections to AD that it reuses to validate passwords rather than setting up and tearing down a connection for every user login.

 X.509 Certificate Handler

                <bean class="org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler"
                    p:trustedIssuerDnPattern="CN=Yale University ITS Issuing Certifying Authority.+"
                    p:maxPathLength="3"
                    p:maxPathLengthAllowUnspecified="true"
                    />

The X509CredentialsAuthenticationHandler examines a User Certificate submitted with the HTTP request. The container (Tomcat, JBoss, etc.) has already verified that the Certificate comes from a trusted Certificate Authority.Generally the container is configured to only accept User Certificates issued by one of the standard Yale University CAs and not from any public sources. With this configuration, the Bean requires that the CA be specifically the Yale University ITS Certifying Authority and not one of the other CAs that the container trusts.

X.509 Certificate Resolver

  • No labels