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.
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
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.
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());
}
}
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
.
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.