Skip to content

Commit

Permalink
feat(Jira Trigger Node): Add optional query auth for security (#3172)
Browse files Browse the repository at this point in the history
* ✨ Add query auth for Jira Trigger security

* ⚡ small fixes:

* ⚡ Response with 403 when invalid query authentication

* 👕 Fix linting issues

Co-authored-by: Michael Kret <[email protected]>
Co-authored-by: ricardo <[email protected]>
  • Loading branch information
3 people authored Jul 10, 2022
1 parent dbc0280 commit 25093b6
Showing 1 changed file with 91 additions and 4 deletions.
95 changes: 91 additions & 4 deletions packages/nodes-base/nodes/Jira/JiraTrigger.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import {
} from 'n8n-core';

import {
ICredentialDataDecryptedObject,
IDataObject,
INodeType,
INodeTypeDescription,
IWebhookResponseData,
NodeOperationError,
} from 'n8n-workflow';

import {
Expand Down Expand Up @@ -55,6 +57,17 @@ export class JiraTrigger implements INodeType {
},
},
},
{
name: 'httpQueryAuth',
required: true,
displayOptions: {
show: {
incomingAuthentication: [
'queryAuth',
],
},
},
},
],
webhooks: [
{
Expand All @@ -81,6 +94,23 @@ export class JiraTrigger implements INodeType {
],
default: 'cloud',
},
{
displayName: 'Incoming Authentication',
name: 'incomingAuthentication',
type: 'options',
options: [
{
name: 'Query Auth',
value: 'queryAuth',
},
{
name: 'None',
value: 'none',
},
],
default: 'none',
description: 'If authentication should be activated for the webhook (makes it more secure)',
},
{
displayName: 'Events',
name: 'events',
Expand Down Expand Up @@ -379,6 +409,8 @@ export class JiraTrigger implements INodeType {

const webhookData = this.getWorkflowStaticData('node');

const incomingAuthentication = this.getNodeParameter('incomingAuthentication') as string;

if (events.includes('*')) {
events = allEvents;
}
Expand All @@ -402,12 +434,30 @@ export class JiraTrigger implements INodeType {
body.excludeBody = additionalFields.excludeBody as boolean;
}

// tslint:disable-next-line: no-any
const parameters: any = {};

if (incomingAuthentication === 'queryAuth') {
let httpQueryAuth;
try{
httpQueryAuth = await this.getCredentials('httpQueryAuth');
} catch (e) {
throw new NodeOperationError(this.getNode(), `Could not retrieve HTTP Query Auth credentials: ${e}`);
}
if (!httpQueryAuth.name && !httpQueryAuth.value) {
throw new NodeOperationError(this.getNode(), `HTTP Query Auth credentials are empty`);
}
parameters[encodeURIComponent(httpQueryAuth.name as string)] = Buffer.from(httpQueryAuth.value as string).toString('base64');
}

if (additionalFields.includeFields) {
// tslint:disable-next-line: no-any
const parameters: any = {};

for (const field of additionalFields.includeFields as string[]) {
parameters[field] = '${' + field + '}';
}
}

if (Object.keys(parameters).length) {
body.url = `${body.url}?${queryString.unescape(queryString.stringify(parameters))}`;
}

Expand Down Expand Up @@ -441,9 +491,46 @@ export class JiraTrigger implements INodeType {

async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
const queryData = this.getQueryData();
const queryData = this.getQueryData() as IDataObject;
const response = this.getResponseObject();

const incomingAuthentication = this.getNodeParameter('incomingAuthentication') as string;

if (incomingAuthentication === 'queryAuth') {
let httpQueryAuth: ICredentialDataDecryptedObject | undefined;

try {
httpQueryAuth = await this.getCredentials('httpQueryAuth');
} catch (error) { }

if (httpQueryAuth === undefined || !httpQueryAuth.name || !httpQueryAuth.value) {

response.status(403).json({ message: 'Auth settings are not valid, some data are missing' });

return {
noWebhookResponse: true,
};
}

const paramName = httpQueryAuth.name as string;
const paramValue = Buffer.from(httpQueryAuth.value as string).toString('base64');

if (!queryData.hasOwnProperty(paramName) || queryData[paramName] !== paramValue) {

response.status(403).json({ message: 'Provided authentication data is not valid' });

return {
noWebhookResponse: true,
};
}

delete queryData[paramName];

Object.assign(bodyData, queryData);

Object.assign(bodyData, queryData);
} else {
Object.assign(bodyData, queryData);
}

return {
workflowData: [
Expand Down

0 comments on commit 25093b6

Please sign in to comment.