How to check if I am logged into CAS or not

View: New views
4 Messages — Rating Filter:   Alert me  

How to check if I am logged into CAS or not

by doahh :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I have been looking for a solution to my problem for a couple of weeks now and having asked on a couple of other forums no-one seems to have any ideas at all (there are views but no replies to my posts).

I am using CAS-3.2.1 with Spring-security-2.0.2 and cas-client-core-3.1.3.

I can log into CAS and access the protected pages in WebApp1. when I go to WebApp2, as long as I access a page that is secured by Spring-security then everything is fine. However, if I access an unprotected page before accessing a protected one, WebApp2 does not know I am logged in and so cannot show any items on the page that are secured by spring-security.

Is there a way for me to ask CAS directly from WebApp2 whether or not I am logged in without me having to go through the log in process?

I hope you can help because I am completely stuck.

Parent Message unknown RE: How to check if I am logged into CAS or not

by Mathieu ROUSSELLE :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello doahh,

Have you tried the gateway feature of the CAS 2.0 protocol ?

http://www.ja-sig.org/products/cas/client/gateway/index.html

It will redirect user browser to the CAS authentication server without displaying login page.
If TGC is found then browser is redirected to the service (Webapp2) with the service ticket.
If the user was not authenticated, the browser is redirected to the service with a parameter avoiding gateway looping.

This might help you.


Mathieu Rousselle

-----Message d'origine-----
De : cas-bounces@... [mailto:cas-bounces@...] De la part de doahh
Envoyé : jeudi 26 juin 2008 17:24
À : cas@...
Objet : How to check if I am logged into CAS or not


I have been looking for a solution to my problem for a couple of weeks now
and having asked on a couple of other forums no-one seems to have any ideas
at all (there are views but no replies to my posts).

I am using CAS-3.2.1 with Spring-security-2.0.2 and cas-client-core-3.1.3.

I can log into CAS and access the protected pages in WebApp1. when I go to
WebApp2, as long as I access a page that is secured by Spring-security then
everything is fine. However, if I access an unprotected page before
accessing a protected one, WebApp2 does not know I am logged in and so
cannot show any items on the page that are secured by spring-security.

Is there a way for me to ask CAS directly from WebApp2 whether or not I am
logged in without me having to go through the log in process?

I hope you can help because I am completely stuck.
--
View this message in context: http://www.nabble.com/How-to-check-if-I-am-logged-into-CAS-or-not-tp18136646p18136646.html
Sent from the CAS Users mailing list archive at Nabble.com.

_______________________________________________
Yale CAS mailing list
cas@...
http://tp.its.yale.edu/mailman/listinfo/cas
_______________________________________________
Yale CAS mailing list
cas@...
http://tp.its.yale.edu/mailman/listinfo/cas

RE: How to check if I am logged into CAS or not

by doahh () :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for replying Mathieu,

I have now managed to get it working based on the info you gave.

RE: How to check if I am logged into CAS or not

by doahh :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I don't know if it is of any use to someone but I will detail my solution below (using spring-security-2.0.1). This really was the only way I could make it work as I wanted:

I added these two beans to the applicationContext-security.xml

 <bean id="CASUnprotectedPageFilter" class="net.tootired.security.spring.cas.CASUnprotectedPageFilter">
        <property name="ignoreFilesOfType" value="css,js,gif,jpg,png,swf,pdf" />
        <property name="loginPage" value="login!goToLogin" />
        <sec:custom-filter after="SWITCH_USER_FILTER"/>
    </bean>
    <bean id="RemoveSavedRequestKeyFilter" class="net.tootired.security.spring.RemoveSavedRequestKeyFilter">
        <sec:custom-filter after="PRE_AUTH_FILTER"/>
    </bean>

And then the two respective classes are:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.tootired.security.spring.cas;

import java.util.HashSet;
import java.util.StringTokenizer;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;

import org.springframework.web.context.support.WebApplicationContextUtils;

import org.springframework.context.ApplicationContext;

import org.springframework.security.AuthenticationCredentialsNotFoundException;

import org.springframework.security.context.SecurityContextImpl;

import org.springframework.security.userdetails.User;

import org.springframework.security.ui.cas.ServiceProperties;

import org.springframework.security.providers.cas.CasAuthenticationToken;

import org.springframework.web.context.ServletContextAware;
       
import org.apache.log4j.Logger;

/**
 * TODO: This filter queries CAS heavily for every request (twice each time). This will lag performace and so it may be sensible for it
 * to detect when a URL is not protected by spring-security first before firing the requests to CAS.
 *
 * <p>For pages that are not secured by spring-security it is not always possible to tell if the user is loggedin. If the user logs in
 * inside of one context and then goes to an unsecured page in another context then the application will not know whether or not the
 * user is logged in. This fixes that by checking for a valid login for every request.</p>
 *
 * <p>This filter will not process requests under the following circumstances:</p>
 *
 * <ul>
 *  <li>If the filetype of the requested file has been passed in, as a comma seperated list, to the setIgnoreFilesOfType(String args);</li>
 *  <li>If the requested URL is the same as setLoginPage(args)</li>
 *  <li>If this is a POST request. This restriction is so that when a form is posted the request is not re-directed to CAS. If
 *  this was allowed to happen then when CAS processed the request and returned us to the page we wanted to go to, we would have
 *  lost the POST data. If this is not desirable then this method could add the posted paramters to the return URL from CAS. This
 *  would have to be done as a GET request though and so would be limited to 256 characters of data. This had not been programmed
 *  in yet and would naturally prevent file uploads and would fail for posted data over the 256 character limit.</li>
 * </ul>
 *
 * @author gavin
 */
public class CASUnprotectedPageFilter implements Filter , ServletContextAware , java.io.Serializable {

    private static final Logger logger = Logger.getLogger(CASUnprotectedPageFilter.class);
    private ServletContext servletContext;
    private String ignoreFilesOfType; // Inputed from applicationContext-security.xml
    private HashSet<String> ignoreFileTypes = new HashSet<String>(); // The HashSet of the parameter taken from variable ignoreFilesOfType
   
    // The URL of the login page as used within the ROOT context. If this filter is not running in the root context this has no effect.
    private String loginPage;
   
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       
        if(request instanceof HttpServletRequest){
            HttpServletRequest httpRequest = (HttpServletRequest) request;
           
            // Find out the file type that was called. There is no point asking CAS if we are logged in when we only want, for example,
            // a stylesheet, image or pdf
            String requestURL = httpRequest.getRequestURL().toString();
            int lastIndexOfDot = requestURL.lastIndexOf(".") + 1;
            String fileType = requestURL.substring(lastIndexOfDot , requestURL.length());
           
            // DEBUG only
            if(ignoreFileTypes.contains(fileType)) logger.debug("Will not run filter for file of type [" + fileType +"] as it is registered to be ignored.");
            if(requestURL.indexOf(loginPage) != -1) logger.debug("Will not run filter as requestURL is registered as loginPage via setLoginPage(.) method.");
            if(httpRequest.getMethod().equalsIgnoreCase("POST")) logger.debug("Will not process filter as request was of type POST.");
            // End DEBUG only
           
            if( ! ignoreFileTypes.contains(fileType) // We don't know what technology this service will be using so exclude the things we know we don't want
                &&
                requestURL.indexOf(loginPage) == -1 // We don't want to see if we are logged in when we are going to the login page
                &&
                ! httpRequest.getMethod().equalsIgnoreCase("POST")  // If we are posting data we don't want to go to CAS as we will  
                                                                    // loose the data on the return from CAS.
              ){
               
                logger.debug("Running filter with filetype [" + fileType +"]");
               
                HttpSession session = httpRequest.getSession(true);

                if(session != null){
                    boolean returnFromCas = new Boolean((String) httpRequest.getParameter("returnFromCas")).booleanValue();
                    boolean loggedInViaCas = new Boolean((String) httpRequest.getParameter("loggedInViaCAS")).booleanValue();

                    logger.debug("returnFromCas [" + returnFromCas +"]");
                    logger.debug("loggedInViaCas [" + loggedInViaCas +"]");

                    // Get the springContext from the session. It will be there if we have logged in via CAS at any time (it will be there even if we logged off)
                    SecurityContextImpl springSecurityContext = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");
                    logger.debug("springSecurityContext [" + springSecurityContext +"]");

                    if(springSecurityContext == null){
                        springSecurityContext = new SecurityContextImpl();
                        session.setAttribute("SPRING_SECURITY_CONTEXT" , springSecurityContext);
                        logger.debug("Created new springSecurityContext and added it to the session under key SPRING_SECURITY_CONTEXT");
                        logger.debug("springSecurityContext [" + session.getAttribute("SPRING_SECURITY_CONTEXT") +"]");
                    }

                    CasAuthenticationToken casAuthenticationToken = null;
                    if(springSecurityContext != null){
                        // Get the user form the springSecurityContext, the user will only be there if they are activly logged on through CAS
                        User user = null;
                        if(springSecurityContext != null){
                            casAuthenticationToken = (CasAuthenticationToken) springSecurityContext.getAuthentication();
                            logger.debug("casAuthenticationToken [" + casAuthenticationToken +"]");

                            if(casAuthenticationToken != null){
                                user = (User) casAuthenticationToken.getPrincipal();
                            }
                        }

                        logger.debug("user [" + user +"] <= null is OK");

                        // Allows access to beans defined in spring config files
                        ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.servletContext); // ServletContext may be a SpringServletContext
                        logger.debug("applicationContext [" + applicationContext +"]");

                        // Get the beans we need. They are defined in /WEB-INF/applicationContext-security.xml
                        ServiceProperties serviceProperties = (ServiceProperties) applicationContext.getBean("serviceProperties");
                        CasProcessingFilterEntryPoint cpfep = (CasProcessingFilterEntryPoint) applicationContext.getBean("casProcessingFilterEntryPoint");

                        String originalServiceURL = serviceProperties.getService();

                        // First time into the page but only if we have already logged into CAS
                        // through either this or another service. This will get us a ticket from CAS
                        if(user == null && !returnFromCas && !loggedInViaCas){

                            // Get the address of this page
                            String file = httpRequest.getRequestURI();
                            if (httpRequest.getQueryString() != null) file += '?' + httpRequest.getQueryString();
                            String thisUrl = new java.net.URL(httpRequest.getScheme() , httpRequest.getServerName() , httpRequest.getServerPort() , file).toString();

                            // If not logged in then we want to use this. It will not thow an error and is always OK but gives a 'ticket'
                            // parameter if logged into CAS.
                            String queryStringSeperator;
                            if(thisUrl.indexOf("returnFromCas=true") == -1){
                                if(thisUrl.indexOf("?") == -1) queryStringSeperator = "?"; // Are we adding the only parameter
                                else queryStringSeperator = "&"; // or to an already existing parameter list
                                       
                                serviceProperties.setService(thisUrl + queryStringSeperator +"returnFromCas=true");
                                logger.debug("1. service [" + serviceProperties.getService() +"]");
                            }

                            cpfep.setUseCASGateway(true); // Tell CAS NOT to show us the login page if we are not logged in.
                            cpfep.commence(request, response, new AuthenticationCredentialsNotFoundException("Authentication credentials not found from CASUnprotectedPageFilter class."));
                            cpfep.setUseCASGateway(false); // Set this back as we only want CAS to act as a gateway on this request
                        }

                        // Returning from CAS possibly with a ticket
                        if(user == null && request.getParameter("ticket") != null && !loggedInViaCas && returnFromCas){

                            // Throws an error if we are not logged in but if we are logged in then we will have a ticket
                            if(originalServiceURL.indexOf("loggedInViaCAS=true") == -1) serviceProperties.setService(serviceProperties.getService() + "?loggedInViaCAS=true");
                            logger.debug("2. service [" + serviceProperties.getService() +"]");
                            cpfep.setUseCASGateway(true); // Tell CAS NOT to show us the login page if we are not logged in.
                            cpfep.commence(request, response, new org.springframework.security.AuthenticationCredentialsNotFoundException("Authentication object not found."));
                            cpfep.setUseCASGateway(false); // Set this back as we only want CAS to act as a gateway on this request
                        }

                        // This must be set back with loggedInViaCas=true
                        if(originalServiceURL.indexOf("loggedInViaCAS=true") == -1){
                            String queryStringSeperator;
                            if(originalServiceURL.indexOf("?") == -1) queryStringSeperator = "?"; // Are we adding the only parameter
                                else queryStringSeperator = "&"; // or to an already existing parameter list
                            serviceProperties.setService(originalServiceURL + queryStringSeperator + "loggedInViaCAS=true");
                        } else {
                            serviceProperties.setService(originalServiceURL);
                        }
                    }
                }
            }
        }
       
        // Continue on with the chain
        chain.doFilter(request , response);
    }
   
    public void init(FilterConfig filterConfig) {
        this.servletContext = filterConfig.getServletContext();
    }

    public void setServletContext(ServletContext servletContext){
        this.servletContext = servletContext;
    }
   
    public void destroy() {}

    public String getIgnoreFilesOfType() {
        return ignoreFilesOfType;
    }

    /**
     * If a file of the type given here is processed through the filter then the filter will not
     * ask CAS if the user is logged in. This is because we do not need to know if the user
     * if logged into CAS for certain types of file to be served up to them. If the user's browser
     * requests a css or javascript file then they can just have it, they don't need to be logged in.
     * We can't do this the other way and allow processing for files of type, for example .jspf as
     * the .jspf files will be included by the server and will not be send to the filter except as part
     * of the whole page request.
     *
     * @param ignoreFilesOfType
     */
    public void setIgnoreFilesOfType(String ignoreFilesOfType) {
        this.ignoreFilesOfType = ignoreFilesOfType;
       
        StringTokenizer stringTokenizer = new StringTokenizer(ignoreFilesOfType , ",");
        while(stringTokenizer.hasMoreTokens()){
            ignoreFileTypes.add(stringTokenizer.nextToken());
        }
       
        logger.debug("Will ignore files of type [" + ignoreFileTypes +"]");
    }

    /**
     * Returns the value set in applicationContext-security.xml
     *
     * @return
     */
    public String getLoginPage() {
        return loginPage;
    }

    /**
     * This parameter should be set from the applicationContext-security.xml file and represents a path that this filter will
     * not run for. The test used is "requestURL.indexOf(loginPage) == -1", if true then this filter will not contact CAS.
     *
     * @param loginPage
     */
    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }
}



and



/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.tootired.security.spring;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;

import org.springframework.security.ui.savedrequest.SavedRequest;

import org.apache.log4j.Logger;

/**
 * <p>This filter removes the SPRING_SECURITY_SAVED_REQUEST_KEY when it is not needed. This resolves undesirable behaviour when a user
 * acts in a certain way. If a user clicks on a page that is secured by spring-security they are taken to the CAS log in page.
 * The SPRING_SECURITY_SAVED_REQUEST_KEY into the session by spring-security before the re-direct to CAS, they are then expected to log in.
 * If they do then they are taken
 * back to the page defined by the SPRING_SECURITY_SAVED_REQUEST_KEY. However, if they decide not to log in and go to another page in
 * a different sub-context (e.g. the forum if they are were about to log into the blog), surf around on the forum for some time and then
 * decide to go back to a different page on the blog to the one they previously visited, the SPRING_SECURITY_SAVED_REQUEST_KEY is stil
 * there. This means that even though they intended to go to a different page in the forum they will still be taken to the first page they
 * requested as the SPRING_SECURITY_SAVED_REQUEST_KEY still points to the first page.</p>
 *
 * <p>This class removes the SPRING_SECURITY_SAVED_REQUEST_KEY if the user has not come from either a page within this context or they have
 * not come from CAS as defined by the presence of either:</p>
 *
 * <ul>
 * <li>A ticket parameter is not present in the request. A ticket may be given by CAS and so would indicate the user has just come from
 * CAS. Therefore do not remove the SPRING_SECURITY_SAVED_REQUEST_KEY;</li>
 * <li>The presence of a returnFromCas parameter that indicates we have just visited CAS to see if we have a valid authentication;</li>
 * <li>The presence of a loggedInViaCAS parameter which indicates that we have just returned froma successful log in through CAS.</li>
 * </ul>
 *
 * <p>The last two items in the above list are custom parameters defined within this application, ticket is defined within CAS.</p>
 *
 * @author gavin
 */
public class RemoveSavedRequestKeyFilter implements Filter {

    private static final Logger logger = Logger.getLogger(RemoveSavedRequestKeyFilter.class);
   
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       
        if(request instanceof  HttpServletRequest){
       
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpSession session = httpRequest.getSession(false);
           
            if(session != null && session.getAttribute("SPRING_SECURITY_SAVED_REQUEST_KEY") != null){
                SavedRequest savedRequest = (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST_KEY");
                String savedRequestURI = savedRequest.getRequestURI();
                String httpRequestContextPath = httpRequest.getContextPath();

                boolean returnFromCas = new Boolean(request.getParameter("returnFromCas")).booleanValue();
                boolean loggedInViaCAS = new Boolean(request.getParameter("loggedInViaCAS")).booleanValue();
                String casTicket = request.getParameter("ticket");

                logger.debug("savedRequest URI [" + savedRequestURI +"]");
                logger.debug("context path [" + httpRequestContextPath +"]");
                logger.debug("returnFromCas [" + returnFromCas +"]");
                logger.debug("loggedInViaCAS [" + loggedInViaCAS +"]");
                logger.debug("Is from with context [" + savedRequestURI.indexOf(httpRequestContextPath) +"]");
                logger.debug("casTicket [" + casTicket +"]");
               
                // See if we came form within this context or from an external context that was not CAS
                if(savedRequestURI.indexOf(httpRequestContextPath) != -1 && !loggedInViaCAS && casTicket != null){
                    logger.debug("Removing SPRING_SECURITY_SAVED_REQUEST_KEY from session");
                    session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST_KEY");
                }
            }
               
        }

        // Continue on with the chain
        chain.doFilter(request , response);
    }

    public void init(FilterConfig filterConfig) {
       
    }

    public void destroy() {
       
    }
}


I also had to override the casProcessingFilterEntryPoint in the applicationContext-security.xml file and make it look like this so that I could set the gateway=true parameter as it wasn't publically available in my build of spring-security:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.tootired.security.spring.cas;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletResponse;

import org.jasig.cas.client.util.CommonUtils;

import org.springframework.security.AuthenticationException;

/**
 *
 * @author gavin
 */
public class CasProcessingFilterEntryPoint extends org.springframework.security.ui.cas.CasProcessingFilterEntryPoint {

    private boolean encodeServiceUrlWithSessionId = true;
    private boolean useCASGateway = false;
   
    @Override
    public void commence(final ServletRequest servletRequest, final ServletResponse servletResponse,
    final AuthenticationException authenticationException) throws IOException, ServletException {

        System.out.println("*************************************");
        System.out.println("Entered CasProcessingFilterEntryPoint.commence(...)");
       
        final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        final String urlEncodedService = CommonUtils.constructServiceUrl(null,
                                                                        httpResponse,
                                                                        getServiceProperties().getService(),
                                                                        null,
                                                                        "ticket",
                                                                        this.encodeServiceUrlWithSessionId);
       
       
        System.out.println("useCASGateway [" + useCASGateway +"]");
        System.out.println("urlEncodedService [" + urlEncodedService +"]");
       
        String redirectUrl = CommonUtils.constructRedirectUrl(getLoginUrl(),
                                                                    "service",
                                                                    urlEncodedService,
                                                                    getServiceProperties().isSendRenew(),
                                                                    useCASGateway);
       
        System.out.println("redirectUrl [" + redirectUrl +"]");
       
        System.out.println("*************************************");
       
        httpResponse.sendRedirect(redirectUrl);
    }

    public boolean isUseCASGateway() {
        return useCASGateway;
    }

    public void setUseCASGateway(boolean useCASGateway) {
        this.useCASGateway = useCASGateway;
    }
           
}
LightInTheBox - Buy quality products at wholesale price