Advanced Workflows
In case you did not find a preset suited for your need, you can write your own procedures manually.
Writing authentication procedures
A procedure is a sequence of operations to execute agains an application, that aims at generating variables to be reused later on to build a user's authentication credentials.
Most of the time, a procedure will be a sequence of one or more HTTP requests, but it can also include other types of operations, like a Selenium script mocking a browser navigation, or a request against a GraphQL server.
A procedure is defined as a JSON object, with the following properties:
name
: the name of the procedure, used to reference it later on within the configuration file. It must be unique across procedures.operations
: an array of operations to execute, in order. Each operation must include atech
property, indicating the type of operation to execute. Depending on the type of operation, the configuration structure might vary.
It consists of an array of operations
An operation is a single action to execute, like a request, a Selenium script, or a GraphQL query. It also declares how to extract variables from the response of the operation, if any. These variables can then be reused later on to declare users.
Operations of different types can be combined within a procedure! As an example, authenticating against an OIDC server, using an authorization code flow might require you to:
- Declare a Selenium operation to navigate on the authentication portal of the OIDC server and retrieve an authorization code
- Use an HTTP request to trade the retrieved token for an access token and a refresh token.
Understanding Injections and Extractions
Extractions are crucial for deriving variables from the responses of operations. These variables are then available for use in subsequent steps of the procedure. The extraction process involves specifying the location (such as the body or header of a response) and the key for the data to be extracted, and the potential regex to extract specific data whithin the key.
Injections are used to incorporate extracted variables into the final credentials generated for the user. This process involves specifying the location (such as a header or cookie), the key where the variable should be inserted, and the potential prefix of the token.
Note that if necessary, multiple variables can be injected at the end of the processure.
Templating in Procedures
Escape's authentication procedures support Jinja templating, allowing the injection of extracted variables into subsequent operations. This templating feature includes all standard Jinja functions, plus the ability to base64
encode values.
Example 1: Simple HTTP requests chaining
procedures:
# (1)
- name: example-procedure # (2)
operations:
- tech: http # (3)
parameters:
url: "https://vampi.tools.escape.tech"
method: GET
# (4)
extractions:
- name: example-extraction
location: body
key: message
# (5)
- tech: http
parameters:
url: "https://vampi.tools.escape.tech"
method: GET
headers:
- name: X-Example-Header-Extracted
values:
- "{{ example-extraction }}" # (6)
# (7)
- This authentication procedure declares two HTTP requests to be executed in order.
- The name of the procedure has to be unique, as it is used as a reference when declaring users later on.
- Requests can rely on different request engines, even if they lie in the same procedure. A GraphQL request could follow an pure HTTP request.
- The parameters to provide depend on the type of the request being declared. For HTTP requests (with
tech
set tohttp
), anything that defines an HTTP request can be configured:url
,method
,headers
,cookies
,body
,username
orpassword
, and even an eventualproxy
. Only theurl
andmethod
parameters are required. - After any request of any type, it is possible to run 0 or more extractions, in order to build variables from the content of the response. Here, we create a variable
example-variable
by looking at themessage
field of the response body. - Once they have been defined, variables can be re-injected within arbitrary locations in the procedure with the syntax
{{ example-variable }}
in the JSON configuration file. Under the hood, the configuration is stringified before the variables are interpolated, before it is deserialized once again. - You can declare multiple procedures in your multiauth configuration file, allowing to declare an authentication procedure as well as a refresh procedure for instance.
Example 2: Selenium Webdriver followed by HTTP requests
Selenium scripts are declared with the selenium
value for the tech
property of the operation configuration object. Selenium tests
are generated through the Selenium IDE.
In this example:
- An intermediate token
intermediateToken
is extracted from the query params of a request of the Webdriver - This token is injected in the header
X-Example-Intermediate-Token
of an HTTP Request made on another server - From the response Body of the HTTP Request, the
finalToken
is extracted - And it will be injected in the final user
header
as theAuthorization: Bearer {{ finalToken }}
procedures:
- name: my-complex-auth-flow
injections:
- location: header
key: Authorization
prefix: Bearer
variable: finalToken
operations:
- tech: selenium
extractions:
- name: intermediateToken
regex: "onboarding-portal.*portal-session-id=([^*]*)"
location: query
key: ""
options:
wait_for_seconds: 15
parameters:
project:
id: 1ae906e4-4e67-4561-abc2-cbbd2e646de9
url: https://gosecure1.example.com
name: lsp-onboarding-portal.auth
urls:
- https://gosecure1.example.com/
tests:
- id: aec1dcca-65ca-4e09-82a6-8da7bbddbde0
name: Example Onboarding
commands:
- id: bb671e84-0d81-40da-92ad-4086ec483f6d
value: ""
target: https://gosecure1.example.com/signin/?return=/setup/payment-types/
command: open
comment: ""
targets: []
- id: 6406387f-c3bf-453c-8dee-561a548f6c42
value: user@example.com
target: name=username
command: type
comment: ""
targets:
- - name=username
- name
- - css=.vd-field:nth-child(1) .vd-input
- css:finder
- - xpath=//input[@name='username']
- xpath:attributes
- - xpath=//div[@id='react-root']/section/main/div/div/div/div/div/div[2]/form/div/div[2]/input
- xpath:idRelative
- - xpath=//input
- xpath:position
- id: adf71a06-33cc-4e89-b69b-0e324edaa314
value: random
target: name=password
command: type
comment: ""
targets:
- - name=password
- name
- - css=.vd-field:nth-child(2) .vd-input
- css:finder
- - xpath=//input[@name='password']
- xpath:attributes
- - xpath=//div[@id='react-root']/section/main/div/div/div/div/div/div[2]/form/div[2]/div[2]/input
- xpath:idRelative
- - xpath=//div[2]/div[2]/input
- xpath:position
- id: 0c18a7ca-b347-4402-adf7-18c02b54d326
value: ""
target: name=signin_submit
command: click
comment: ""
targets:
- - name=signin_submit
- name
- - css=.vd-btn
- css:finder
- - xpath=//button[@name='signin_submit']
- xpath:attributes
- - xpath=//div[@id='react-root']/section/main/div/div/div/div/div/div[2]/form/div[3]/button
- xpath:idRelative
- - xpath=//button
- xpath:position
- - xpath=//button[contains(.,'Sign in')]
- xpath:innerText
- id: e9b59e56-3117-4b52-8b7a-aeabbfa513cf
value: ""
target: index=2
command: selectFrame
comment: ""
targets:
- - index=2
- id: 760521da-c075-4aa7-a84f-98ab0e3ca9b1
value: ""
target: css=.css-kw31c7-ButtonContent
command: click
comment: ""
targets:
- - css=.css-kw31c7-ButtonContent
- css:finder
- - xpath=//div[@id='__next']/div/span/div[2]/div/div/div/div/div/div/button/span/span
- xpath:idRelative
- - xpath=//span/span
- xpath:position
- id: 552d7f74-25bf-4213-aba3-b0c5b598f3b9
value: 30
target: request_url_contains=portal-session-id
command: wait
comment: ""
targets: []
suites:
- id: d2b66875-2f64-4d4f-b02b-1a30ea96b810
name: Default Suite
tests:
- aec1dcca-65ca-4e09-82a6-8da7bbddbde0
timeout: 300
parallel: false
persistSession: false
plugins: []
version: 2.0
- tech: http
parameters:
url: https://vampi.tools.escape.tech
method: GET
headers:
- name: X-Example-Intermediate-Token
values:
- "{{ intermediateToken }}"
cookies: []
query_parameters: []
extractions:
- name: finalToken
location: body
key: token
users:
- name: user
credentials: {}
procedure: webdriver