Ensure ShibbolethRestController only redirects to trusted URLs

This commit is contained in:
Tim Donohue
2020-07-28 12:55:54 -05:00
parent 667a362b25
commit 441043587b
2 changed files with 36 additions and 5 deletions

View File

@@ -11,7 +11,9 @@ import java.io.IOException;
import java.util.Arrays;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.model.AuthnRest;
import org.dspace.core.Utils;
import org.dspace.services.ConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,8 +55,20 @@ public class ShibbolethRestController implements InitializingBean {
if (redirectUrl == null) {
redirectUrl = configurationService.getProperty("dspace.ui.url");
}
log.info("Redirecting to " + redirectUrl);
response.sendRedirect(redirectUrl);
// Validate that the redirectURL matches either the server or UI hostname. It *cannot* be an arbitrary URL.
String redirectHostName = Utils.getHostName(redirectUrl);
String serverHostName = Utils.getHostName(configurationService.getProperty("dspace.server.url"));
String clientHostName = Utils.getHostName(configurationService.getProperty("dspace.ui.url"));
if (StringUtils.equalsAnyIgnoreCase(redirectHostName, serverHostName, clientHostName)) {
log.debug("Shibboleth redirecting to " + redirectUrl);
response.sendRedirect(redirectUrl);
} else {
log.error("Invalid Shibboleth redirectURL=" + redirectUrl +
". URL doesn't match hostname of server or UI!");
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Invalid redirectURL! Must match server or ui hostname.");
}
}
}

View File

@@ -31,12 +31,29 @@ public class ShibbolethRestControllerIT extends AbstractControllerIntegrationTes
}
@Test
public void testRedirectToGivenUrl() throws Exception {
public void testRedirectToGivenTrustedUrl() throws Exception {
String token = getAuthToken(eperson.getEmail(), password);
getClient(token).perform(get("/api/authn/shibboleth")
.param("redirectUrl", "http://dspace.org"))
.param("redirectUrl", "http://localhost:8080/server/api/authn/status"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://dspace.org"));
.andExpect(redirectedUrl("http://localhost:8080/server/api/authn/status"));
}
@Test
public void testRedirectToGivenUntrustedUrl() throws Exception {
String token = getAuthToken(eperson.getEmail(), password);
// Now attempt to redirect to a URL that is NOT trusted (i.e. not the Server or UI).
// Should result in a 400 error.
getClient(token).perform(get("/api/authn/shibboleth")
.param("redirectUrl", "http://dspace.org"))
.andExpect(status().isBadRequest());
}
@Test
public void testRedirectRequiresAuth() throws Exception {
getClient().perform(get("/api/authn/shibboleth"))
.andExpect(status().isUnauthorized());
}
}