Skip to end of metadata
Go to start of metadata
Table of Contents

At the moment the JA-SIG Java Client 3.1 is relatively new and there are not so many examples out there. This is a simple web application, that claims to demonstrate JA-SIG Java Client 3.1 showing a public and protected page and how to generate proxy tickets for legacy services. It also was developed with minimalistic dependencies in mind and purely showing how to use the JA-SIG client. For this sample web application it's expected, that you know a little about tomcat configuration and that you read further on different sites, how to setup basic stuff (example certificates).

If you want to start modifying this example, I recommend reading Configuring the Jasig CAS Client for Java in the web.xml first.

Scenario Overview

To put the test application in a bit more realistic environment, we're using two separate Tomcat servers. One Tomcat is serving only the JA-SIG CAS Server and the other one only our sample web application. In the end we will produce proxy tickets (PT) to authenticate users in a legacy application. This legacy application doesn't have to be a web application, but have to have a URL as some kind of an identifier. I will show an example later on, how such an application can consume proxy tickets.

By dividing the sample web application and CAS Server into two Tomcat instances, you can easier figure out, where a URL is pointing to. In this example all "https://localhost/" are pointing to CAS server, all "https://localhost:8443/" are pointing to this sample web application.

Preparing The Tomcat Servers

When using Tomcat as application server, I always propose to set an environment variable "JAVA_HOME", pointing to the root of your Java installation directory. I also assume, that you are using a JDK, cause you are a developer, right? (wink)

In this sample I will assume you are using a JDK (not a JRE) and running under Windows 2000/XP/2003/Vista Operating System. I also like to install all these programs directly in the root folder of drive C. So all pathnames are only recommendations.

Preparing And/Or Creating The Certificates

Now we need to create a self signed certificate, make it available for Tomcat and create a key store with trusted certificates. If this is the first time, you're doing such stuff, take a deep breath and catch up a big cup of strong coffee, you probably will need it (wink) In case you don't like coffee, strong black tea has nearly the same effect.

I don't want to explain how to create certificates at this point, thats why I'm showing you other documents that will help you. In general you should have before OR after reading this other articles a basic understanding of what digital certificates are, how to create, use and verify them.

  • X.509 Certificates (CAS user manual, general overview)
  • Demo (CAS user manual, step by step installation/setup guide)

I'm using this program from Andreas Sterbenz (mentioned in Demo or google for hist name +certificate) to generate a "jssecacerts" file and place it in "%JAVA_HOME%\jre\lib\security\jssecacerts". I also was a bit lazy and didn't configure the key store and trust store file locations in Tomcat's server.xml, cause I'm counting on the "automatic discovery" from Java SE. But in the end we want to have a error free running Tomcat with a signed certificate and an accessible trusted keys storage.

Preparing CAS Server

First you should download the Tomcat server from http://tomcat.apache.org, and install it under "c:\tomcat-cas" (installing means, just unzip or use the installer). Then we need to download JA-SIG CAS Server (Download: http://www.ja-sig.org/products/cas/downloads/index.html). Copy the .WAR file from the downloaded archive and rename it to "c:\tomcat-cas\webapps\cas.war" (as also described in Demo).

Edit the file "c:\tomcat-cas\conf\server.xml" and change the following:

  • In the beginning, change
    to a different value, lets say port="8555". This will avoid conflicts, when using multiple tomcats
  • Do comment out the
    We don't need HTTP connector, so comment out.
  • Do comment out the
    We don't need AJP connector, so comment out.
  • Uncomment the SSL connector, cause we really need it

Save the file and (re)start the server. I assume, that the "certstore" and "truststore" is accessible by this Tomcat (see above, creating certs).

You should now be able to connect to "https://localhost/cas" with your browser.

Preparing The Sample Web Application

Install a new and fresh copy of Tomcat into "c:\tomcat-mywebapp\". I'm using Tomcat v5.5.25, but any v6.0.x should also work fine. Cause we are installing a second Tomcat on the same box, we also have to change some setting to avoid conflicts and get it running.
Edit the file "c:\tomcat-mywebapp\conf\server.xml" and change the following:

  • In the beginning, change
    to a different value, lets say port="8666". This will avoid conflicts, when using multiple tomcats
  • Do comment out the
    We don't need HTTP connector, so comment out.
  • Do comment out the
    We don't need AJP connector, so comment out.
  • Uncomment the SSL connector, cause we really need it and change the port to 8443

Save and (re)start this Tomcat.

Download and copy the attached mywebapp.war into a temporary folder, for example "c:\temp\mywebapp.war". In order to keep the download small, I didn't include the required .JAR files. So you have to download them additionally and put them into this mywebapp.war. The structure of the mywebapp.war should look like this (after adding the .JAR files).

mywebapp.war
  |
  +---META-INF/
  .   |
  .   |---manifest.mf
  +---protected/
  .   |
  .   |---getpt.jsp
  .   |---index.jsp
  +---WEB-INF/
  .   |
  .   +---classes/
  .   +---lib/
  .   .   |
  .   .   |---cas-client-core-3.1.1.jar     (from JA-SIG Java client release 3.1.1)
  .   .   |---commons-logging-1.1.jar       (from JA-SIG Java client release 3.1.1)
  .   .   |---xercesImpl.jar                (from Apache Xerces release 2.9.1)
  .   .   |---xml-apis.jar                  (from Apache Xerces release 2.9.1)
  .   .   |---xmlsec-1.3.0.jar              (from JA-SIG Java client release 3.1.1)
  .   |---web.xml
  |---include_footer.jsp
  |---include_header.jsp
  |---index.jsp
  |---license.txt
  |---main.css

Xerces can be found at http://xerces.apache.org/xerces2-j/download.cgi (download the binaries).

After adding the .JAR files to the mywebapp.war, copy it to "c:\tomcat-mywebapp\webapps\mywebapp.war".

Now, you should have two non-conflicting Tomcat servers up and running, using the same certificates (this makes our life a little easier). Go ahead to "https://localhost:8443/mywebapp/". You should see the sample public page.

Result

In case everything went fine, like described in this article, you should now have access to the sample application. You will enter a public page. When going to protected page, you need to authenticate yourself on CAS server (demo mode uses user name equals password, like: test/test). In protected page area you can generate proxy tickets for legacy applications.

Screenshots

For sure, that's not a genius design, but the application is minimalistic and working fine, showing you, how to use JA-SIG Java 3.1 client.

Authentication In Legacy Application

For this given scenario, you can add this method to you sources, verify the proxy ticket and get the user name from the response.

TicketValidator.java

Troubleshooting

If you get something like this NullpointerException, please apply the patch from http://www.ja-sig.org/issues/browse/CASC-50

  • No labels

9 Comments

  1. Hi Martin,

    Is that possible to get first name and last name, the CAS server attributes, using principal? or which class I can use to retrieve the CAS's entire response if authentication was succsesful?

    I used .getAttribute(), but returned nothing. Please help me out.

     Thanks,

     Kevin

  2. Nice article, especially since it does a good job of trying to delineate between the Web app and the "legacy" or proxied application. However, in my mind, there's a bit of confusion caused by the choice of URLs to signify the CAS server and the legacy server. Here are some suggestions:

    1. I think it would be better if instead of "https://localhost/" to refer to the CAS server, you wrote something like "https://localhost/cas-web/" – having CAS in the URI immediately tells me which server (and Web app) this is. As it is now, I found myself scrolling back to the top to remind myself of which was which.

    2. In the code snippet to be applied to the legacy application, you refer to two different URLs. I'd suggest refactoring the strings "https://localhost/cas" and "http://otherserver/legacy/service" to something like

    String casServerUrl = "https://localhost/cas";
    String legacyServerServiceUrl = "http://otherserver/legacy/service";

    These variable names explicitly tell the reader the meaning of the URL, hopefully removing any doubt from the reader's mind. And there will be doubts and questions for anyone who is new to this. (Sort of like me – familiar with what CAS does, but not so sure of how to go about using it in my SSO scenarios especially when doing proxy authentication.)

    1. Hi,

      you are right, the names are not the best choose.
      What do you think about "https://localhost/cas" for CAS and "https://localhost/mywebapp" for the sample?
      If there are no "NOs", I will do rename all and everything in the sample and update the download files.

      I mean, having two Tomcats running on one box is also confusing. But, my target was to make it easier in case you have a distributed environment. So different ports and names showing the direction.

  3. I followed the instructions, and the example works fine for me.
    My doubt is very foundational. Every time the ticket validation filter runs, it means a ticket validation against CAS server?
    I have doubts. I shutdown the CAS server, and the user still seems valid.

  4. When I browse to the JA-SIG website (https://wiki.jasig.org/display/CASC/JA-SIG+Java+Client+Simple+WebApp+Sample) for the WebApp sample. I tried the same instructions, but it still doesn't work. Would you tell me how did you make your test? It is very appreciated if you can show me the detail step-by-step (based on the previous website content) methods to make this sample work.

    Tomcat version: apache-tomcat-6.0.33

    CAS server version: cas-server-3.4.10

    Thank you very much.

  5. Here I have a problem while generating PT its a last step in the process. I am getting an exception at the following statement in getpt.jsp

    String result1 = assertion1.getPrincipal().getProxyTicketFor(targetService);

    I am using the same jar files as stated in this examples and I just changed project name. The same project name I updated in web.xml also.

    I relly appreciate your help.

    Here my legacy applicaiton is deplyed on different server but it is not CASified.

    2012-04-20 14:08:36,236 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/proxywebapp].[jsp]] (ajp-0.0.0.0-8009-5) Servlet.service() for servlet jsp threw exception: java.io.IOException: Server returned HTTP response code: 500 for URL: https://auth.westernu.edu/proxy?pgt=TGT-28-pgYrJyFzcS29XABSfohqNDsxMYi1AY9ePywUSElx9Uti7OTqVo-cas&targetService=http%3A%2F%2Fit04.westernu.edu%3A8080%2Ffinancialaid%2F  

    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1436)  

    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)  

    at org.jasig.cas.client.proxy.Cas20ProxyRetriever.getProxyTicketIdFor(Cas20ProxyRetriever.java:65)  

    at org.jasig.cas.client.authentication.AttributePrincipalImpl.getProxyTicketFor(AttributePrincipalImpl.java:87)  

    at org.apache.jsp.protected_.getpt_jsp._jspService(getpt_jsp.java:169)  

    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)  

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)  

    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:369)  

    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:326)  

    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:253)  

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)  

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324)  

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)  

    at org.jasig.cas.client.util.AssertionThreadLocalFilter.doFilter(AssertionThreadLocalFilter.java:40)  

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274)

     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)  

    at org.jasig.cas.client.util.HttpServletRequestWrapperFilter.doFilter(HttpServletRequestWrapperFilter.java:50)

     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274)  

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)  

    at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:163)  

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274)  

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)  

    at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:103)  

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274)  

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)  

    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)  

    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)  

    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)  

    at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285)

     at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261)  

    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88)  

    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100)  

    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:159)  

    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)  

    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)  

    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)  

    at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)  

    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)  

    at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:504)  

    at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:437)  

    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951)  at java.lang.Thread.run(Thread.java:662)

     

    1. Hi,

      it looks, that your server responds: "Server returned HTTP response code: 500..."
      So you should look into the server's log file to see whats going wrong.

      Regards
      Martin

      1. Thank you very much for your reply. The following error is from the CAS server logs

        org.apache.catalina.core.StandardWrapperValve invoke
        SEVERE: Servlet.service() for servlet [cas] in context with path [] threw exception [Request processing failed; nested exception is org.jasig.cas.services.UnauthorizedServiceException: service.not.authorized] with root cause
        org.jasig.cas.services.UnauthorizedServiceException: service.not.authorized
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket_aroundBody2(CentralAuthenticationServiceImpl.java:190)
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket_aroundBody3$advice(CentralAuthenticationServiceImpl.java:44)
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket(CentralAuthenticationServiceImpl.java:1)
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket_aroundBody4(CentralAuthenticationServiceImpl.java:251)
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket_aroundBody5$advice(CentralAuthenticationServiceImpl.java:44)
            at org.jasig.cas.CentralAuthenticationServiceImpl.grantServiceTicket(CentralAuthenticationServiceImpl.java:1)
            at sun.reflect.GeneratedMethodAccessor126.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
            at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
            at org.perf4j.aop.AbstractTimingAspect$1.proceed(AbstractTimingAspect.java:47)
            at org.perf4j.aop.AgnosticTimingAspect.runProfiledMethod(AgnosticTimingAspect.java:53)
            at org.perf4j.aop.AbstractTimingAspect.doPerfLogging(AbstractTimingAspect.java:45)
            at sun.reflect.GeneratedMethodAccessor98.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
            at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
            at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
            at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
            at com.github.inspektr.audit.AuditTrailManagementAspect.handleAuditTrail(AuditTrailManagementAspect.java:126)
            at sun.reflect.GeneratedMethodAccessor96.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
            at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
            at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
            at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
            at $Proxy36.grantServiceTicket(Unknown Source)
            at org.jasig.cas.web.ProxyController.handleRequestInternal(ProxyController.java:72)
            at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
            at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
            at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
            at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
            at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
            at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
            at org.jasig.cas.web.init.SafeDispatcherServlet.service_aroundBody2(SafeDispatcherServlet.java:115)
            at org.jasig.cas.web.init.SafeDispatcherServlet.service_aroundBody3$advice(SafeDispatcherServlet.java:44)
            at org.jasig.cas.web.init.SafeDispatcherServlet.service(SafeDispatcherServlet.java:1)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
            at com.github.inspektr.common.web.ClientInfoThreadLocalFilter.doFilter(ClientInfoThreadLocalFilter.java:63)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
            at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
            at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
            at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
            at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1571)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:662)

         

        Why this error is throwing? UnauthorizedServiceException means Was it complaining about the legacy application?

        Regards,

        Bhaskar.

        1.   Actually the second method

          Assertion assertion2 = AssertionHolder.getAssertion();  is throwing exception. When I commented out the following

          String result2 = assertion2.getPrincipal().getProxyTicketFor(targetService); application worked well and got the PT from assertion 1.

          Now my problem is when I tested the PT with the following URL

          https://cas_server/proxyValidate?service=https://someserver/TestApp1/sso/ProtectedServlet&ticket=ST-9-DGUYLhUyTmH494YaAGv1-cas

          the result xml is

          <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
          	<cas:authenticationFailure code='INVALID_TICKET'>
          		ticket &#039;ST-9-DGUYLhUyTmH494YaAGv1-cas&#039; not recognized
          	</cas:authenticationFailure>
          </cas:serviceResponse>

          Why PT become invalid? Really appreciate your help.

          Regards,

          Bhaskar.