001    /**
002     * Copyright 2005-2011 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     */
016    package org.kuali.rice.kim.client.acegi;
017    
018    import java.io.StringReader;
019    
020    import javax.xml.parsers.DocumentBuilder;
021    import javax.xml.parsers.DocumentBuilderFactory;
022    
023    import org.acegisecurity.AuthenticationServiceException;
024    import org.acegisecurity.BadCredentialsException;
025    import org.acegisecurity.providers.cas.TicketResponse;
026    import org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator;
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.kuali.rice.kim.sesn.DistributedSession;
030    import org.w3c.dom.Document;
031    import org.w3c.dom.Element;
032    import org.w3c.dom.NodeList;
033    import org.xml.sax.InputSource;
034    
035    import 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     */
046    public 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    }