Webhooks plugins tutorial
In this tutorial we are going to create a custom authentication method for HTTP endpoint for webhooks.
The tutorial plugin will be called xlr-mywebhooks-plugin
.
The authentication method will be able to authenticate HTTP requests based on an URL parameter’s value. The user must configure the parameter name and a secret token.
Plugin structure
- First create a directory for the plugin:
mkdir xlr-mywebhooks-plugin
- Create the structure:
touch synthetic.xml
mkdir mywebhooks/
touch mywebhooks/UrlParameterTokenAuthentication.py
The synthetic.xml
file will contain the custom types definitions while the mywebhooks
directory will contain the python scripts.
- Enter the following text into the
synthetic.xml
file:
<synthetic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.xebialabs.com/deployit/synthetic"
xsi:schemaLocation="http://www.xebialabs.com/deployit/synthetic synthetic.xsd">
</synthetic>
That is what an empty synthetic.xml
file looks like, and you will add type definitions inside the <synthetic>
node.
Custom authentication method: URL Parameter Token
- Open the
synthetic.xml
file add add the type definition of our custom authentication method:
<synthetic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.xebialabs.com/deployit/synthetic"
xsi:schemaLocation="http://www.xebialabs.com/deployit/synthetic synthetic.xsd">
<type type="mywebhooks.UrlParameterTokenAuthentication"
extends="events.CustomJythonAuthentication"
label="URL Parameter Token"
description="Verify that the value of a given URL parameter matches the secret token.">
<property name="parameter" kind="string" required="true"
label="URL parameter"
description="URL parameter name containing the token."/>
<property name="token" kind="string" password="true" required="true"
label="Token"
description="Secret token value."/>
</type>
</synthetic>
- Open the
mywebhooks/UrlParameterTokenAuthentication.py
file and write this script:
# required to decrypt password properties. Can only be used by packaged scripts.
from com.xebialabs.deployit.util import PasswordEncrypter
# the endpoint instance.
global endpoint
# the `mywebhooks.UrlParameterTokenAuthentication` instance. Holds the `parameter` and `token` properties
global config
# the HTTP headers. Python dictionary
global headers
# the URL parameters. Python dictionary. Each value is an array of strings.
global parameters
# the HTTP request body. Only available when endpoint.method == "POST"
global payload
# let's get the PasswordEncrypter instance
pe = PasswordEncrypter.getInstance()
# find the URL parameter named `config.parameter` and return its value
def getToken():
return parameters[config.parameter] if config.parameter in parameters else ""
# True if one of the value of the `config.parameter` URL parameter is the decrypted `config.token`.
authenticated = pe.ensureDecrypted(config.token) == getToken()
Test the new custom authentication method
Setup a test endpoint
- Add the type definition from
synthetic.xml
toXL_RELEASE_HOME/ext/synthetic.xml
. - Copy your
mywebhooks
directory to yourXL_RELEASE_HOME/ext/
directory. - Restart Release.
- From the navigation pane, under Configuration > Connections > Webhooks and Event, create a new HTTP GET endpoint for Webhooks.
- Name it, for example
My Test Endpoint (GET)
. - Set the path, for example
test_endpoint_get
. - Under authentication, a new option named ‘URL Parameter Token” should be available.
- Select ‘URL Parameter Token’.
- Configure the parameter field: type
token
. - Configure the token field: type
tok3n
. - Save the new HTTP endpoint for webhooks.
Verify the test endpoint with the custom authentication method
- Check that it rejects requests with the bad token value:
curl -v 'http://your-xl-release-url/webhooks/test_endpoint_get?token=wr0ng'
> * Trying ::1:5516...
> * TCP_NODELAY set
> * Connected to localhost (::1) port 5516 (#0)
> > GET /webhooks/test_endpoint_get?token=wr0ng HTTP/1.1
> > Host: localhost:5516
> > User-Agent: curl/7.66.0
> > Accept: */*
> >
> * Mark bundle as not supporting multiuse
> < HTTP/1.1 401 Unauthorized
> < Date: Mon, 24 Feb 2020 15:59:00 GMT
> < X-XSS-Protection: 1; mode=block
> < X-Content-Type-Options: nosniff
> < Content-Type: application/json
> < Content-Length: 238
> <
> * Connection #0 to host localhost left intact
> Unauthorized request for 'Configuration/Custom/Configurationc2f85e3a3d424d45a81f4b87fe32bc5e (My Test Endpoint (GET))' (authentication method: com.xebialabs.xlrelease.webhooks.authentication.CustomJythonAuthenticationMethod)%
- Check that it rejects requests with the bad parameter name:
curl -v -X GET 'http://your-xl-release-url/webhooks/test_endpoint_get?wrong=tok3n'
> * Trying ::1:5516...
> * TCP_NODELAY set
> * Connected to localhost (::1) port 5516 (#0)
> > GET /webhooks/test_endpoint_get?wrong=tok3n HTTP/1.1
> > Host: localhost:5516
> > User-Agent: curl/7.66.0
> > Accept: */*
> >
> * Mark bundle as not supporting multiuse
> < HTTP/1.1 401 Unauthorized
> < Date: Mon, 24 Feb 2020 15:57:49 GMT
> < X-XSS-Protection: 1; mode=block
> < X-Content-Type-Options: nosniff
> < Content-Type: application/json
> < Content-Length: 238
> <
> * Connection #0 to host localhost left intact
> Unauthorized request for 'Configuration/Custom/Configurationc2f85e3a3d424d45a81f4b87fe32bc5e (My Test Endpoint (GET))' (authentication method: com.xebialabs.xlrelease.webhooks.authentication.CustomJythonAuthenticationMethod)%
- Check that it accepts requests with the correct parameter name and value:
curl -v -X GET 'http://your-xl-release-url/webhooks/test_endpoint_get?token=tok3n'
> * Trying ::1:5516...
> * TCP_NODELAY set
> * Connected to localhost (::1) port 5516 (#0)
> > GET /webhooks/test_endpoint_get?token=tok3n HTTP/1.1
> > Host: localhost:5516
> > User-Agent: curl/7.66.0
> > Accept: */*
> >
> * Mark bundle as not supporting multiuse
> < HTTP/1.1 200 OK
> < Date: Mon, 24 Feb 2020 15:56:54 GMT
> < X-XSS-Protection: 1; mode=block
> < X-Content-Type-Options: nosniff
> < Vary: Accept-Encoding, User-Agent
> < Content-Length: 0
> <
> * Connection #0 to host localhost left intact
Package your plugin
- Go to your plugin’s working directory (
xlr-mywebhooks-plugin
) - Go up one level:
cd ..
- Create a build directory:
rm -rf xlr-mywebhooks-plugin-build && mkdir xlr-mywebhooks-plugin-build
- Enter the build directory:
cd xlr-mywebhooks-plugin-build
- Add the
MANIFEST.MF
file:mkdir -p META-INF && echo 'Manifest-Version: 1.0' > META-INF/MANIFEST.MF
- Copy the synthetic.xml file:
cp ../xlr-mywebhooks-plugin/synthetic.xml .
- Copy the scripts directory:
cp -r ../xlr-mywebhooks-plugin/mywebhooks .
- Create the plugin:
zip -r ../xlr-mywebhooks-plugin-0.1.jar .
- Exit the build directory:
cd ..
- Your plugin is ready in your current directory, named
xlr-mywebhooks-plugin-0.1.jar
- You can upload to your Release instance using the Plugin Manager screen (required being admin and a non-clustered installation).
- Alternatively, place the
xlr-mywebhooks-plugin-0.1.jar
file in theXL_RELEASE_HOME/plugin/__local__
directory - Remember to remove your type definitions from
XL_RELEASE_HOME/ext/synthetic.xml
and remove theXL_RELEASE_HOME/ext/mywebhooks
directory from your installation used during development and testing once you install the plugin. - Restart Release