Forum Discussion

QWERTY's avatar
QWERTY
Occasional Contributor
14 years ago

Script for adding cookie to request header

Hi

A while ago I came across the problem with adding a cookie to a SoapUI (Pro) request to authenticate against a WSL protected server. I eventually solved the problem by writing a script that does it and now I want to share this with the community. The script comes in two flavours; lite and full, they both works fine although the full version has a lot more finesse. All directories given below is based on the SoapUI Pro 4.0.1 setup, if you have another setup you directory will differ.

Please note that these scripts only works with SoapUI Pro and the full script is only tested using SoapUI Pro 4.0.1

This post will deal with the lite version and the next post will deal with the full version.

Open the demo-listeners.xml in the C:\Program Files\SmartBear\soapUI-Pro-4.0.1\bin\listeners directory and paste the following:

<?xml version="1.0" encoding="UTF-8"?>
<tns:soapui-listeners xmlns:tns="http://eviware.com/soapui/config">

<!-- The below demo-listeners are described in the extensions overview at
http://www.soapui.org/architecture/extensions.html -->

<!-- This demo-listener is not reloadable -->
<!--
<tns:listener id="DemoListener" listenerClass="soapui.demo.DemoListener"
listenerInterface="com.eviware.soapui.model.testsuite.TestRunListener" />
-->

<!-- This demo-listener is reloadable -->

<tns:listener id="DemoListener"
listenerClass="com.eviware.soapui.support.scripting.listeners.ScriptTestRunListener"
groovyClass="soapui.demo.DemoListener"
listenerInterface="com.eviware.soapui.model.testsuite.TestRunListener"/>


<tns:listener id="DemoListener" listenerClass="com.eviware.soapui.support.scripting.listeners.ScriptRequestFilter"
groovyClass="soapui.demo.DemoRequestFilter" listenerInterface="com.eviware.soapui.impl.wsdl.submit.RequestFilter"/>

</tns:soapui-listeners>

This will set up a listener to the DemoRequestFilter class located in the DemoRequestFilter.groovy file in the C:\Program Files\SmartBear\soapUI-Pro-4.0.1\bin\scripts\soapui\demo directory. Now you have to modify this file to add cookies to request headers so open the file and paste the following:

package soapui.demo;

import com.eviware.soapui.impl.wsdl.submit.RequestFilter;
import com.eviware.soapui.model.iface.Request;
import com.eviware.soapui.model.iface.Response;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.support.types.StringToStringsMap
import com.eviware.soapui.SoapUI;

public class DemoRequestFilter implements RequestFilter {
@Override
public void afterRequest(SubmitContext arg0, Request arg1) {}

public void afterRequest(SubmitContext context, Response response) {}

@Override
public void filterRequest(SubmitContext context, Request wsdlRequest) {
SoapUI.log.info("****running demofilter******")

//The Header field in the SoapUI request header
String header = "Cookie"

//The type of cookie
String type = "type 1"
// "type 2"

//The WSL cookie. Paste the new cookie here and it will replace the old cookie or be added if the header is empty
String cookie = "My cookie"

def headers = new StringToStringsMap()
headers.put(header, type + cookie)
wsdlRequest.requestHeaders = headers
}
}

The indents disappeared but using a somewhat nifty text editor such as Notepad++ you can do it nice and clean. Now, some comments on the script:

*) After updating the listener you must restart SoapUI but the groovy file can be updated without restarting as SoapUI reloads it (check the log)
*) Paste your cookie where it sais "My cookie"
*) Some headers require a type before the value of the cookie, e.g. "WSL-external=", update the type with whatever string you want. If no type is needed just comment it out.
*) The put method takes to arguments: header and value. These corresponds to the two fields in the header tab in SoapUI. Change the header string if needed.
*) The script will create a new StringToString map object each time it's run effectively overwriting the previous header
*) requestHeaders is a property of the wsdlRequest object. It is the actual request being sent and is a StringToStringMap type

Next, the full version, a bit more complex
  • QWERTY's avatar
    QWERTY
    Occasional Contributor
    The full version of the script is a bit more complex. First, you have to add a new listener to the listeners folder: cookie-listeners.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <tns:soapui-listeners xmlns:tns="http://eviware.com/soapui/config">
    <tns:listener id="CookieListener"
    listenerClass="com.eviware.soapui.support.scripting.listeners.ScriptRequestFilter"
    groovyClass="soapui.cookie.Cookie"
    listenerInterface="com.eviware.soapui.impl.wsdl.submit.RequestFilter"/>
    </tns:soapui-listeners>

    I never got this to work in conjunction with the demo-listeners.xml so remove that one. Now you have to create a new folder called cookie like this: C:\Program Files\SmartBear\soapUI-Pro-4.0.1\bin\scripts\soapui\cookie
    As you can see it's on the same level as the demo folder.
    Next, in that folder, create Cookie.groovy and paste the following:

    package soapui.cookie;

    import com.eviware.soapui.impl.wsdl.submit.RequestFilter;
    import com.eviware.soapui.model.iface.Request;
    import com.eviware.soapui.model.iface.Response;
    import com.eviware.soapui.model.iface.SubmitContext;
    import com.eviware.soapui.SoapUI;
    import com.eviware.soapui.support.types.StringToStringMap

    public class Cookie implements RequestFilter {
    //The different types
    private String TYPE1 = "type 1"
    private String TYPE2 = "type 2"
    private String NOWSL = "noWSL"

    //The Header field in the SoapUI test request header
    private String HEADERFIELD = "Cookie"

    //The WSL cookie. Paste the new cookies here and they will replace the old cookies or be added if the header is empty
    private String type 1 cookie = "type 1 cookie"
    private String type 2 cookie = "type 2 cookie"

    //The SoapUI test request header
    private def soapReqHeader

    @Override
    public void afterRequest(SubmitContext arg0, Request arg1) {}

    public void afterRequest(SubmitContext context, Response response) {}

    @Override
    public void filterRequest(SubmitContext context, Request wsdlRequest) {
    String wslCookie
    String wslType

    //The header taken from the request is a StringToStringMap property of the wsdlRequest object
    soapReqHeader = wsdlRequest.requestHeaders

    String endpoint = getEndpointType(wsdlRequest)

    switch (endpoint) {
    case TYPE1 :
    SoapUI.log.info("**** type 1 cookie ****")
    wslType = "type 1"
    wslCookie = type 1 cookie
    populateHeader(soapReqHeader, HEADERFIELD, wslType, wslCookie)
    break

    case TYPE2 :
    SoapUI.log.info("**** type 2 cookie ****")
    wslType = "type 2"
    wslCookie = type 2 cookie
    populateHeader(soapReqHeader, HEADERFIELD, wslType, wslCookie)
    break

    default:
    SoapUI.log.info("***** No cookie needed ****")
    soapReqHeader = new StringToStringMap()
    break
    }
    wsdlRequest.requestHeaders = soapReqHeader
    }

    /* Populates the header by either replacing an existing cookie
    or adding one if no header can he found.
    The header consists of a key (supposed to be "cookie" or
    "Cookie") and a value.
    The toString() method invoked on the header returns a hidden
    "\n" that must be removed for matching purposes.
    The substring(9) method call is to remove the key ("Cookie : ")
    from the value to be replaced.
    */

    private void populateHeader(def reqHeader, String headerName, String prefix, String cookie) {
    if ((reqHeader.toString().length() && cookie.trim().length() > 1) && reqHeader.getKeys()[0] ==~ /(?i)cookie/) {
    SoapUI.log.info("**** Header has cookie ****")
    if (reqHeader.toString().replaceAll("(\\r|\\n)", "").endsWith(cookie)) {
    SoapUI.log.info("**** Cookies match, do nothing ****")
    } else {
    SoapUI.log.info("**** Updating cookie ****")
    reqHeader.replace(reqHeader.getKeys()[0], reqHeader.toString().substring(9).replaceAll("(\\r|\\n)", ""), prefix + cookie)
    }
    } else if (cookie.trim().length() > 1) {
    SoapUI.log.info("**** Header is empty, adding cookie ****")
    reqHeader.put(headerName, prefix + cookie)
    } else {
    SoapUI.log.info("**** FYI: The cookie is empty ****")
    }
    }

    /* getEndpoint() returns the entire path including the service name.
    The regexp filters out the essential information and braces
    potential "https" additions
    */

    private String getEndpointType(Request wsdlRequest) {
    String endpointType

    if (wsdlRequest.getEndpoint() =~ "type 1 endpoint") { endpointType = TYPE1 }

    else if (wsdlRequest.getEndpoint() =~ "type 2 endpoint") { endpointType = TYPE2 }

    else { endpointType = NOWSL }

    return endpointType
    }
    }

    To set this up you should put in the cookies, cookie types and the endpoint urls. The endpoint urls you add in the getEndpointTypes method and they should not include "http://" nor the services. The idea is that a certain cookie type is used for a certain url regardless if it's http or https and regardless of the specific service. This is why a regexp is used. For example,

    http://myservice.com/wsdl/service_1

    and

    https://myservice.com/wsdl/service_2

    both use the same cookie type but you don't want two cases for this. The regexp pattern =~ "myservice.com" makes sure that the same type is used in both cases. When set up, the script will automatically change type and cookie based on the used endpoint so you can use it with automated scrips running against different urls authenticated by different cookies. Of course, you have to add cookies, types, cases and endpoint types yourself.
  • QWERTY's avatar
    QWERTY
    Occasional Contributor
    A bit more specifics on the full script:

    The filterRequest method first calls the getEndpointType method to resolve the type of cookie to be used. It then enters a switch based on the result. Each case sets the type and cookie and then calls the populateHeader method. This one is a bit more complicated. Basically it checks if a header even exists and if so, if the key is "cookie" (ignores case) and if the current cookie the same. If so, nothing happens otherwise the cookie is updated. If no header exists one is added and if the value of the cookie (in the script file) is empty, the log informs the user and nothing happens.

    Now, the header read from the request includes "Cookie : " which is removed by using substring(9) and a line break at the end that is removed by replaceAll("(\\r|\\n)

    The key is a property used in the replace and put methods belonging to the StringToStringMap class. Look it up in the API for details.

    This script, unlike the lite version, will not work out of the box but needs a bit of configuring but read through it and you'll understand the principle.