diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index a9b4390..a9c8504 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -45,6 +45,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { handler.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket")); handler.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName", "logoutRequest")); handler.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig, "artifactParameterOverPost", "false"))); + handler.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig, "eagerlyCreateSessions", "true"))); } handler.init(); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index b47e94f..04cceeb 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -54,6 +54,8 @@ public final class SingleSignOutHandler { private boolean artifactParameterOverPost = false; + private boolean eagerlyCreateSessions = true; + private List safeParameters; @@ -83,6 +85,10 @@ public final class SingleSignOutHandler { this.logoutParameterName = name; } + public void setEagerlyCreateSessions(final boolean eagerlyCreateSessions) { + this.eagerlyCreateSessions = eagerlyCreateSessions; + } + /** * Initializes the component for use. */ @@ -128,7 +134,12 @@ public final class SingleSignOutHandler { * @param request HTTP request containing an authentication token. */ public void recordSession(final HttpServletRequest request) { - final HttpSession session = request.getSession(true); + final HttpSession session = request.getSession(this.eagerlyCreateSessions); + + if (session == null) { + log.debug("No session currently exists (and none created). Cannot record session information for single sign out."); + return; + } final String token = CommonUtils.safeGetParameter(request, this.artifactParameterName, this.safeParameters); logger.debug("Recording session for token {}", token); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java index 627ca9a..99637ac 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java @@ -27,10 +27,16 @@ import org.jasig.cas.client.proxy.ProxyRetriever; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.StringReader; +import java.util.*; /** * Implementation of the TicketValidator that will validate Service Tickets in compliance with the CAS 2. @@ -128,27 +134,18 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick * @return the map of attributes. */ protected Map extractCustomAttributes(final String xml) { - - if (!xml.contains("")) { - return new HashMap(); - } - - final Map attributes = new HashMap(); - + final SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + spf.setValidating(false); try { - NodeList nodeList = XmlUtils.getNodeListForElements(xml,"cas:attributes"); - for (int i = 0; i < nodeList.getLength(); i++) { - final String nodeName = nodeList.item(i).getNodeName(); - final int beginIndex = nodeName.indexOf(":") + 1; - final int endIndex = nodeList.item(i).getNodeName().length(); - - final String attributeName = nodeName.substring(beginIndex, endIndex); // remove the "cas:" prefix from node name - final Object attributeValue = nodeList.item(i).getTextContent(); - attributes.put(attributeName, attributeValue); - } - return attributes; - - } catch (Exception e) { + final SAXParser saxParser = spf.newSAXParser(); + final XMLReader xmlReader = saxParser.getXMLReader(); + final CustomAttributeHandler handler = new CustomAttributeHandler(); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(xml))); + return handler.getAttributes(); + } catch (final Exception e) { + log.error(e.getMessage(), e); return Collections.emptyMap(); } } @@ -187,4 +184,65 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick protected final ProxyRetriever getProxyRetriever() { return this.proxyRetriever; } + + private class CustomAttributeHandler extends DefaultHandler { + + private Map attributes; + + private boolean foundAttributes; + + private String currentAttribute; + + private StringBuilder value; + + @Override + public void startDocument() throws SAXException { + this.attributes = new HashMap(); + } + + @Override + public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes attributes) throws SAXException { + if ("attributes".equals(localName)) { + this.foundAttributes = true; + } else if (this.foundAttributes) { + this.value = new StringBuilder(); + this.currentAttribute = localName; + } + } + + @Override + public void characters(final char[] chars, final int start, final int length) throws SAXException { + if (this.currentAttribute != null) { + value.append(chars, start, length); + } + } + + @Override + public void endElement(final String namespaceURI, final String localName, final String qName) throws SAXException { + if ("attributes".equals(localName)) { + this.foundAttributes = false; + this.currentAttribute = null; + } else if (this.foundAttributes) { + final Object o = this.attributes.get(this.currentAttribute); + + if (o == null) { + this.attributes.put(this.currentAttribute, this.value.toString()); + } else { + final List items; + if (o instanceof List) { + items = (List) o; + } else { + items = new LinkedList(); + items.add(o); + this.attributes.put(this.currentAttribute, items); + } + items.add(this.value.toString()); + } + } + } + + public Map getAttributes() { + return this.attributes; + } + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java index c250969..0b1f137 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidatorTests.java @@ -139,13 +139,14 @@ public final class Cas20ServiceTicketValidatorTests extends AbstractTicketValida + USERNAME + "" + PGTIOU - + "testid"; + + "testidtest1\n\ntest"; server.content = RESPONSE.getBytes(server.encoding); final Assertion assertion = this.ticketValidator.validate("test", "test"); assertEquals(USERNAME, assertion.getPrincipal().getName()); assertEquals("test", assertion.getPrincipal().getAttributes().get("password")); assertEquals("id", assertion.getPrincipal().getAttributes().get("eduPersonId")); + assertEquals("test1\n\ntest", assertion.getPrincipal().getAttributes().get("longAttribute")); //assertEquals(PGT, assertion.getProxyGrantingTicketId()); }