001/**
002 * Copyright 2005-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kim.client.acegi;
017
018import java.io.StringReader;
019
020import javax.xml.parsers.DocumentBuilder;
021import javax.xml.parsers.DocumentBuilderFactory;
022
023import org.acegisecurity.AuthenticationServiceException;
024import org.acegisecurity.BadCredentialsException;
025import org.acegisecurity.providers.cas.TicketResponse;
026import org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator;
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.kuali.rice.kim.sesn.DistributedSession;
030import org.w3c.dom.Document;
031import org.w3c.dom.Element;
032import org.w3c.dom.NodeList;
033import org.xml.sax.InputSource;
034
035import edu.yale.its.tp.cas.client.ProxyTicketValidator;
036
037
038/**
039 * Uses CAS' <code>ProxyTicketValidator</code> to validate a service ticket.  
040 * Creates the distributed session.  Session principal is currently 
041 * user@method.
042 *  
043 * @author Kuali Rice Team (rice.collab@kuali.org)
044 *
045 */
046public class KualiCasProxyTicketValidator extends CasProxyTicketValidator {
047    //~ Static fields/initializers =====================================================================================
048
049    private static final Log logger = LogFactory.getLog(KualiCasProxyTicketValidator.class);
050
051    private DistributedSession distributedSession;
052    //~ Instance fields ================================================================================================
053
054
055    /**
056     * This overridden method gets the authentication source and 
057     * Distributed Session Ticket from the response
058     * 
059     * @see org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator#validateNow(edu.yale.its.tp.cas.client.ProxyTicketValidator)
060     */
061    protected TicketResponse validateNow(ProxyTicketValidator pv)
062        throws AuthenticationServiceException, BadCredentialsException {
063                String                                  sAuthenticationSource = null;
064                String                  sDST = null;
065
066        try {
067            pv.validate();
068        } catch (Exception internalProxyTicketValidatorProblem) {
069            throw new AuthenticationServiceException(internalProxyTicketValidatorProblem.getMessage());
070        }
071
072        if (!pv.isAuthenticationSuccesful()) {
073            throw new BadCredentialsException(pv.getErrorCode() + ": " + pv.getErrorMessage());
074        }
075        
076        logger.debug("PROXY RESPONSE: " + pv.getResponse());
077        
078        if (logger.isDebugEnabled()) {
079            logger.debug("DEBUG");
080        }
081                
082        try {
083                        DocumentBuilderFactory  factory = DocumentBuilderFactory.newInstance();
084                        DocumentBuilder                 builder = factory.newDocumentBuilder();
085                        InputSource inStream = new InputSource();
086                        inStream.setCharacterStream(new StringReader(pv.getResponse()));
087                        Document                                doc     = builder.parse(inStream);
088                        Element                                 head = doc.getDocumentElement();
089                        NodeList                                attrs = head.getElementsByTagName("cas:attribute");
090                        for (int i=0; i<attrs.getLength(); i++) {
091                                logger.debug(("Field name:" + ((Element)attrs.item(i)).getAttribute("name")) + "=" + ((Element)attrs.item(i)).getAttribute("value"));
092                                if ( ((Element)attrs.item(i)).getAttribute("name").equals("authenticationMethod") ) {
093                                        sAuthenticationSource = ((Element)attrs.item(i)).getAttribute("value");
094                                } else if ( ((Element)attrs.item(i)).getAttribute("name").equals("DST") ) {
095                                    sDST = ((Element)attrs.item(i)).getAttribute("value");
096                                }
097                        }
098                        if (sAuthenticationSource != null && sDST != null) {
099                String sPrincipal = pv.getUser() + "@" + sAuthenticationSource;
100
101                if (logger.isDebugEnabled()) {
102                                logger.debug("Updating session: " + sDST + " " + sPrincipal);
103                            }
104// Touching here may be overkill since it should happen in the filter
105                distributedSession.touchSesn(sDST);
106              //  distributedSession.addPrincipalToSesn(sDST, sPrincipal);
107                        } else {
108                            if (logger.isDebugEnabled()) {
109                    logger.debug("Incomplete data from CAS:" + sAuthenticationSource + ":" + sDST);
110                }
111                        }
112        } catch (Exception e) {
113                logger.error("Error parsing CAS Result", e);
114        }
115        
116        logger.debug("Authentication Method:" + sAuthenticationSource);
117        return new KualiTicketResponse(pv.getUser(), pv.getProxyList(), pv.getPgtIou(), sDST);
118    }
119
120
121    /**
122     * @param distributedSession the distributedSession to set
123     */
124    public void setDistributedSession(DistributedSession distributedSession) {
125        this.distributedSession = distributedSession;
126    }
127    
128
129}