...
Each subproject creates a JAR or WAR file. The first project is cas-server-core and it contains builds a JAR file containing about 95% or more of all the CAS code. It has to be built first because all the other projects depend on it. After that, there are projects to create optional components that you may or may not choose to use.
Building the WAR
The CAS WAR that you actually run in the Web server is built in two steps in two Maven projects.
Apereo distributes a project called cas-server-webapp to create an initial template WAR file. This WAR is not particularly useful, but it contains at least a starter version of all the Spring XML used to configure CAS and many CSS, JSP, and HTML pages. It also contains a WEB-INF/lib with the basic JAR libraries needed by a CAS system.
Although you can modify the cas-server-webapp project directly, this results in a directory with a mixture of Apereo files and Yale files, and the next time you get a new CAS release from Apereo you have to sift through them to find out which ones have been changed by Apereo.
Apereo recommends using the WAR Overlay feature of Maven. Yale creates a second WAR project called cas-server-yale-webapp that contains only the files that Yale has changed or added. Generally the WAR Overlay includes:
- Yale Java source for Spring Beans that are slightly modified versions of standard Apereo beans.
- Yale "branded" look and feel (CSS, JSP, HTML).
- Spring XML to configure Apereo options that Yale has selected and a few Yale additions.
- A pom.xml file with dependency statements for Apereo optional and Yale additional JAR files referenced by the Spring XML that will be added to WEB-INF/lib.
Maven realizes this is a WAR Overlay project because the cas-server-webapp WAR is referenced as a dependency. Since one WAR cannot be included inside another, this is a Maven idiom that everything in this project modifies or adds to this original template war. Files in this project with the same name replace files in the template project. Other files are added. The section of the pom.xml file that configures the maven-war-plugin also contains a list of files in the template that should be deleted, usually because they are replaced by new files with slightly different names.
Because Yale wrote CAS Versions 1 and 2, Apereo/JASIG numbering starts with Version 3. We know that the Apereo numbering won't go backwards, so any cas.war file with a Version number less than 3 is safe from collision. The Yale WAR file generated by the Overlay project, and all the Yale internal CAS projects are assigned Versions such as 1.1.2. An actual CAS artifact that might be installed into production will be store in Artifactory as https://repository.its.yale.edu/maven2/libs-releases-local/edu/yale/its/cas/cas-server-war/1.1.1/cas-server-war-1.1.1.war.
Version Numbers and Project Structure
CAS development at Yale only requires Maven projects to build the Yale added JARs (notably the cas-server-expired-password-change and the cas-server-support-CushyTicketRegistry projects) and the WAR Overlay project (cas-server-yale-webapp). There is no need to recompile Apereo projects if we are not going to change them. The WAR Overlay project has <dependency> statements with <version> values that select specific Apereo artifacts. These artifacts do not have to be created at Yale, but could be downloaded from the network like any other JAR library. This even extends to the base cas-server-webapp WAR file. If the WAR Overlay references Version 3.5.3 of cas-server-webapp, then it will start with the vanilla Apereo WAR template downloaded from apereo.org. This single project (the cas-server-yale-webapp project) builds the version of CAS that is ultimately installed and run at Yale. So if you want to know what is actually being used (vanilla Apereo code or some Yale modification) looking at the POM file in cas-server-yale-weapp is the authoritative source of information.
However, Yale does occasionally need to compile and perhaps modify Apereo source. Sometimes these changes are exploratory. Sometimes they help us debug a problem. Sometimes they fix an error that is important to Yale. For whatever reason this code gets compiled, it is critical that no Yale modified version of an Apereo project ever be created with the same Version number as the corresponding vanilla Apereo module. If that happens, then there are two versions of the same JAR file with the same name. One is vanilla code and one is Yale modified code, and once the two get into the Yale system there will be no way to know which you have in any given context.
So even if there is absolutely no intent to change Apereo code, or to use anything other than a Vanilla Apereo library, the first step when working with a new release of CAS from Apereo is to create a Yale base version number for this generation of Yale development and to make sure that any Yale compilation of any Apereo source use the Yale <version> value and not the Apereo vanilla value. Generally speaking, the Yale convention is to increment the middle dotted number (1.x.0) for each iteration of CAS development, and we do not install every CAS version. So Yale version 1.1.x corresponds to the Apereo CAS 3.5.y versions, and Yale 1.2.x corresponds to Apereo 4.0.0. Generally you have to change the version number in the parent project POM, but then you also have to change the <parent> version number in all the subprojects.
Now every time Yale compiles an Apereo project the resulting generated JAR will have the current Yale project number. That JAR will go into the local Maven Repository on the Sandbox machine with the Yale version number (say 1.1.4-SNAPSHOT) and if the source gets checked into Maven and you run the Jenkins Build job then a JAR file with the Yale Version number (say 1.1.4) will be uploaded to the Yale Artifactory network server. However, the Artifactory server will also have the vanilla Apereo version of the same file with the original version number (say 3.5.3). Just because we compiled our own copy of cas-server-core and uploaded it to Artifactory doesn't mean that that JAR file will eventually end up in production. If the cas-server-yale-webapp project calls for version 3.5.3 then it is the vanilla JAR that gets deployed to DEV, TEST, and PROD CAS.
However, if a Yale modified version of the source was every checked into SVN with the Apereo version number and was then built by the Jenkins Build job, then the Yale compiled version would replace the Apereo vanilla version on the Artifactory server and you would lose the ability to distinguish vanilla from Yale modified. It is not a problem if, during the initial exploration of a new release of CAS, you compile Apereo source on a sandbox machine. That just changes the local Maven Repository, and you can always clean it up later by deleting that subdirectory tree in the repository and rebuilding it. You just have to replace Apereo with Yale version numbers on the source before the first Jenkins Build job.
During development, we may make changes to vanilla CAS source to see how something works or to track down a problem. Those changes will be abandoned in the final deployment. The only time we deploy a Yale modified version of a standard Apereo JAR file is if there is a critical Yale bug fix that we need for reliability, or if we have a serious difference of opinion with the Apereo source committers.
Some examples of differences of opinion or bugs:
- The "service=" parameter value on the CAS login has to exactly match the value of the same parameter on the validate, serviceValidate, or samlValidate request. There is a difference of option about how carefully they have to match. The JASIG code matched the entire string excluding JSESSIONID if it was present. Yale believes that the entire query string (everything after the "?") should be excluded, and maybe the match should stop with context (https://servername/context/stuff-to-be-ingnored). This changes the substrings used in the equals() test.
- When you are having a CAS problem, you may want to insert additional logging. For example, if the validate request is failing you may want to print out the exact service= strings being compared and the point at which they differ.
- Apereo defaults all registered services to be able to Proxy, but it seems better if the default is that they cannot Proxy unless you explicitly authorize it. This involves changing the default value for allowedToProxy in AbstractRegisteredService.java from "true" to "false".
- AbstractTicket is a Serializable class, but Apereo source forgot to give it a VersionUID. As a result, every time you deploy a new version of cas-server-core you have to "cold start" CAS by wiping out all the current tickets. You should only have to do that if you actually have changed the Ticket classes, not just because you recompiled the library to change something that has nothing to do with Tickets.
- Yale does not use Single Sign-Out, but code in TicketGrantingTicketImpl added to support that option has a very small but non-zero chance of throwing a ConcurrentAccessException and possibly screwing CAS up. Since we don't need it, Yale might just comment out the statement that causes the problem.
Each of these is a one line change, and only the first is user visible and the last is important for reliablity. If CAS was not open source we would probably just live with the old code, but we have the chance to fix/change it.
Once you start to consider changing Apereo code, then it is inconvenient to maintain two separate projects. For one thing, you need two separate Jenkins build jobs, one for each project.
The alternative is to have a single project that combines both the Apereo source for a CAS release (example: 3.5.2.1) and the Yale code that has been built and tested for that CAS release (separately designated Version 1.1.x). Most of the time the Apereo source just sits there and is not used and is not compiled because it is not changed. If you need to make a modification, it is immediately available and can be compiled simply by adding or re-enabling the <module> statement for that project in the top level pom.xml file.
If you look at the Yale single project file without reading this explanation, it may be confusing. There are a large number of subdirectories of Apereo source, and one of them (cas-server-core) is huge. Yet many of these Maven projects are ignored by the Build job. Why are they there? If the base Apereo code on which you are working is all preloaded into the Project directory tree, then it is easily available for debugging, testing, and possible modification during development. If you don't need to use it, then just ignore it.
The Parent pom.xml
The top level directory is the "parent" project. Typically it is named "cas-server" although this is simply a choice you make when you check the source out from SVN into Eclipse. The only thing in the parent project is its pom.xml file, and a few README-type files.
Changing the parent pom.xml file is one of the most complicated problems of migration from one CAS release to another. Any other file in CAS, whether Java source or HTML has pretty much the same purpose at Yale that it had in the original Apereo code.
However, the top level pom.xml file is not just about compiling the source and building the template WAR file (which is the part Yale needs). Apereo is in the business of maintaining an Open Source Project that is distributed widely on the Internet. A large part of their concern is to make sure that all the legal boilerplate is properly maintained. Do the files all have a proper copyright notice? Are all the licenses to the dependency files properly listed? Maven has some impressive support for doing all this open source release management, but unless that is something you specifically have learned, setting up the legal boilerplate is a daunting task.
Yale is a CAS customer. We may have our own files, but unless and until we contribute them back to Apereo we do not care if a file that nobody sees outside Yale has a proper open source copyright notice and license declaration. If we try to use the Apereo top level pom.xml file as distributed, then every time we try to cut a Yale release we get error messages for all the boilerplate that is missing from our own files. So we create our own top level pom.xml that just has the Maven configuration to compile the code and build the WAR.
Every so often Apereo generates a release that has some new processing step added to the build, and that in turn requires adding something to the top level pom.xml file. When that happens we have to notice it and add the same configuration item to our version of the file.
The Yale top level pom.xml file contains the following sections:
- Version - The Yale pom.xml has Yale version IDs (1.1.2-SNAPSHOT) instead of Apereo (3.5.2.1).
- SCM - defines the Yale Subversion server where all Yale projects maintain their production source.
- Repositories - defines Yale's Artifactory, but merged with other sources for artifacts from the Apereo pom.
- pluginManagement - Maven is a modular system of extensible functions implemented by optional "plugin" modules. Yale has to maintain the plugin configurations that actually build the code (the AspectJ processing plugin for example) while dumping the open source project boilerplate managing steps (the maven-license-plugin and maven-notice-plugin for example). We also reconfigure some plugins. For example, when you are done working on Version 1.1.1-SNAPSHOT and want to create the official 1.1.1 Yale version of CAS and then reset the project to begin work on 1.1.2-SNAPSHOT, you call the Yale Jenkins Build job "Perform Maven Release" operation, which in turn uses the maven-release-plugin. At Yale we find that running the JUnit tests during this process is not only slow but a bad idea, so we change the configuration of the release plugin in the parent pom to bypass tests.
- dependencyMangement - the top level pom.xml lists standard version numbers for dependency JAR libraries shared by all the projects at compile and run time. Unfortunately, when Yale develops its own code it may need a later version of the same library. For example, Apereo is happy with commons-io Version 2.0, but Yale code needs Version 2.4. Apache is smart enough to make the 2.4 library downward compatible with programs written for 2.0, but swapping a newer better version of a library is tricky. The first step is that our top level pom.xml declares the 2.4 version to be the one we want so that all our projects use the same version. This also ensures that the 2.4 version of the commons-io JAR will be merged into the WAR during the Overlay processing.
- However, there is a final processing step that has to be done in the WAR Overlay project and is related to but not directly specified in the parent pom.xml file. Because we are using some unmodified CAS 3.5.2.1 modules (particularly cas-server-webapp) and then we merge in new libraries from the WAR Overlay project, the resulting cas.war file would have a WEB-INF/lib with both commons-io-2.0.jar (from vanilla cas-server-webapp) and commons-io-2.4.jar from the Yale Overlay WAR project. So we have to add an exclude statement in the configuration of maven-war-plugin in the WAR Overlay project to remove the unwanted commons-io-2.0.jar file). Generally speaking, we remove any file that the build process would normally include that is bad for JBoss or where there are multiple versions of the same code and we only want to keep the latest version.
- modules - The directory contains the source and pom files for all the Apereo code. However, we only want to compile things that have been changed. Maven only looks at subdirectories mentioned by a <module> statement in the top level pom.xml file. Initially we comment out all the Apereo <module> statements and add statements for the Yale subprojects. When an Apereo project is to be changed, then it is reassigned a Yale (1.1.x-SNAPSHOT) ID and its <module> statement is uncommented. From one CAS release to another the inventory of Apereo projects and <module> statements changes and has to be updated even if they start out all commented out.
- Parameters - At the end of the POM there are <parameter> statements that Apereo uses to specify the version numbers of dependency libraries and Java.
Subversion
One weakness of Subversion is that it tracks history based on the name and path of a file. If you rename or move a file, Subversion "loses" its history. Git does not suffer from this problem, and if we really did serious ongoing "development" in CAS all the time Git would be a much better source repository for us to use.
However, Subversion is the Yale standard for source used in production deployment, so everything has to be checked into Subversion at some point if only to put it into the DEV, TEST, and PROD computers in the machine room. Since Yale does not do continuous CAS development, but rather generates a CAS release and then runs it for years before starting work on a new release, a break in source control file history across that two year gap is acceptable.
So in any given cycle of CAS development, you begin by obtaining a copy of the current CAS release from Apereo. You then replace the top level pom.xml with a new one created by merging any changes made by Apereo since the last release with the prior Yale top level pom.xml (and this has to be done manually by someone who understands Maven). Then you merge in the Yale added subdirectories.
This becomes a new project in the /cas area of Yale Subversion. Because it is nominally new, you start without history. If you want to see the history for Apereo code, use Git. If you want to see the actual history of Yale modules, find the Subversion directory of previous CAS development projects.
The ReleaseNotes.html file in in the root of the cas-server project will identify the current state of new directories and any modified files. This should be a descriptive match for the physical code change history in SVNWith CAS 3 Yale starts with the Apereo CAS source directory tree and adds new subproject subdirectories for the Yale added code.
Starting with CAS 4, Yale creates a separate Yale-CAS project directory containing only our subprojects, but we copy the Apereo parent pom.xml file from the distributed Apereo Source distribution and modify it so it becomes a Yale specific file.
Building the WAR
Before you build the WAR, you have to build all the JAR files it will contain. Apereo JAR files can be downloaded by Maven from the Internet so they do not have to be rebuilt. Yale JAR files, and any Apereo JAR files that Yale decides to modify, have be be locally compiled and stored. Yale new and modified artifacts always have a Yale specific Version ID that distinguishes them from the Apereo CAS artifacts.
The CAS WAR that you actually run in the Web server is built in two steps in two Maven projects.
Apereo distributes a project called cas-server-webapp to create an initial template WAR file. This WAR is not particularly useful, but it contains at least a starter version of all the Spring XML used to configure CAS and many CSS, JSP, and HTML pages. It also contains a WEB-INF/lib with the basic JAR libraries needed by a CAS system. This unmodified Apereo WAR file is a "template" that Yale modifies or updates to create our final WAR.
Although you can modify the cas-server-webapp project directly, this results in a directory with a mixture of Apereo files and Yale files, and the next time you get a new CAS release from Apereo you have to sift through them to find out which ones have been changed by Apereo.
Apereo recommends using the WAR Overlay feature of Maven. Yale creates a second WAR project called cas-server-yale-webapp that contains only the files that Yale has changed or added. Generally the WAR Overlay includes:
- Yale Java source for Spring Beans that are slightly modified versions of standard Apereo beans.
- Yale "branded" look and feel (CSS, JSP, HTML).
- Spring XML to configure CAS options that Yale has selected and a few Yale additions.
- A pom.xml file with dependency statements for Apereo optional and Yale additional JAR files referenced by the Spring XML that will be added to WEB-INF/lib.
A normal WAR project simply takes all the files in the project and uses them to build a WAR. A WAR Overlay project, however, starts with a template WAR that has already been built. Maven knows that it is working with a WAR Overlay project when it discovers that the first <dependency> in the POM is a file of type "war". Since one WAR cannot contain another WAR inside it, Maven knows that it is supposed to start with the template (dependency) WAR and update it by replacing or adding files from this project to build the output WAR file.
The Template WAR built by cas-server-webapp contains most of the Spring XML configuration, an initial set of CSS, HTML, and JSP files, and almost all the JAR files needed by CAS in its WEB-INF/lib. It also contains the cas-server-core JAR because which has 95% of all the CAS code.
The Yale WAR Overlay project replaces the CSS, JS, HTML, and JSP files associated with the CAS login function to provide the Yale "look and feel" of the CAS login page that everyone expects. It also replaces some of the subsequent confirmation or error pages to also have the same look.
Yale has selected several CAS optional modules. We use cas-server-support-ldap because we authenticate user passwords to AD using LDAP protocol, and cas-server-integration-ehcache because we use ehcache to replicate tickets between CAS servers. These optional JAR files will have been built by Apereo and are available as Maven artifacts, but they were not included in the cas-server-webapp template because they are optional. So the Yale WAR Overly has to add these JAR files to its list of dependencies and configure these options in new or modified Spring XML files. We also must include the JAR files build by the two Yale projects.
While the WAR Overlay process provides a way to update, replace, or add files, it does not provide any way to delete files you no longer want. However, Maven builds a WAR using the maven-war-plugin which can be configured in the POM file. One configuration option is the <packagingExcludes> list that lists a file (or wildcard set of files) in the Template WAR that are to be removed instead of being copied to the output WAR. There are two cases where this is used:
- Some JAR files used by the cas-server-webapp project to build a WAR that will run in Tomcat are inappropriate for JBoss. JBoss provides its own versions of some JAR files, so the JAR file provided by the application should be deleted.
- If you build everything with a single Maven environment then Maven will ensure that the latest required version of any given JAR file is used by all modules. However, the cas-server-webapp WAR file is built by Apereo with the latest version of all the libraries it uses. Yale has a few of its own projects that it builds in its own Maven environment, and every so often Yale will use a later version of a JAR file than Apereo required. So if cas-server-webapp had a dependency on 1.2.3 of some JAR file and Yale depends on 1.2.4, then the normal WAR Overlay process would copy both versions of the JAR file (1.2.3 and also 1.2.4) to the output WEB-INF/lib. So we add a packagingExcludes statement in the WAR Overly POM to delete the old version (1.2.3) to make sure the only version of the JAR in the WAR we are going to run at Yale has only the version of the library we want to use.
Version Numbers and Project Structure
The first Apereo version of CAS was 3.0.0 and now there are CAS 4.0.x versions. CAS 1 and CAS 2 were written at Yale and are no longer meaningful, but this means that the Maven version numbers starting 1.x and 2.x are free and will never be used by Apereo. So Yale internally is reusing the 1.x Version numbers for Yale modules and for Yale modified versions of Apereo modules. Since Yale only periodically updates its CAS version, we skip over a lot of Apereo version numbers:
Apero Version | Yale Version |
---|---|
3.4.x | 1.0.x |
3.5.x | 1.1.x |
4.0.x | 1.2.x |
This becomes important (and confusing) when Yale has to make a change to an Apereo JAR file to fix a problem we cannot ignore and cannot wait for a new Apereo release. In the Maven repositories there will be a vanilla Apereo artifact ending in *-4.0.2.jar and Yale will then add its own artifact named *-1.2.0.jar. If the artifact is one of the optional libraries, then we will simply add the 1.2.0 dependency to the WAR Overlay project, but if this is cas-server-core or anything else in the template WAR built by the cas-server-webapp project then we also have to add the -4.0.2.jar file to the Exclude list of the Maven WAR plugin configuration in the WAR Overlay POM file.
Although there may be additional code in various stages of development, a CAS release at Yale only depends on three Yale projects:
- cas-server-expired-password-change (to prompt the user to change a password that is a year old)
- cas-server-support-CushyTicketRegistry (only the configuration module is currently used to configure ehcache)
- cas-server-yale-webapp (the WAR Overlay with all the Yale configuration and HTML changes)
In CAS 3 development Yale created a source project that included the standard Apereo source along with the three additional Yale projects in a single directory. The advantage of this project structure is that Yale was recompiling all the source and was building at least formal artifacts with the Yale version numbers for all the Apereo code. If Yale ever wanted to change an Apereo module, all it had to do was to make a change in the Apereo source and then change the dependency version number for that artifact in the WAR Overlay from the vanilla 3.5.x to the Yale 1.1.x. It made modifications to Apereo easy, but it created a lot of work when you upgraded to a new CAS release where you ended up changing the project structure of a bunch of Apereo modules you were never really going to change.
So in CAS 4 we change the Yale project structure to a much simpler and cleaner approach. All the vanilla Apereo code is removed initially. If there are modification we need to make to an Apereo module, that will be a bunch of work we can do later on when it is needed. The Yale project then consists of only the three Yale added projects as subdirectories of a parent CAS project, plus a parent POM as the only file in that parent directory.
The Yale parent POM is a modified version of the parent POM in the vanilla Apereo CAS 4.0.2 source directory. First, we change the version number from 4.0.2 to Yale's 1.2.0 because that is the default version of any Yale written or modified code. Then we comment out all the processing that Apereo has added to Maven to do open source project housekeeping. When you build an open source project for general distribution, there are Maven plugins that make sure that your comment files list the open source licenses of all the open source dependency libraries you use, and plugins that complain about syle (missing JavaDoc commments for example), and plugins that do special release packaging. Yale is a customer and our projects only have to run at Yale, so we don't need all those checks.
We should note that there are two distinct meanings to the term "parent" in a Parent POM.
The parent directory is a Maven project with a POM file with a packaging type of "pom". For example, the Apereo parent POM for CAS 4.0.0 begins with the following declaration:
Code Block |
---|
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server</artifactId>
<packaging>pom</packaging>
<version>4.0.0</version> |
This file is processed when anyone does a Maven "mvn install" operation on the parent directory. In this case, the important part of the Parent Directory POM is that it contains "<module>cas-server-core</module>" statements for every subdirectory that builds an artifact. Maven processes each <module> statement in the order they appear in the Parent Directory POM file, so this file can be written so that a JAR file is built and stored in the Maven repository before a subsequent module is compiled that depends on that JAR file.
There is, however, a second meaning of "parent" that relates to the projects in the subdirectories. Each subproject POM file contains a <parent> reference:
Code Block |
---|
<parent>
<artifactId>cas-server</artifactId>
<groupId>org.jasig.cas</groupId>
<version>4.0.0</version>
</parent> |
The <parent> directory contains DepedencyManagement statements, Maven plugin configuration statements, and <parameter> definitions that are shared by all the subprojects that reference it. This ensures that, for example, all the subdirectory projects are complied with the same version of the Apache commons-io JAR library.
It is a common Maven programming convention that the <parent> POM is also the Parent Directory POM. That is the way that Apereo organizes CAS and it is the way that Yale organizes its CAS additions project, but it is not a requirement. Technically, the Parent simply has to be a project of type "<packaging>pom</packaging>" that has already been processed by Maven and has already been stored in the Maven local repository before it is referenced in a <parent> statement of a subproject POM. When the <parent> POM is also the Parent Directory POM and Maven is invoked to build the parent directory, then by definition the Parent Directory POM is processed first and is stored in the Maven Repository before any of the subdirectory projects are built. However, Shibboleth 3 is an example of another approach where the <parent> POM is itself a subdirectory and the Parent Directory POM but is the first <module> statement and is therefore built and stored in the local Maven repository before any of the subprojects that reference it.
The vanilla Apereo CAS source project has its Parent Directory POM that establishes the global defaults and builds all the Apereo artifacts at version 4.0.2. You can recompile them in your sandbox or you can simply let Maven download the artifacts from the Yale Artifactory network server or from the Internet. Then the Yale CAS source project has its modified version of the Apereo Parent Directory POM with all the open source project boilerplate processing commented out and maybe a few version numbers incremented (for example, Yale changes the Java compiler versions from 1.6 to 1.7 for its own coding). The WAR Overlay (cas-server-yale-webapp) project can get the template WAR from an instance previously complied on the sandbox machine and stored in the local Maven repository, or it can get the standard version of the template WAR complied by Apereo and stored on the internet servers. Either way the template WAR is the same file (except for timestamps) and the WAR Overlay processing produces the same result.
In CAS 3.5.x (Yale version 1.1.x) the Yale CAS source project contains the three Yale subprojects, but it also contains a bunch of vanilla Apereo source subprojects. Some of them build Yale versions of Apereo modules (that is, a cas-server-core-1.1.1.jar file), but just because we build a Yale version of the artifact doesn't mean that it is ever used or deployed anywhere. If you look at the WAR Overlay project (cas-server-yale-webapp) you may find that the <dependency> statement in that POM references the vanilla Apereo Version number (3.5.2.1) and so the Yale version of the artifact we have just compiled is stored but ignored. If you are debugging a probem and need to add trace statements to the vanilla Apereo code on the Sandbox, you can temporarily change the Version number in the WAR Overlay to use your modified code, but then after the problem has been resolved you can revert the WAR Overlay POM to its standard settings and go back to using vanilla Apereo code.
Because the CAS 4.0.x (Yale version 1.2.x) project does not normally contain a copy of any Apereo project, making temporary changes for sandbox debugging is a much larger amount of work. You have to build a custom version of the Apereo JAR file, and that means making all the necessary changes to the project and subproject directories to make it work. It is important if you do this to NEVER compile a modified version of the Apereo source and store it in the local Maven repository under the vanilla Apereo version number. Once you have stored your own modified version of cas-server-core-4.0.2.jar then without some custom cleanup on your part it will override the real vanilla version of the module and you will always get the modified version on that Sandbox machine. So if you decide to do some work on a previously vanilla Apereo project, the first thing to do is to change the Version number in the project POM.
Why Not Vanilla?
Apereo code contains some bugs or sloppy coding. Yale has found them and reported them informally, but there has not been much interest in fixing them. Some examples of differences of opinion or bugs:
- The "service=" parameter value on the CAS login has to exactly match the value of the same parameter on the validate, serviceValidate, or samlValidate request. There is a difference of option about how carefully they have to match. The JASIG code matched the entire string excluding JSESSIONID if it was present. Yale believes that the entire query string (everything after the "?") should be excluded, and maybe the match should stop with context (https://servername/context/stuff-to-be-ingnored). This changes the substrings used in the equals() test.
- In the Login WebFlow logic Apereo saves the generated TGTID in a "request" scoped variable between the userid/password form and the CASTGC cookie generation, but when we insert the Duo second login screen all "request" scoped variables are lost. We had to copy it to "flow" scope during the display of the Duo form.
- When you are having a CAS problem, you may want to insert additional logging. For example, if the validate request is failing you may want to print out the exact service= strings being compared and the point at which they differ.
- Apereo defaults all registered services to be able to Proxy, but it seems better if the default is that they cannot Proxy unless you explicitly authorize it. This involves changing the default value for allowedToProxy in AbstractRegisteredService.java from "true" to "false".
- AbstractTicket is a Serializable class, but Apereo source forgot to give it a VersionUID. As a result, every time you deploy a new version of cas-server-core you have to "cold start" CAS by wiping out all the current tickets. You should only have to do that if you actually have changed the Ticket classes, not just because you recompiled the library to change something that has nothing to do with Tickets.
- Yale does not use Single Sign-Out, but code in TicketGrantingTicketImpl added to support that option has a very small but non-zero chance of throwing a ConcurrentAccessException and possibly screwing CAS up. Since we don't need it, Yale might just comment out the statement that causes the problem.
Each of these is a one line change, and only the first is user visible and the last is important for reliablity. If CAS was not open source we would probably just live with the old code, but we have the chance to fix/change it.
Whether we use vanilla Apereo code or make Yale modifications depends on Yale requirements, staffing, and management. There is a cost and commitment to maintaining a modification, but there is also a problem if some application does not work correctly or if some Yale need is not being properly addressed.
Subversion
If you check out a project from Subversion, then you rename a file or copy it to another directory, and then commit the changes, Subversion doesn't realize that the file has been renamed or moved. It sees that the original file name is no longer where it once was, and that a new file name has appeared in the directory, so it treats this as a delete and a create. All the file history is lost.
The command level Subversion client has commands that copy a file and link its old history to its new location. So if it matters, there are some things you should do with Subversion outside the Eclipse environment. This is easy to learn with any Linux Sandbox development environment.
During Sandbox development your complied JAR and WAR artifacts are stored in the local Maven repository on the Sandbox machine. However, the result of Sandbox development is to make and commit source changes to the Subversion version of the project. When you move to DEV (and then TEST and PROD) the Jenkins Build process will check out and compile the project and build new copies of the artifacts on the Jenkins managed machines and store them in the Artifactory network server.
An Eclipse project is built when you check a Maven project out of Subversion into the Eclipse Workspace. Generally a Sandbox instance will contain an Eclipse Workspace directory, it will contain a CAS project, and that project will contain source from some earlier version of CAS development. The first step when you begin work on CAS is to update the source in the workspace project with the latest version from Subversion.
There is a small amount of customization that has to be done manually after the project is checked out of Subversion into an Eclipse Workspace. For example, every Maven J2EE project seems to default to Java 1.6 while Yale CAS modules are written to use Java 1.7. So you have to manually go in and change the project defaults and the generated library section of the Eclipse Build configuration. Updating the contents of an existing Eclipse project preserves this customization, while checking out a complete new Maven project from Subversion means you will have to redo the small amount of post checkout project cleanup.
The Jenkins Build and Install Jobs
...