scripts.cas-auth.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zap-utils Show documentation
Show all versions of zap-utils Show documentation
Utils module responsible for ZAP automatic initialization
/*
* This script is intended to handle CAS (http://jasig.github.io/cas) authentication via ZAP.
*
* When working with CAS, a single POST request with the credentials is not enough to trigger the authentication.
* When we GET the login page, some input values used by CAS are generated (the login ticket and some Spring Web
* Flow related parameters), and they must be included in the POST request for the authentication to work. So
* this script basically sends a GET to the login page, parses its response looking for the values generated by
* CAS, and sends a POST request with these values and the credentials.
*
* This is enough to trigger the authentication, but it's not enough to enable a successfull authenticated scan
* with ZAP. There is one more step needed because of redirects: CAS loves them and ZAP doesn't. More details on
* that can be found in the comments within the script.
*
* Reauthentication works and a good way to achieve it is with a Logged Out Regex as something like:
* \QLocation: http://your.domain/cas-server/\E.*
* Unauthenticated responses will be 302 redirects to the CAS server, so this is the easiest way to identify that
* there was a redirect to the CAS server and thus the user is not logged in.
*
* @author Thiago Porciúncula
* @author Hugo Baes
* @author Fábio Resner
*/
function authenticate(helper, paramsValues, credentials) {
print("---- CAS authentication script has started ----");
// Enable Rhino behavior, in case ZAP is running on Java 8 (which uses Nashorn)
if (java.lang.System.getProperty("java.version").startsWith("1.8")) {
load("nashorn:mozilla_compat.js");
}
// Imports
importClass(org.parosproxy.paros.network.HttpRequestHeader)
importClass(org.parosproxy.paros.network.HttpHeader)
importClass(org.apache.commons.httpclient.URI)
importClass(org.apache.commons.httpclient.params.HttpClientParams)
importClass(java.util.regex.Pattern)
var loginUri = new URI(paramsValues.get("loginUrl"), false);
// Perform a GET request to the login page to get the values generated by CAS on the response (login ticket, event id, etc)
var get = helper.prepareMessage();
get.setRequestHeader(new HttpRequestHeader(HttpRequestHeader.GET, loginUri, HttpHeader.HTTP10));
helper.sendAndReceive(get);
var casInputValues = getCASInputValues(get.getResponseBody().toString());
// Build the request body using the credentials values and the CAS values obtained from the first request
requestBody = "username=" + encodeURIComponent(credentials.getParam("username"));
requestBody += "&password=" + encodeURIComponent(credentials.getParam("password"));
requestBody += "<=" + encodeURIComponent(casInputValues["lt"]);
requestBody += "&execution=" + encodeURIComponent(casInputValues["execution"]);
requestBody += "&_eventId=" + encodeURIComponent(casInputValues["_eventId"]);
// Add any extra post data provided
extraPostData = paramsValues.get("extraPostData");
if (extraPostData != null && !extraPostData.trim().isEmpty()) {
requestBody += "&" + extraPostData.trim();
}
// Perform a POST request to authenticate
print("POST request body built for the authentication:\n " + requestBody.replaceAll("&", "\n "));
var post = helper.prepareMessage();
post.setRequestHeader(new HttpRequestHeader(HttpRequestHeader.POST, loginUri, HttpHeader.HTTP10));
post.setRequestBody(requestBody);
helper.sendAndReceive(post);
/*
* At this point we are authenticated, but we are not done yet :(
*
* We have authenticated on the CAS server (let's say http://mydomain/cas-server), so when we access
* the app (i.e. http://mydomain/my-app) for the first time, we will be redirected to the CAS server.
* Since we are authenticated, the CAS server will redirect us back to the app:
*
* http://your.domain/your-app -> http://your.domain/cas-server -> http://your.domain/your-app
*
* There are two problems here: the first is that ZAP's Spider explicitly doesn't follow redirects.
* So if the Spider access the app, it will get a redirect response and the page will never really
* be spidered. However, this redirect happens only at the first time we access the app after the
* authentication, so we could just access the app once before ZAP's Spider starts, right? Almost.
* This is a circular redirect, and the second problem is that ZAP doesn't support it. So, this
* strategy works, but we need a bit of code to get us through this.
*
* This script has another parameter that should hold at least one protected page for each app that
* might be analyzed. We then proceed to enable circular redirect for ZAP (reflection to the rescue!)
* and do a simple GET for each page, ensuring no redirects will happen during our analysis.
*/
// Get the protected pages
var protectedPagesSeparatedByComma = paramsValues.get("protectedPages");
var protectedPages = protectedPagesSeparatedByComma.split(",");
// Enable circular redirect
var client = getHttpClientFromHelper(helper);
client.getParams().setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true);
// Perform a GET request on the protected pages to avoid redirects during the scan
for (index in protectedPages) {
var request = helper.prepareMessage();
request.setRequestHeader(new HttpRequestHeader(HttpRequestHeader.GET, new URI(protectedPages[index], false), HttpHeader.HTTP10));
helper.sendAndReceive(request, true);
}
// Disable circular redirect
client.getParams().setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, false);
print("---- CAS authentication script has finished ----\n");
return post;
}
function getCASInputValues(response){
var result = {};
var regex = "
© 2015 - 2024 Weber Informatics LLC | Privacy Policy