diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index 4034b47..886c460 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -8,6 +8,8 @@ package org.jasig.cas.client.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.validation.ProxyList; +import org.jasig.cas.client.validation.ProxyListEditor; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -338,4 +340,14 @@ public final class CommonUtils { throw new IllegalArgumentException(e); } } + + public static ProxyList createProxyList(final String proxies) { + if (CommonUtils.isBlank(proxies)) { + return new ProxyList(); + } + + final ProxyListEditor editor = new ProxyListEditor(); + editor.setAsText(proxies); + return (ProxyList) editor.getValue(); + } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index 3fbb431..9582111 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -102,7 +102,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) { final Cas20ProxyTicketValidator v = new Cas20ProxyTicketValidator(casServerUrlPrefix); v.setAcceptAnyProxy(parseBoolean(allowAnyProxy)); - v.setAllowedProxyChains(createProxyList(allowedProxyChains)); + v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains)); validator = v; } else { validator = new Cas20ServiceTicketValidator(casServerUrlPrefix); @@ -130,16 +130,6 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal return validator; } - protected final ProxyList createProxyList(final String proxies) { - if (CommonUtils.isBlank(proxies)) { - return new ProxyList(); - } - - final ProxyListEditor editor = new ProxyListEditor(); - editor.setAsText(proxies); - return (ProxyList) editor.getValue(); - } - public void destroy() { super.destroy(); this.timer.cancel(); diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java new file mode 100644 index 0000000..23e9d36 --- /dev/null +++ b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java @@ -0,0 +1,104 @@ +package org.jasig.cas.client.tomcat; + +import org.apache.catalina.authenticator.AuthenticatorBase; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jasig.cas.client.util.AbstractCasFilter; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.validation.Assertion; +import org.jasig.cas.client.validation.TicketValidationException; +import org.jasig.cas.client.validation.TicketValidator; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; + +/** + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public abstract class AbstractAuthenticator extends AuthenticatorBase { + + private static final String INFO = "org.jasig.cas.client.tomcat.AbstractAuthenticator/1.0"; + + private static final Log log = LogFactory.getLog(AbstractAuthenticator.class); + + private String casServerLoginUrl; + + private String casServerUrlPrefix; + + private boolean encode; + + private boolean renew; + + protected abstract String getArtifactParameterName(); + + protected abstract String getServiceParameterName(); + + protected abstract TicketValidator getTicketValidator(); + + private String serverName; + + private String serviceUrl; + + protected final String getCasServerUrlPrefix() { + return this.casServerUrlPrefix; + } + + public String getInfo() { + return INFO; + } + + public final boolean authenticate(final Request request, final HttpServletResponse response, final LoginConfig loginConfig) throws IOException { + final Assertion assertion = (Assertion) request.getSession(true).getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); + + if (assertion != null) { + return isKnownUser(assertion, request, response); + } + + final String token = request.getParameter(getArtifactParameterName()); + final String service = CommonUtils.constructServiceUrl(request, response, this.serviceUrl, this.serverName, getArtifactParameterName(), true); + + if (CommonUtils.isBlank(token)) { + final String redirectUrl = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), service, false, false); + response.sendRedirect(redirectUrl); + return false; + } + + try { + final Assertion newAssertion = getTicketValidator().validate(token, service); + request.getSession(true).setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, newAssertion); + return isKnownUser(newAssertion, request, response); + } catch (final TicketValidationException e) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); + return false; + } + } + + protected boolean isKnownUser(final Assertion assertion, final Request request, final HttpServletResponse response) throws IOException { + final String userName = assertion.getPrincipal().getName(); + final Principal principal = request.getUserPrincipal(); + + if (principal == null) { + // principal not already known; look it up via the configured realm + principal = realm.getPrincipal(userName); + if (principal != null) { + // register it so that Tomcat can reuse it without another realm lookup + register(request, response, principal, "CAS", userName, null); + } + } + + if (principal == null) { + log.warn("unknown CAS user " + userName + " for " + + request.getRequestURI()); + response.sendError(Response.SC_UNAUTHORIZED); + return false; + } + request.setUserPrincipal(principal); + return true; + } +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractCasAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractCasAuthenticator.java new file mode 100644 index 0000000..d497d65 --- /dev/null +++ b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractCasAuthenticator.java @@ -0,0 +1,49 @@ +package org.jasig.cas.client.tomcat; + +/** + * + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public abstract class AbstractCasAuthenticator extends AbstractAuthenticator { + + private String encoding; + + private String proxyCallbackUrl; + + private boolean renew; + + protected final String getEncoding() { + return this.encoding; + } + + public final void setEncoding(final String encoding) { + this.encoding = encoding; + } + + protected final String getProxyCallbackUrl() { + return this.proxyCallbackUrl; + } + + public final void setProxyCallbackUrl(final String proxyCallbackUrl) { + this.proxyCallbackUrl = proxyCallbackUrl; + } + + protected final boolean isRenew() { + return this.renew; + } + + public void setRenew(final boolean renew) { + this.renew = renew; + } + + protected final String getArtifactParameterName() { + return "ticket"; + } + + protected final String getServiceParameterName() { + return "Service"; + } +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java new file mode 100644 index 0000000..b11cdab --- /dev/null +++ b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java @@ -0,0 +1,27 @@ +package org.jasig.cas.client.tomcat; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Cas10TicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * Authenticator that handles CAS 1.0 responses. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public class Cas10CasAuthenticator extends AbstractCasAuthenticator { + + private TicketValidator ticketValidator; + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + + this.ticketValidator = new Cas10TicketValidator(getCasServerUrlPrefix()); + } +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java new file mode 100644 index 0000000..f08b105 --- /dev/null +++ b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java @@ -0,0 +1,32 @@ +package org.jasig.cas.client.tomcat; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * Authenticator that handles the CAS 2 protocol. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class Cas20CasAuthenticator extends AbstractCasAuthenticator { + + private Cas20ServiceTicketValidator ticketValidator; + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Cas20ServiceTicketValidator(getCasServerUrlPrefix()); + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl()); + this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage()); + this.ticketValidator.setRenew(isRenew()); + } +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java new file mode 100644 index 0000000..faa8cf8 --- /dev/null +++ b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java @@ -0,0 +1,46 @@ +package org.jasig.cas.client.tomcat; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.validation.Cas20ProxyTicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class Cas20ProxyCasAuthenticator extends AbstractCasAuthenticator { + + private Cas20ProxyTicketValidator ticketValidator; + + private boolean acceptAnyProxy; + + private String allowedProxyChains; + + public void setAcceptAnyProxy(final boolean acceptAnyProxy) { + this.acceptAnyProxy = acceptAnyProxy; + } + + public void setAllowedProxyChains(final String allowedProxyChains) { + this.allowedProxyChains = allowedProxyChains; + } + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + + this.ticketValidator = new Cas20ProxyTicketValidator(getCasServerUrlPrefix()); + this.ticketValidator.setRenew(isRenew()); + this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl()); + this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage()); + this.ticketValidator.setAcceptAnyProxy(this.acceptAnyProxy); + this.ticketValidator.setAllowedProxyChains(CommonUtils.createProxyList(this.allowedProxyChains)); + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + } +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasAuthenticator.java deleted file mode 100644 index 952060e..0000000 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasAuthenticator.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.jasig.cas.client.tomcat; - -import org.apache.catalina.authenticator.AuthenticatorBase; -import org.apache.catalina.connector.Request; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jasig.cas.client.util.AbstractCasFilter; -import org.jasig.cas.client.util.CommonUtils; -import org.jasig.cas.client.validation.Assertion; -import org.jasig.cas.client.validation.TicketValidationException; -import org.jasig.cas.client.validation.TicketValidator; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.security.Principal; - -/** - * @author Scott Battaglia - * @version $Revision$ $Date$ - * @since 3.1.12 - */ -public abstract class CasAuthenticator extends AuthenticatorBase { - - private static final String INFO = "org.jasig.cas.client.tomcat.CasAuthenticator/1.0"; - - private static final Log log = LogFactory.getLog(CasAuthenticator.class); - - private String serverName; - - private String serviceUrl; - - private String casServerLoginUrl; - - private boolean encode; - - private boolean renew; - - protected abstract String getArtifactParameterName(); - - protected abstract String getServiceParameterName(); - - private TicketValidator ticketValidator; - - public String getInfo() { - return INFO; - } - - public boolean authenticate(final Request request, final HttpServletResponse httpServletResponse, final LoginConfig loginConfig) throws IOException { - final Assertion assertion = (Assertion) request.getSession(true).getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); - - if (assertion != null) { - return isKnownUser(assertion); - } - - - - - return false; //To change body of implemented methods use File | Settings | File Templates. - } - - protected boolean isKnownUser(final Assertion assertion) { - return true; - } - - protected boolean isAuthenticatedRequest(final HttpServletRequest request, final HttpServletResponse response) throws IOException { - final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName()); - final String serviceUrl = CommonUtils.constructServiceUrl(request, response, this.serviceUrl, this.serverName, getArtifactParameterName(), this.encode); - - if (CommonUtils.isBlank(ticket)) { - final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), serviceUrl, this.renew, false); - response.sendRedirect(urlToRedirectTo); - return false; - } - - try { - final Assertion assertion = this.ticketValidator.validate(ticket, serviceUrl); - request.getSession(true).setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion); - return isKnownUser(assertion); - } catch (final TicketValidationException e) { - return false; - } - - } - - -} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java deleted file mode 100644 index 4efc18a..0000000 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.jasig.cas.client.tomcat; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Realm; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.SecurityConstraint; - -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.security.Principal; -import java.security.cert.X509Certificate; - -/** - * Created by IntelliJ IDEA. - * User: scottbattaglia - * Date: Jul 19, 2010 - * Time: 11:11:28 PM - * To change this template use File | Settings | File Templates. - */ -public class CasRealm implements Realm { - - // <description>/<version> - - private static final String INFO = "org.jasig.cas.client.tomcat.CasRealm/1.0"; - - private Container container; - - public Container getContainer() { - return this.container; - } - - public void setContainer(final Container container) { - this.container = container; - } - - public String getInfo() { - return INFO; - } - - public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) { - //To change body of implemented methods use File | Settings | File Templates. - } - - public Principal authenticate(String s, String s1) { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public Principal authenticate(String s, String s1, String s2, String s3, String s4, String s5, String s6, String s7) { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public Principal authenticate(X509Certificate[] x509Certificates) { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public void backgroundProcess() { - //To change body of implemented methods use File | Settings | File Templates. - } - - public SecurityConstraint[] findSecurityConstraints(Request request, Context context) { - return new SecurityConstraint[0]; //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean hasResourcePermission(Request request, Response response, SecurityConstraint[] securityConstraints, Context context) throws IOException { - return false; //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean hasRole(Principal principal, String s) { - return false; //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean hasUserDataPermission(Request request, Response response, SecurityConstraint[] securityConstraints) throws IOException { - return false; //To change body of implemented methods use File | Settings | File Templates. - } - - public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) { - //To change body of implemented methods use File | Settings | File Templates. - } -}