Skip to content

Commit 1969631

Browse files
committed
sailpoint init
1 parent 2dbbd91 commit 1969631

File tree

6 files changed

+402
-0
lines changed

6 files changed

+402
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import sailpoint from "../../sailpoint.app.mjs";
2+
import { axios } from "@pipedream/platform";
3+
4+
export default {
5+
key: "sailpoint-list-certification-campaigns",
6+
name: "List Certification Campaigns",
7+
description: "Retrieves multiple certification campaigns in IdentityNow. [See the documentation]()",
8+
version: "0.0.{{ts}}",
9+
type: "action",
10+
props: {
11+
sailpoint: {
12+
type: "app",
13+
app: "identitynow",
14+
},
15+
filter: {
16+
propDefinition: [
17+
"sailpoint",
18+
"filter",
19+
],
20+
optional: true,
21+
},
22+
},
23+
async run({ $ }) {
24+
const campaigns = await this.sailpoint.retrieveCertificationCampaigns();
25+
$.export("$summary", `Successfully retrieved ${campaigns.length} certification campaigns`);
26+
return campaigns;
27+
},
28+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import identitynow from "../../identitynow.app.mjs";
2+
import { axios } from "@pipedream/platform";
3+
4+
export default {
5+
key: "identitynow-submit-access-request",
6+
name: "Submit Access Request",
7+
description: "Sends an access request to IdentityNow. [See the documentation](https://developer.sailpoint.com/docs/api/v2024/create-access-request)",
8+
version: "0.0.{{ts}}",
9+
type: "action",
10+
props: {
11+
identitynow,
12+
requestedFor: {
13+
propDefinition: [
14+
identitynow,
15+
"requestedFor",
16+
],
17+
},
18+
requestType: {
19+
propDefinition: [
20+
identitynow,
21+
"requestType",
22+
],
23+
optional: true,
24+
},
25+
requestedItems: {
26+
propDefinition: [
27+
identitynow,
28+
"requestedItems",
29+
],
30+
},
31+
},
32+
async run({ $ }) {
33+
const response = await this.identitynow.submitAccessRequest();
34+
$.export("$summary", "Access request submitted successfully.");
35+
return response;
36+
},
37+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import sailpoint from "../../sailpoint.app.mjs";
2+
import { axios } from "@pipedream/platform";
3+
4+
export default {
5+
key: "sailpoint-upload-account-source-file",
6+
name: "Upload Account Source File",
7+
description: "Uploads a CSV-formatted account source file to IdentityNow. [See the documentation]()",
8+
version: "0.0.{{ts}}",
9+
type: "action",
10+
props: {
11+
sailpoint,
12+
sourceId: {
13+
propDefinition: [
14+
sailpoint,
15+
"sourceId",
16+
],
17+
},
18+
csvAccountFile: {
19+
propDefinition: [
20+
sailpoint,
21+
"csvAccountFile",
22+
],
23+
},
24+
},
25+
async run({ $ }) {
26+
const response = await this.sailpoint.uploadCsvAccountFile();
27+
$.export("$summary", `Successfully uploaded CSV account file for source ${response.id} (${response.name})`);
28+
return response;
29+
},
30+
};
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { axios } from "@pipedream/platform";
2+
3+
export default {
4+
type: "app",
5+
app: "identitynow",
6+
propDefinitions: {
7+
// Props for uploading CSV account file
8+
sourceId: {
9+
type: "string",
10+
label: "Source ID",
11+
description: "ID of the source to upload the account file.",
12+
},
13+
csvAccountFile: {
14+
type: "string",
15+
label: "CSV Account File",
16+
description: "CSV-formatted account file content.",
17+
},
18+
// Props for retrieving certification campaigns
19+
filter: {
20+
type: "string",
21+
label: "Filter",
22+
description: "Optional filter to adjust campaign retrieval.",
23+
optional: true,
24+
},
25+
// Props for submitting access request
26+
requestedFor: {
27+
type: "string[]",
28+
label: "Requested For",
29+
description: "List of Identity IDs for whom the Access is requested.",
30+
},
31+
requestType: {
32+
type: "string",
33+
label: "Request Type",
34+
description: "Type of access request.",
35+
options: [
36+
{
37+
label: "Grant Access",
38+
value: "GRANT_ACCESS",
39+
},
40+
{
41+
label: "Revoke Access",
42+
value: "REVOKE_ACCESS",
43+
},
44+
],
45+
optional: true,
46+
},
47+
requestedItems: {
48+
type: "string[]",
49+
label: "Requested Items",
50+
description: "List of requested items as JSON strings.",
51+
},
52+
},
53+
methods: {
54+
_baseUrl() {
55+
return "https://sailpoint.api.identitynow.com/v2024";
56+
},
57+
async _makeRequest(opts = {}) {
58+
const {
59+
$, method = "GET", path = "/", headers, ...otherOpts
60+
} = opts;
61+
return axios($, {
62+
method,
63+
url: this._baseUrl() + path,
64+
headers: {
65+
...headers,
66+
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
67+
},
68+
...otherOpts,
69+
});
70+
},
71+
async uploadCsvAccountFile() {
72+
const {
73+
sourceId, csvAccountFile,
74+
} = this;
75+
const formData = new FormData();
76+
formData.append("file", csvAccountFile, "accounts.csv");
77+
return this._makeRequest({
78+
method: "POST",
79+
path: `/v3/sources/${sourceId}/schemas/accounts`,
80+
headers: {
81+
...formData.getHeaders(),
82+
"X-SailPoint-Experimental": "true",
83+
},
84+
data: formData,
85+
});
86+
},
87+
async retrieveCertificationCampaigns() {
88+
const { filter } = this;
89+
const params = {};
90+
if (filter) {
91+
params.filter = filter;
92+
}
93+
return this._makeRequest({
94+
method: "GET",
95+
path: "/campaigns",
96+
params,
97+
});
98+
},
99+
async submitAccessRequest() {
100+
const {
101+
requestedFor, requestType, requestedItems,
102+
} = this;
103+
const data = {
104+
requestedFor,
105+
requestType: requestType || "GRANT_ACCESS",
106+
requestedItems: requestedItems.map((item) => JSON.parse(item)),
107+
};
108+
return this._makeRequest({
109+
method: "POST",
110+
path: "/access-requests",
111+
data,
112+
});
113+
},
114+
},
115+
version: `0.0.${Date.now()}`,
116+
};
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import sailpoint from "../../sailpoint.app.mjs";
2+
import crypto from "crypto";
3+
import { axios } from "@pipedream/platform";
4+
5+
export default {
6+
key: "sailpoint-identity-attribute-change-instant",
7+
name: "Identity Attribute Change Instant",
8+
description: "Emit new event when any attributes of an identity change. [See the documentation]()",
9+
version: "0.0.{{ts}}",
10+
type: "source",
11+
dedupe: "unique",
12+
props: {
13+
sailpoint: {
14+
type: "app",
15+
app: "sailpoint",
16+
},
17+
http: {
18+
type: "$.interface.http",
19+
customResponse: true,
20+
},
21+
db: "$.service.db",
22+
},
23+
methods: {
24+
async createWebhook() {
25+
const callbackUrl = this.http.endpoint;
26+
const response = await this.sailpoint._makeRequest({
27+
method: "POST",
28+
path: "/webhooks",
29+
data: {
30+
triggerId: "idn:identity-attributes-changed",
31+
callbackUrl: callbackUrl,
32+
},
33+
});
34+
return response.id;
35+
},
36+
async deleteWebhook(webhookId) {
37+
await this.sailpoint._makeRequest({
38+
method: "DELETE",
39+
path: `/webhooks/${webhookId}`,
40+
});
41+
},
42+
async listIdentityAttributeChanges() {
43+
const response = await this.sailpoint._makeRequest({
44+
method: "GET",
45+
path: "/identity-attributes-changed",
46+
params: {
47+
limit: 50,
48+
sort: "-timestamp",
49+
},
50+
});
51+
return response.events || [];
52+
},
53+
},
54+
hooks: {
55+
async deploy() {
56+
const events = await this.listIdentityAttributeChanges();
57+
for (const event of events.reverse()) {
58+
this.$emit(event.attributes, {
59+
id: event.id || event.timestamp.toString(),
60+
summary: `Attributes changed for identity ${event.identityId}`,
61+
ts: new Date(event.timestamp).getTime(),
62+
});
63+
}
64+
},
65+
async activate() {
66+
const webhookId = await this.createWebhook();
67+
await this.db.set("webhookId", webhookId);
68+
},
69+
async deactivate() {
70+
const webhookId = await this.db.get("webhookId");
71+
if (webhookId) {
72+
await this.deleteWebhook(webhookId);
73+
await this.db.set("webhookId", null);
74+
}
75+
},
76+
},
77+
async run(event) {
78+
const signature = event.headers["X-Signature"] || event.headers["x-signature"];
79+
const secretKey = this.sailpoint.$auth.secret;
80+
const computedSignature = crypto
81+
.createHmac("sha256", secretKey)
82+
.update(event.body)
83+
.digest("base64");
84+
if (computedSignature !== signature) {
85+
await this.http.respond({
86+
status: 401,
87+
body: "Unauthorized",
88+
});
89+
return;
90+
}
91+
const data = JSON.parse(event.body);
92+
this.$emit(data.changedAttributes, {
93+
id: data.id || data.timestamp.toString(),
94+
summary: `Attributes changed for identity ${data.identityId}`,
95+
ts: Date.parse(data.timestamp) || Date.now(),
96+
});
97+
},
98+
};

0 commit comments

Comments
 (0)