Send X-XSRF-TOKEN header with all requests

In ALM 16.00 and later versions, ALM enforces the XSRF security check: ALM checks whether the X-XSRF-TOKEN header is included in all requests, except the ones that use the GET HTTP method. If the header is missing, the REST API calls fail.

Overview of XSRF and XSRF security check

Cross-Site Request Forgery (CSRF), also known as XSRF, Sea Surf, or Session Riding, is an attack that tricks the victim into submitting a malicious request. It inherits the identity and privileges of the victim to perform an undesired function on the victim’s behalf. If the victim is a normal user, a successful CSRF attack can force the user to perform such requests as transferring funds and changing email addresses. If the victim is an administrative account, CSRF attacks can endanger the entire web application.

How ALM mitigates XSRF

When a user accesses ALM and requests an action, such as submitting a defect change, the ALM website embeds a random token inside the form. When the user submits the form, the random token is returned, and the ALM server then checks if the two tokens match. If the tokens match, the required action is performed. The attackers have no way to access the random token value generated in the web page, and if they request the page, ALM prevents the attackers from reading the answer.

Impacts of XSRF security check

  • If you have existing scripts to run ALM REST APIs, all these scripts stop working in ALM 16.00 and later versions.

  • If your integrations with ALM access ALM resources using ALM REST APIs, the integrations do not work in ALM 16.00 and later versions.

To make sure your existing scripts and integrations continue working after the upgrade to ALM 16.00, do either of the following:

  • (Recommended) Send the X-XSRF-TOKEN header in all requests. After getting authenticated, the ALM server returns the value of XSRF-TOKEN cookie. In all your subsequent requests, except for the ones that use the HTTP GET method, you should include the X-XSRF-TOKEN header (that is the value of XSRF-TOKEN cookie) in the requests. See X-XSRF-TOKEN header example.

    If you want to bypass the security check for some clients, see Bypass security check.

  • (Not recommended) Disable the security check. See Disable security check.

Back to top

X-XSRF-TOKEN header example

This section provides examples of how the REST requests for the same action differ before and after 16.00. You can refer to the examples to update your requests.

Python example of creating a domain in 16.00 and later

Add the following in your request for ALM 16.00 and later versions. See line 33-34 in the example below.

if cookieName == 'XSRF-TOKEN':
    headers['X-XSRF-TOKEN'] = cookieValue
Copy code
import json
import requests
from requests.auth import HTTPBasicAuth

almUserName = "sa"
almPassword = ""

almURL = "http://<ALM server URL>:<port>/qcbin/"
authEndPoint = almURL + "authentication-point/authenticate"
qcSessionEndPoint = almURL + "rest/site-session"

cookies = dict()

headers = {
    'cache-control': "no-cache",
    'Accept': "application/json",
    'Content-Type': "application/json"
}

response = requests.post(authEndPoint, auth=HTTPBasicAuth(almUserName, almPassword), headers=headers)
if response.status_code == 200:
    cookieName = response.headers.get('Set-Cookie')
    LWSSO_COOKIE_KEY = cookieName[cookieName.index("LWSSO_COOKIE_KEY=") + 17: cookieName.index(";")]
    cookies['LWSSO_COOKIE_KEY'] = LWSSO_COOKIE_KEY
    print('logged in successfully')
response = requests.post(qcSessionEndPoint, headers=headers, cookies=cookies)
if response.status_code == 200 | response.status_code == 201:
    setCookies = response.headers.get('Set-Cookie').split(",")
    for setCookie in setCookies:
        cookieName = setCookie[0: setCookie.index("=")].strip()
        cookieValue = setCookie[setCookie.index("=") + 1: setCookie.index(";")]
        cookies[cookieName] = cookieValue
        if cookieName == 'XSRF-TOKEN':
            headers['X-XSRF-TOKEN'] = cookieValue

createDomainUrl = almURL + "v2/sa/api/domains"

domainData = {'domain': {'name': 'TEST'}}
response = requests.post(createDomainUrl, headers=headers, cookies=cookies, data=json.dumps(domainData))
print(response)

Java example of creating a defect in 16.00 and later

Add createDefect.setRequestProperty("X-XSRF-TOKEN", xsrfHeaderValue); in your request for ALM 16.00 and later versions. See line 51 in the example below.

Copy code
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.*;
import java.util.List;
import java.util.Map;
public class CreateDefect {
    private static String createDefectRequest = "{\"Fields\":[{\"Name\":\"detected-by\",\"values\":[{\"value\":\"sa\"}]}," +
            "{\"Name\":\"creation-time\",\"values\":[{\"value\":\"2010-03-02\"}]}," +
            "{\"Name\":\"severity\",\"values\":[{\"value\":\"2-Medium\"}]}," +
            "{\"Name\":\"name\",\"values\":[{\"value\":\"Returned value not does not match value in database.</ \"}]}]}";
    public static void main(String[] args) throws Exception {
        String almURL = "http://<ALM server URL>:<port>/qcbin/";
        String authEndPoint = almURL + "authentication-point/alm-authenticate";
        String qcSessionEndPoint = almURL + "rest/site-session";
        /*authenticate begin */
        URL authUrl = new URL(authEndPoint);
        HttpURLConnection authConnection = (HttpURLConnection) authUrl.openConnection();
        authConnection.setRequestMethod("POST");
        authConnection.setRequestProperty("Content-Type", "application/xml");
        authConnection.setDoOutput(true);
        OutputStream os = authConnection.getOutputStream();
        try(OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8")){
            osw.write("<alm-authentication><user>sa</user><password></password></alm-authentication>");
        }
        authConnection.connect();
        System.out.println(authConnection.getResponseMessage());
        String lwssoCookie = authConnection.getHeaderField("Set-Cookie").split(";")[0];
        /*authenticate end */
        /*create session begin*/
        HttpURLConnection createSession = (HttpURLConnection) new URL(qcSessionEndPoint).openConnection();
        createSession.setRequestProperty("Cookie", lwssoCookie);
        createSession.setRequestProperty("Content-Type", "application/json");
        createSession.setRequestMethod("POST");
        createSession.connect();
        Map < String, List < String >> values = createSession.getHeaderFields();
        String xsrfHeaderValue = "";
        String cookies = "";
        for (String cookie: values.get("Set-Cookie")) {
            String content = cookie.split(";")[0];
            cookies = cookies + content + ";";
            String[] nameValue = content.split("=");
            String name = nameValue[0];
            String value = nameValue[1];
            if (name.equalsIgnoreCase("XSRF-TOKEN")) {
                xsrfHeaderValue = value;
            }
        }
        /*create session end*/
        /*create defect begin*/
        HttpURLConnection createDefect = (HttpURLConnection) new URL(almURL + "rest/domains/DEFAULT/projects/demo/defects").openConnection();
        createDefect.setRequestProperty("X-XSRF-TOKEN", xsrfHeaderValue);
        createDefect.setRequestProperty("Cookie", cookies + lwssoCookie);
        createDefect.setRequestProperty("Content-Type", "application/json");
        createDefect.setRequestProperty("Accept", "application/json");
        createDefect.setRequestMethod("POST");
        createDefect.setDoOutput(true);
        createDefect.setDoInput(true);
        OutputStream osCreateDefect = createDefect.getOutputStream();
        try(OutputStreamWriter osCreateDefectWriter = new OutputStreamWriter(osCreateDefect, "UTF-8")){
            osCreateDefectWriter.write(createDefectRequest);
        }
        createDefect.connect();
        System.out.println(createDefect.getResponseMessage());
    }
}

Back to top

Bypass security check

If you want to bypass the security check for some clients. Specify the clients by setting the XSRF_BY_CLIENT_TYPE parameter. For the clients that are not defined in this parameter, you still should send the X-XSRF-TOKEN header in all REST API calls.

The format of the parameter value is: <client type 1>=false; <client type 2>=false.

For example:

If you want to bypass the check for UFT and LoadRunner, set the parameter value to Unified Functional Testing=false; LoadRunner=false.

Back to top

Disable security check

If you disable the security check, you make ALM REST API calls without sending the X-XSRF-TOKEN header. However, we recommended you do not disable the security check because it may result in security risks.

To disable the security check, set the ENABLE_XSRF_VALIDATION parameter to N.

Back to top