From a68b4e8a08853321065726d228dc837709ab2ea6 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 3 Oct 2006 13:14:02 +0000 Subject: [PATCH] updated to reflect that Assertion now has a reference to ProxyRetriever --- .../AbstractUrlBasedTicketValidator.java | 18 ++++++- .../cas/client/validation/Assertion.java | 8 +-- .../cas/client/validation/AssertionImpl.java | 46 ++++++++++++++--- .../validation/Cas10TicketValidator.java | 2 +- .../validation/Cas20ProxyTicketValidator.java | 41 +++++++--------- .../Cas20ServiceTicketValidator.java | 49 ++++++++++++------- .../client/validation/AssertionImplTests.java | 7 ++- .../Cas20ProxyTicketValidatorTests.java | 17 ++++++- .../Cas20ServiceTicketValidatorTests.java | 25 ++++++++-- 9 files changed, 150 insertions(+), 63 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index 551809e..2dff518 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -26,7 +26,7 @@ public abstract class AbstractUrlBasedTicketValidator implements protected final Log log = LogFactory.getLog(this.getClass()); /** - * Url to CAS server. + * Url to CAS server. Generally of the form https://server:port/cas/ */ private final String casServerUrl; @@ -36,7 +36,7 @@ public abstract class AbstractUrlBasedTicketValidator implements private final boolean renew; /** - * Instance of HttpClient for connecting to server. + * Instance of HttpClient for connecting to server. Care should be taken only inject a multi-threaded HttpClient. */ private final HttpClient httpClient; @@ -48,9 +48,23 @@ public abstract class AbstractUrlBasedTicketValidator implements return parseResponse(response); } + /** + * Constructs the URL endpoint for contacting CAS for ticket validation. + * + * @param ticketId the opaque ticket id. + * @param service the service we are validating for. + * @return the fully constructed url. + */ protected abstract String constructURL(final String ticketId, final Service service); + /** + * Parses the response retrieved from the url endpoint. + * + * @param response the String response. + * @return an Assertion based on the response. + * @throws ValidationException if there was an error validating the ticket. + */ protected abstract Assertion parseResponse(final String response) throws ValidationException; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java index 5ae3714..a751be5 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Assertion.java @@ -6,6 +6,7 @@ package org.jasig.cas.client.validation; import org.jasig.cas.authentication.principal.Principal; +import org.jasig.cas.authentication.principal.Service; import java.io.Serializable; import java.util.Map; @@ -36,9 +37,10 @@ public interface Assertion extends Serializable { Map getAttributes(); /** - * Method to retrieve the proxyGrantingTicket Id. + * Retrieves a proxy ticket for the specific service. * - * @return the ProxyGrantingTicket Id if one exists, otherwise null. + * @param service The service to proxy to. + * @return the Proxy Ticket Id or null. */ - String getProxyGrantingTicketId(); + String getProxyTicketFor(Service service); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java index d497135..a305a7c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java @@ -6,6 +6,8 @@ package org.jasig.cas.client.validation; import org.jasig.cas.authentication.principal.Principal; +import org.jasig.cas.authentication.principal.Service; +import org.jasig.cas.client.proxy.ProxyRetriever; import org.jasig.cas.client.util.CommonUtils; import java.util.HashMap; @@ -41,29 +43,61 @@ public class AssertionImpl implements Assertion { */ private final String proxyGrantingTicketId; + /** + * Reference to ProxyRetriever so that clients can retrieve proxy tickets for a service. + */ + private final ProxyRetriever proxyRetriever; + + + /** + * Simple constructor that accepts a Principal. + * + * @param principal the Principal this assertion is for. + */ public AssertionImpl(final Principal principal) { - this(principal, null, null); + this(principal, null, null, null); } + /** + * Constructor that accepts a Principal and a map of attributes. + * + * @param principal the Principal this assertion is for. + * @param attributes a map of attributes about the principal. + */ + public AssertionImpl(final Principal principal, final Map attributes) { + this(principal, attributes, null, null); + } + + /** + * @param principal the Principal this assertion is for. + * @param attributes a map of attributes about the principal. + * @param proxyRetriever used to retrieve proxy tickets from CAS Server. + * @param proxyGrantingTicketId the Id to use to request proxy tickets. + */ public AssertionImpl(final Principal principal, final Map attributes, - final String proxyGrantingTicketId) { + final ProxyRetriever proxyRetriever, final String proxyGrantingTicketId) { CommonUtils.assertNotNull(principal, "principal cannot be null"); this.principal = principal; this.attributes = attributes == null ? new HashMap() : attributes; this.proxyGrantingTicketId = CommonUtils .isNotEmpty(proxyGrantingTicketId) ? proxyGrantingTicketId : null; + this.proxyRetriever = proxyRetriever; } public final Map getAttributes() { return this.attributes; } + public String getProxyTicketFor(final Service service) { + if (proxyRetriever == null || proxyGrantingTicketId == null) { + return null; + } + + return this.proxyRetriever.getProxyTicketIdFor(this.proxyGrantingTicketId, service); + } + public final Principal getPrincipal() { return this.principal; } - - public final String getProxyGrantingTicketId() { - return this.proxyGrantingTicketId; - } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java index f639ac2..43d2053 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidator.java @@ -47,7 +47,7 @@ public final class Cas10TicketValidator extends AbstractUrlBasedTicketValidator reader.readLine(); final Principal principal = new SimplePrincipal(reader.readLine()); - return new AssertionImpl(principal); + return new AssertionImpl(principal, null); } catch (final IOException e) { throw new ValidationException("Unable to parse response.", e); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java index 5c579ef..2c86e82 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java @@ -9,6 +9,7 @@ import org.apache.commons.httpclient.HttpClient; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.authentication.principal.SimpleService; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.proxy.ProxyRetriever; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; @@ -41,19 +42,18 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator { private final boolean acceptAnyProxy; /** - * @param casServerUrl the url to the CAS server, minus the endpoint. - * @param renew flag for whether we require authentication to be via an initial authentication. - * @param httpClient an instance of HttpClient to do the calls. - * @param proxyGrantingTicketStorage a reference to the storage of the proxy tickets. - * @param proxyChains the chains of proxy lists that we accept tickets from. - * @param acceptAnyProxy flag on whether we accept any proxy or not. + * @param casServerUrl the url to the CAS server, minus the endpoint. + * @param renew flag for whether we require authentication to be via an initial authentication. + * @param httpClient an instance of HttpClient to do the calls. + * @param proxyChains the chains of proxy lists that we accept tickets from. + * @param acceptAnyProxy flag on whether we accept any proxy or not. */ - public Cas20ProxyTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final ProxyGrantingTicketStorage proxyGrantingTicketStorage, List proxyChains, boolean acceptAnyProxy) { - this(casServerUrl, renew, httpClient, null, proxyGrantingTicketStorage, proxyChains, acceptAnyProxy); + public Cas20ProxyTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, List proxyChains, boolean acceptAnyProxy) { + this(casServerUrl, renew, httpClient, null, proxyChains, acceptAnyProxy, null, null); } - public Cas20ProxyTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final Service proxyCallbackUrl, final ProxyGrantingTicketStorage proxyGrantingTicketStorage, List proxyChains, boolean acceptAnyProxy) { - super(casServerUrl, renew, httpClient, proxyCallbackUrl, proxyGrantingTicketStorage); + public Cas20ProxyTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final Service proxyCallbackUrl, List proxyChains, boolean acceptAnyProxy, final ProxyGrantingTicketStorage proxyGrantingTicketStorage, final ProxyRetriever proxyRetriever) { + super(casServerUrl, renew, httpClient, proxyCallbackUrl, proxyGrantingTicketStorage, proxyRetriever); CommonUtils.assertTrue(proxyChains != null || acceptAnyProxy, "proxyChains cannot be null or acceptAnyProxy must be true."); @@ -83,34 +83,27 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator { return "proxyValidate"; } - protected Assertion getValidAssertionInternal(final String response, - final Assertion assertion) throws ValidationException { + + protected Assertion getValidAssertionInternal(final String response, final String principal, final String proxyGrantingTicketIou) throws ValidationException { final List proxies = XmlUtils.getTextForElements(response, "proxy"); - final Service[] principals = new Service[proxies.size()]; // this means there was nothing in the proxy chain, which is okay - if (principals.length == 0 || this.acceptAnyProxy) { - return assertion; + if (proxies.isEmpty() || this.acceptAnyProxy) { + return getAssertionBasedOnProxyGrantingTicketIou(proxyGrantingTicketIou, principal); } + final Service[] principals = new Service[proxies.size()]; int i = 0; for (final Iterator iter = proxies.iterator(); iter.hasNext();) { principals[i++] = new SimpleService((String) iter.next()); } - boolean found = false; for (Iterator iter = this.proxyChains.iterator(); iter.hasNext();) { if (Arrays.equals(principals, (Object[]) iter.next())) { - found = true; - break; + return getAssertionBasedOnProxyGrantingTicketIou(proxyGrantingTicketIou, principal); } } - if (!found) { - throw new InvalidProxyChainValidationException(); - } - - return new AssertionImpl(assertion.getPrincipal(), assertion - .getAttributes(), assertion.getProxyGrantingTicketId()); + throw new InvalidProxyChainValidationException(); } } 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 0f6a2ea..adb6166 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 @@ -9,6 +9,7 @@ import org.apache.commons.httpclient.HttpClient; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.authentication.principal.SimplePrincipal; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.proxy.ProxyRetriever; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; @@ -33,16 +34,26 @@ public class Cas20ServiceTicketValidator extends */ private final ProxyGrantingTicketStorage proxyGrantingTicketStorage; - public Cas20ServiceTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final ProxyGrantingTicketStorage proxyGrantingTicketStorage) { - this(casServerUrl, renew, httpClient, null, proxyGrantingTicketStorage); + /** + * Injected into Assertions to allow them to retrieve proxy tickets. + */ + private final ProxyRetriever proxyRetriever; + + public Cas20ServiceTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient) { + this(casServerUrl, renew, httpClient, null, null, null); } - public Cas20ServiceTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final Service proxyCallbackUrl, final ProxyGrantingTicketStorage proxyGrantingTicketStorage) { + public Cas20ServiceTicketValidator(final String casServerUrl, final boolean renew, final HttpClient httpClient, final Service proxyCallbackUrl, final ProxyGrantingTicketStorage proxyGrantingTicketStorage, final ProxyRetriever proxyRetriever) { super(casServerUrl, renew, httpClient); - CommonUtils.assertNotNull(proxyGrantingTicketStorage, - "proxyGrantingTicketStorage cannot be null"); + + if (proxyCallbackUrl != null) { + CommonUtils.assertNotNull(proxyGrantingTicketStorage, + "proxyGrantingTicketStorage cannot be null"); + CommonUtils.assertNotNull(proxyRetriever, "proxyRetriever cannot be null."); + } this.proxyCallbackUrl = proxyCallbackUrl; this.proxyGrantingTicketStorage = proxyGrantingTicketStorage; + this.proxyRetriever = proxyRetriever; } protected String constructURL(final String ticketId, @@ -58,8 +69,9 @@ public class Cas20ServiceTicketValidator extends + getEncodedService(this.proxyCallbackUrl) : ""); } - protected final Assertion parseResponse(String response) + protected final Assertion parseResponse(final String response) throws ValidationException { + final String error = XmlUtils.getTextForElement(response, "authenticationFailure"); @@ -76,23 +88,24 @@ public class Cas20ServiceTicketValidator extends throw new ValidationException("No principal found."); } - if (CommonUtils.isNotBlank(proxyGrantingTicketIou)) { - return getValidAssertionInternal(response, new AssertionImpl( - new SimplePrincipal(principal), null, - this.proxyGrantingTicketStorage - .retrieve(proxyGrantingTicketIou))); - } - - return getValidAssertionInternal(response, new AssertionImpl( - new SimplePrincipal(principal))); + return getValidAssertionInternal(response, principal, proxyGrantingTicketIou); } protected String getValidationUrlName() { return "serviceValidate"; } - protected Assertion getValidAssertionInternal(final String response, - final Assertion assertion) throws ValidationException { - return assertion; + protected final Assertion getAssertionBasedOnProxyGrantingTicketIou(final String proxyGrantingTicketIou, final String principal) { + if (CommonUtils.isNotBlank(proxyGrantingTicketIou)) { + return new AssertionImpl( + new SimplePrincipal(principal), null, this.proxyRetriever, this.proxyGrantingTicketStorage == null ? null : this.proxyGrantingTicketStorage + .retrieve(proxyGrantingTicketIou)); + } else { + return new AssertionImpl(new SimplePrincipal(principal)); + } + } + + protected Assertion getValidAssertionInternal(final String response, final String principal, final String proxyGrantingTicketIou) throws ValidationException { + return getAssertionBasedOnProxyGrantingTicketIou(proxyGrantingTicketIou, principal); } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java index 87fe070..91cd5c8 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java @@ -8,6 +8,7 @@ package org.jasig.cas.client.validation; import junit.framework.TestCase; import org.jasig.cas.authentication.principal.Principal; import org.jasig.cas.authentication.principal.SimplePrincipal; +import org.jasig.cas.authentication.principal.SimpleService; import java.util.HashMap; import java.util.Map; @@ -36,16 +37,14 @@ public final class AssertionImplTests extends TestCase { assertEquals(CONST_PRINCIPAL, assertion.getPrincipal()); assertTrue(assertion.getAttributes().isEmpty()); - assertNull(assertion.getProxyGrantingTicketId()); + assertNull(assertion.getProxyTicketFor(new SimpleService("test"))); } public void testCompleteConstructor() { final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, - CONST_ATTRIBUTES, CONST_PROXY_GRANTING_TICKET_IOU); + CONST_ATTRIBUTES); assertEquals(CONST_PRINCIPAL, assertion.getPrincipal()); assertEquals(CONST_ATTRIBUTES, assertion.getAttributes()); - assertEquals(CONST_PROXY_GRANTING_TICKET_IOU, assertion - .getProxyGrantingTicketId()); } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java index 92f554a..58ada81 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java @@ -7,10 +7,12 @@ package org.jasig.cas.client.validation; import org.apache.commons.httpclient.HttpClient; +import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.authentication.principal.SimpleService; import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; +import org.jasig.cas.client.proxy.ProxyRetriever; import java.io.UnsupportedEncodingException; import java.util.ArrayList; @@ -37,15 +39,26 @@ public final class Cas20ProxyTicketValidatorTests extends final List list = new ArrayList(); list.add("proxy1 proxy2 proxy3"); - this.ticketValidator = new Cas20ProxyTicketValidator(CONST_CAS_SERVER_URL, true, new HttpClient(), proxyGrantingTicketStorage, list, false); + this.ticketValidator = new Cas20ProxyTicketValidator(CONST_CAS_SERVER_URL, true, new HttpClient(), new SimpleService("test"), list, false, getProxyGrantingTicketStorage(), getProxyRetriever()); } private ProxyGrantingTicketStorage getProxyGrantingTicketStorage() { - ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl(); + final ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl(); return proxyGrantingTicketStorageImpl; } + private ProxyRetriever getProxyRetriever() { + final ProxyRetriever proxyRetriever = new ProxyRetriever() { + + public String getProxyTicketIdFor(String proxyGrantingTicketId, Service targetService) { + return "test"; + } + }; + + return proxyRetriever; + } + public void testProxyChainWithValidProxy() throws ValidationException, UnsupportedEncodingException { final String USERNAME = "username"; 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 efd6044..721f115 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 @@ -7,10 +7,12 @@ package org.jasig.cas.client.validation; import org.apache.commons.httpclient.HttpClient; +import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.authentication.principal.SimpleService; import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; +import org.jasig.cas.client.proxy.ProxyRetriever; import java.io.UnsupportedEncodingException; @@ -28,21 +30,38 @@ public final class Cas20ServiceTicketValidatorTests extends private ProxyGrantingTicketStorage proxyGrantingTicketStorage; + private ProxyRetriever proxyRetriever; + public Cas20ServiceTicketValidatorTests() { super(); } + public Cas20ServiceTicketValidatorTests(Cas20ServiceTicketValidator ticketValidator) { + this.ticketValidator = ticketValidator; + } + protected void setUp() throws Exception { this.proxyGrantingTicketStorage = getProxyGrantingTicketStorage(); - this.ticketValidator = new Cas20ServiceTicketValidator(CONST_CAS_SERVER_URL, true, new HttpClient(), this.proxyGrantingTicketStorage); + this.ticketValidator = new Cas20ServiceTicketValidator(CONST_CAS_SERVER_URL, true, new HttpClient(), new SimpleService("test"), this.proxyGrantingTicketStorage, getProxyRetriever()); } private ProxyGrantingTicketStorage getProxyGrantingTicketStorage() { - ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl(); + final ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl = new ProxyGrantingTicketStorageImpl(); return proxyGrantingTicketStorageImpl; } + private ProxyRetriever getProxyRetriever() { + final ProxyRetriever proxyRetriever = new ProxyRetriever() { + + public String getProxyTicketIdFor(String proxyGrantingTicketId, Service targetService) { + return "test"; + } + }; + + return proxyRetriever; + } + public void testNoResponse() throws UnsupportedEncodingException { final String RESPONSE = "Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized"; PublicTestHttpServer.instance().content = RESPONSE @@ -88,7 +107,7 @@ public final class Cas20ServiceTicketValidatorTests extends final Assertion assertion = this.ticketValidator.validate("test", new SimpleService("test")); assertEquals(USERNAME, assertion.getPrincipal().getId()); - assertEquals(PGT, assertion.getProxyGrantingTicketId()); +// assertEquals(PGT, assertion.getProxyGrantingTicketId()); } public void testInvalidResponse() throws Exception {