Support casServerUrlPrefix config option

`casServerUrlPrefix` is used for validation and single logout,
but before this commit it couldn't be used by the auth filter.
As a result, web.xml needed to (for the typical usecase)
contain at least two references to the cas server.

Now, only one context init-param reference is necessary,
as long as the login page is hosted at {prefix}/login
(which seems to be mandated by cas protocol spec).
This commit is contained in:
Matt Drees 2018-07-24 14:25:02 -06:00
parent 93561a297f
commit b6f6b5de76
5 changed files with 57 additions and 13 deletions

View File

@ -176,8 +176,8 @@ The `AuthenticationFilter` is what detects whether a user needs to be authentica
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://battags.ad.ess.rutgers.edu:8443/cas/login</param-value>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://battags.ad.ess.rutgers.edu:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
@ -192,7 +192,8 @@ The `AuthenticationFilter` is what detects whether a user needs to be authentica
| Property | Description | Required
|----------|-------|-----------
| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login` | Yes
| `casServerUrlPrefix` | The start of the CAS server URL, i.e. `https://localhost:8443/cas` | Yes (unless `casServerLoginUrl` is set)
| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login`. This overrides `casServerUrlPrefix`, if set. | Yes (unless `casServerUrlPrefix` is set)
| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. https://localhost:8443 (you must include the protocol, but port is optional if it's a standard port). | Yes
| `service` | The service URL to send to the CAS server, i.e. `https://localhost:8443/yourwebapp/index.html` | No
| `renew` | specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No
@ -230,7 +231,8 @@ The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be a
| Property | Description | Required
|----------|-------|-----------
| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login` | Yes
| `casServerUrlPrefix` | The start of the CAS server URL, i.e. `https://localhost:8443/cas` | Yes (unless `casServerLoginUrl` is set)
| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login`. This overrides `casServerUrlPrefix`, if set. | Yes (unless `casServerUrlPrefix` is set)
| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. https://localhost:8443 (you must include the protocol, but port is optional if it's a standard port). | Yes
| `service` | The service URL to send to the CAS server, i.e. `https://localhost:8443/yourwebapp/index.html` | No
| `renew` | specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No

View File

@ -93,7 +93,14 @@ public class AuthenticationFilter extends AbstractCasFilter {
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
if (!isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL));
String loginUrl = getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL);
if (loginUrl != null) {
setCasServerLoginUrl(loginUrl);
} else {
setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
}
setRenew(getBoolean(ConfigurationKeys.RENEW));
setGateway(getBoolean(ConfigurationKeys.GATEWAY));
@ -133,7 +140,13 @@ public class AuthenticationFilter extends AbstractCasFilter {
public void init() {
super.init();
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
String message = String.format(
"one of %s and %s must not be null.",
ConfigurationKeys.CAS_SERVER_LOGIN_URL.getName(),
ConfigurationKeys.CAS_SERVER_URL_PREFIX.getName());
CommonUtils.assertNotNull(this.casServerLoginUrl, message);
}
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
@ -192,6 +205,10 @@ public class AuthenticationFilter extends AbstractCasFilter {
this.gateway = gateway;
}
public final void setCasServerUrlPrefix(final String casServerUrlPrefix) {
setCasServerLoginUrl(CommonUtils.addTrailingSlash(casServerUrlPrefix) + "login");
}
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}

View File

@ -719,4 +719,13 @@ public final class CommonUtils {
}
}
/**
* Adds a trailing slash to the given uri, if it doesn't already have one.
*
* @param uri a string that may or may not end with a slash
* @return the same string, except with a slash suffix (if necessary).
*/
public static String addTrailingSlash(String uri) {
return uri.endsWith("/") ? uri : uri + "/";
}
}

View File

@ -71,8 +71,8 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
* @param casServerUrlPrefix the location of the CAS server.
*/
protected AbstractUrlBasedTicketValidator(final String casServerUrlPrefix) {
this.casServerUrlPrefix = casServerUrlPrefix;
CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
CommonUtils.assertNotNull(casServerUrlPrefix, "casServerUrlPrefix cannot be null.");
this.casServerUrlPrefix = CommonUtils.addTrailingSlash(casServerUrlPrefix);
}
/**
@ -124,9 +124,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator
int i = 0;
buffer.append(this.casServerUrlPrefix);
if (!this.casServerUrlPrefix.endsWith("/")) {
buffer.append("/");
}
buffer.append(suffix);
for (Map.Entry<String, String> entry : urlParameters.entrySet()) {

View File

@ -47,7 +47,8 @@ public final class AuthenticationFilterTests {
private static final String CAS_SERVICE_URL = "https://localhost:8443/service";
private static final String CAS_LOGIN_URL = "https://localhost:8443/cas/login";
private static final String CAS_PREFIX = "https://localhost:8443/cas";
private static final String CAS_LOGIN_URL = CAS_PREFIX + "/login";
private AuthenticationFilter filter;
@ -66,7 +67,25 @@ public final class AuthenticationFilterTests {
}
@Test
public void testRedirect() throws Exception {
public void testRedirectWithLoginUrlConfig() throws Exception {
doRedirectTest();
}
@Test
public void testRedirectWithCasServerPrefixConfig() throws Exception {
replaceFilterWithPrefixConfiguredFilter();
doRedirectTest();
}
private void replaceFilterWithPrefixConfiguredFilter() throws ServletException {
this.filter = new AuthenticationFilter();
final MockFilterConfig config = new MockFilterConfig();
config.addInitParameter("casServerUrlPrefix", CAS_PREFIX);
config.addInitParameter("service", CAS_SERVICE_URL);
this.filter.init(config);
}
private void doRedirectTest() throws IOException, ServletException {
final MockHttpSession session = new MockHttpSession();
final MockHttpServletRequest request = new MockHttpServletRequest();
final MockHttpServletResponse response = new MockHttpServletResponse();