Skip to content
This repository has been archived by the owner on Aug 8, 2024. It is now read-only.

INT-7818 - Add personal access token support #181

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
BULK_INGEST_ISSUES=false
REDACT_ISSUE_DESCRIPTIONS=FALSE
CUSTOM_FIELDS=["customField1", "custonField2"]
PROJECTS=["JJI"]

# Jira Cloud
JIRA_HOST=https://jupiterone-dev.atlassian.net
JIRA_API_VERSION=
JIRA_USERNAME=jupiterone-dev
JIRA_PASSWORD=testing123
REDACT_ISSUE_DESCRIPTIONS=FALSE
PROJECTS=["JJI"]

# Jira Server (local)
LOCAL_SERVER_JIRA_HOST=http://localhost:8080
LOCAL_SERVER_JIRA_USERNAME=jupiterone-dev
LOCAL_SERVER_JIRA_PASSWORD=testing123
LOCAL_SERVER_PROJECTS=["SP"]
CUSTOM_FIELDS=["customField1", "custonField2"]
JIRA_HOST=https://localhost
JIRA_API_VERSION=2
JIRA_PAT_TOKEN=dummy-pat-token
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ and this project adheres to

## [Unreleased]

### 3.6.2 - 2023-04-04

### Added

- Added support for using a Jira PAT Token for Jira On-Prem

### 3.6.1 - 2023-03-01

### Fixed
Expand Down
44 changes: 36 additions & 8 deletions docs/jupiterone.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ projects one wishes to ingest. Then delete the old integration configuration.
## Requirements

- JupiterOne requires the hostname for your Jira organization. JupiterOne also
requires the username/email and an API key for a user having the correct
permissions granted.
requires the username/email and an API key for Jira Cloud or a
password/Personal Access Token (PAT) for Jira Data Center (On-Prem).
- The integration supports Jira Cloud with Jira API v3 and Jira Data Center with
Jira API v2. Other setups may work.
- You must have permission in JupiterOne to install new integrations.
Expand All @@ -72,10 +72,15 @@ If you need help with this integration, please contact

## Integration Walkthrough

Customers authorize access to JupiterOne by creating a Jira user and providing
the username and password (or [API token][2] when passwords require MFA) to
JupiterOne for HTTP Basic Auth as described in the [Jira Security for Other
Integrations][1] documentation.
For Jira Cloud, customers authorize access to JupiterOne by creating a Jira user
and providing the username and [API token][2] to JupiterOne for HTTP Basic Auth
as described in the [Jira Security for Other Integrations][1] documentation.

For Jira On-Prem, customers authorize access by creating a Jira user and
providing either:

1. A username and passowrd or;
2. A Personal Access Token ([PAT][6])

### In Jira

Expand Down Expand Up @@ -108,11 +113,16 @@ Before you use an existing user, you should verify a couple of things.
- Authorize "Create Issues" permissions in projects that serve as JupiterOne
Alert Rule action targets.

#### Create an API Token
#### Create an API Token (For Cloud)

1. Log in to Jira as the JupiterOne user and follow the Jira guide to [create an
API token][2].

#### Create a PAT (For On-Prem)

1. Log in to Jira as the JupiterOne user and follow the Jira guide to [create a
PAT][6].

### In JupiterOne

1. From the top navigation of the J1 Search homepage, select **Integrations**.
Expand All @@ -129,6 +139,8 @@ Before you use an existing user, you should verify a couple of things.
- Enter the **Hostname** of your organization.
- Enter the **User Email** used to authenticate with Jira.
- Enter the **API Token** in the **User Password** field.
- (Optionally) Enter the **PAT** in the **Personal Access Token** field if
you are using JIRA On-Prem
- Toggle the **Redact Issue Descriptions** option if you would like to avoid
descriptions on your `jira_issue` entities
- Enter the **Project Keys** that the integration will retrieve data from.
Expand All @@ -148,7 +160,21 @@ This integration supports both Jira Cloud and Jira on-prem deployments and will
automatically detect which is being ingested. It is important to note that there
are some minor differences in the APIs for cloud and on-prem. For this reason,
we recommended that you recreate your integration configuration in the event of
an on-prem -> cloud migration or vice versa.
an on-prem -> cloud migration or vice versa. Specifically, the relevant
differences are:

### Jira On-Prem:

Jira On-Prem supports (version dependant):

- Basic Auth with username + password
- Bearer token (still Basic Auth) with a PAT

### Jira Cloud:

Jira Cloud supports:

- Basic Auth with username + API Token

<!-- {J1_DOCUMENTATION_MARKER_START} -->
<!--
Expand Down Expand Up @@ -202,3 +228,5 @@ END OF GENERATED DOCUMENTATION AFTER BELOW MARKER
https://confluence.atlassian.com/jirakb/jira-cloud-how-to-create-a-read-only-user-779160729.html
[5]:
https://confluence.atlassian.com/adminjiraserver/managing-global-permissions-938847142.html
[6]:
https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/graph-jira",
"version": "3.6.1",
"version": "3.6.2",
"description": "A JupiterOne managed integration for https://www.atlassian.com/software/jira.",
"main": "dist/index.js",
"repository": "https://github.com/JupiterOne/graph-jira",
Expand Down
2 changes: 2 additions & 0 deletions src/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
import { setupJiraRecording } from '../test/recording';
import { JiraIntegrationInstanceConfig, validateInvocation } from './config';

jest.setTimeout(10000);

describe(validateInvocation, () => {
let recording: Recording;

Expand Down
14 changes: 12 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export const instanceConfigFields: IntegrationInstanceConfigFieldMap = {
type: 'string',
mask: true,
},
jiraPATToken: {
type: 'string',
mask: true,
},
redactIssueDescriptions: {
type: 'boolean',
mask: false,
Expand Down Expand Up @@ -88,6 +92,7 @@ export interface JiraIntegrationInstanceConfig

jiraUsername: string;
jiraPassword: string;
jiraPATToken: string;

/**
* An array of Jira project keys to target for ingestion.
Expand Down Expand Up @@ -139,9 +144,13 @@ export async function validateInvocation(
) {
const { config } = context.instance;

if (!config.jiraHost || !config.jiraPassword || !config.jiraUsername) {
if (!config.jiraHost) {
throw new IntegrationValidationError('Config requires {jiraHost}');
}

if (!(config.jiraPassword && config.jiraUsername) && !config.jiraPATToken) {
throw new IntegrationValidationError(
'Config requires all of {jiraHost, jiraUsername, jiraPassword}',
'Config requires either {jiraUsername, jiraPassword} or {jiraPATToken}',
);
}

Expand Down Expand Up @@ -200,6 +209,7 @@ export function buildNormalizedInstanceConfig(
...jiraHostConfig,
username: config.jiraUsername,
password: config.jiraPassword,
bearer: config.jiraPATToken,
apiVersion: jiraApiVersion,
projects: normalizeProjectKeys(config.projects),
customFields: normalizeCustomFieldIdentifiers(config.customFields),
Expand Down
2 changes: 2 additions & 0 deletions src/jira/detectApiVersion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
import { setupJiraRecording } from '../../test/recording';
import { detectApiVersion } from './detectApiVersion';

jest.setTimeout(10000);

describe(detectApiVersion, () => {
let recording: Recording;

Expand Down
2 changes: 2 additions & 0 deletions test/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const integrationInstanceConfig: JiraIntegrationInstanceConfig = {
jiraHost: process.env.JIRA_HOST || 'jupiterone-dev.atlassian.net',
jiraUsername: process.env.JIRA_USERNAME || '[email protected]',
jiraPassword: process.env.JIRA_PASSWORD || 'default-jira-password',
jiraPATToken: process.env.JIRA_PAT_TOKEN || 'default-pat-token',
projects: process.env.PROJECTS || ['JJI'],
redactIssueDescriptions: false,
};
Expand All @@ -41,6 +42,7 @@ export const localServerInstanceConfig: JiraIntegrationInstanceConfig = {
jiraUsername: process.env.LOCAL_SERVER_JIRA_USERNAME || 'jupiterone-dev',
jiraPassword:
process.env.LOCAL_SERVER_JIRA_PASSWORD || 'default-jira-password',
jiraPATToken: process.env.JIRA_PAT_TOKEN || 'default-pat-token',
projects: process.env.LOCAL_SERVER_PROJECTS || ['SP'],
redactIssueDescriptions: false,
};
Expand Down