@optimizely-opal/opal-tool-ocp-sdk 0.0.0-OCP-1487.5 → 0.0.0-OCP-1487.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -14
- package/dist/auth/AuthUtils.d.ts +12 -28
- package/dist/auth/AuthUtils.d.ts.map +1 -1
- package/dist/auth/AuthUtils.js +94 -50
- package/dist/auth/AuthUtils.js.map +1 -1
- package/dist/auth/AuthUtils.test.js +535 -403
- package/dist/auth/AuthUtils.test.js.map +1 -1
- package/dist/function/GlobalToolFunction.d.ts +0 -1
- package/dist/function/GlobalToolFunction.d.ts.map +1 -1
- package/dist/function/GlobalToolFunction.js +1 -10
- package/dist/function/GlobalToolFunction.js.map +1 -1
- package/dist/function/ToolFunction.d.ts +0 -1
- package/dist/function/ToolFunction.d.ts.map +1 -1
- package/dist/function/ToolFunction.js +1 -13
- package/dist/function/ToolFunction.js.map +1 -1
- package/package.json +1 -1
- package/src/auth/AuthUtils.test.ts +638 -495
- package/src/auth/AuthUtils.ts +99 -48
- package/src/function/GlobalToolFunction.ts +2 -14
- package/src/function/ToolFunction.ts +2 -18
package/src/auth/AuthUtils.ts
CHANGED
|
@@ -3,64 +3,115 @@ import { getTokenVerifier } from './TokenVerifier';
|
|
|
3
3
|
import { OptiIdAuthData } from '../types/Models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Validate the OptiID access token
|
|
7
|
+
*
|
|
8
|
+
* @param accessToken - The access token to validate
|
|
9
|
+
* @returns true if the token is valid
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Validate the OptiID access token
|
|
12
|
-
*
|
|
13
|
-
* @param accessToken - The access token to validate
|
|
14
|
-
* @returns true if the token is valid
|
|
15
|
-
*/
|
|
16
|
-
public static async validateAccessToken(accessToken: string | undefined): Promise<boolean> {
|
|
17
|
-
try {
|
|
18
|
-
if (!accessToken) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
const tokenVerifier = await getTokenVerifier();
|
|
22
|
-
return await tokenVerifier.verify(accessToken);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
logger.error('OptiID token validation failed:', error);
|
|
11
|
+
async function validateAccessToken(accessToken: string | undefined): Promise<boolean> {
|
|
12
|
+
try {
|
|
13
|
+
if (!accessToken) {
|
|
25
14
|
return false;
|
|
26
15
|
}
|
|
16
|
+
const tokenVerifier = await getTokenVerifier();
|
|
17
|
+
return await tokenVerifier.verify(accessToken);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
logger.error('OptiID token validation failed:', error);
|
|
20
|
+
return false;
|
|
27
21
|
}
|
|
22
|
+
}
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Extract and validate basic OptiID authentication data from request
|
|
26
|
+
*
|
|
27
|
+
* @param request - The incoming request
|
|
28
|
+
* @returns object with authData and accessToken, or null if invalid
|
|
29
|
+
*/
|
|
30
|
+
function extractAuthData(request: any): { authData: OptiIdAuthData; accessToken: string } | null {
|
|
31
|
+
const authData = request?.bodyJSON?.auth as OptiIdAuthData;
|
|
32
|
+
const accessToken = authData?.credentials?.access_token;
|
|
33
|
+
if (!accessToken || authData?.provider?.toLowerCase() !== 'optiid') {
|
|
34
|
+
logger.error('OptiID token is required but not provided');
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { authData, accessToken };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Validate organization ID matches the app context
|
|
43
|
+
*
|
|
44
|
+
* @param customerId - The customer ID from the auth data
|
|
45
|
+
* @returns true if the organization ID is valid
|
|
46
|
+
*/
|
|
47
|
+
function validateOrganizationId(customerId: string | undefined): boolean {
|
|
48
|
+
if (!customerId) {
|
|
49
|
+
logger.error('Organisation ID is required but not provided');
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
const appOrganisationId = getAppContext()?.account?.organizationId;
|
|
54
|
+
if (customerId !== appOrganisationId) {
|
|
55
|
+
logger.error(`Invalid organisation ID: expected ${appOrganisationId}, received ${customerId}`);
|
|
56
|
+
return false;
|
|
44
57
|
}
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
* @param customerId - The customer ID from the auth data
|
|
50
|
-
* @returns true if the organization ID is valid
|
|
51
|
-
*/
|
|
52
|
-
public static validateOrganizationId(customerId: string | undefined): boolean {
|
|
53
|
-
if (!customerId) {
|
|
54
|
-
logger.error('Organisation ID is required but not provided');
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Check if a request should skip authentication (discovery/ready endpoints)
|
|
64
|
+
*
|
|
65
|
+
* @param request - The incoming request
|
|
66
|
+
* @returns true if auth should be skipped
|
|
67
|
+
*/
|
|
68
|
+
function shouldSkipAuth(request: any): boolean {
|
|
69
|
+
return request.path === '/discovery' || request.path === '/ready';
|
|
70
|
+
}
|
|
63
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Core authentication flow - extracts auth data and validates token
|
|
74
|
+
*
|
|
75
|
+
* @param request - The incoming request
|
|
76
|
+
* @param validateOrg - Whether to validate organization ID
|
|
77
|
+
* @returns true if authentication succeeds
|
|
78
|
+
*/
|
|
79
|
+
async function authenticateRequest(request: any, validateOrg: boolean = false): Promise<boolean> {
|
|
80
|
+
if (shouldSkipAuth(request)) {
|
|
64
81
|
return true;
|
|
65
82
|
}
|
|
83
|
+
|
|
84
|
+
const authInfo = extractAuthData(request);
|
|
85
|
+
if (!authInfo) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { authData, accessToken } = authInfo;
|
|
90
|
+
|
|
91
|
+
// Validate organization ID if required
|
|
92
|
+
if (validateOrg && !validateOrganizationId(authData.credentials?.customer_id)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return await validateAccessToken(accessToken);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Authenticate a request for regular functions (with organization validation)
|
|
101
|
+
*
|
|
102
|
+
* @param request - The incoming request
|
|
103
|
+
* @returns true if authentication and authorization succeed
|
|
104
|
+
*/
|
|
105
|
+
export async function authenticateRegularRequest(request: any): Promise<boolean> {
|
|
106
|
+
return await authenticateRequest(request, true);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Authenticate a request for global functions (without organization validation)
|
|
111
|
+
*
|
|
112
|
+
* @param request - The incoming request
|
|
113
|
+
* @returns true if authentication succeeds
|
|
114
|
+
*/
|
|
115
|
+
export async function authenticateGlobalRequest(request: any): Promise<boolean> {
|
|
116
|
+
return await authenticateRequest(request, false);
|
|
66
117
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GlobalFunction, Response, amendLogContext } from '@zaiusinc/app-sdk';
|
|
2
|
-
import {
|
|
2
|
+
import { authenticateGlobalRequest } from '../auth/AuthUtils';
|
|
3
3
|
import { toolsService } from '../service/Service';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -41,21 +41,9 @@ export abstract class GlobalToolFunction extends GlobalFunction {
|
|
|
41
41
|
/**
|
|
42
42
|
* Authenticate the incoming request by validating only the OptiID token
|
|
43
43
|
*
|
|
44
|
-
* @param request - The incoming request
|
|
45
44
|
* @returns true if authentication succeeds
|
|
46
45
|
*/
|
|
47
46
|
private async authorizeRequest(): Promise<boolean> {
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const authInfo = AuthUtils.extractAuthData(this.request);
|
|
53
|
-
if (!authInfo) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const { accessToken } = authInfo;
|
|
58
|
-
|
|
59
|
-
return await AuthUtils.validateAccessToken(accessToken);
|
|
47
|
+
return await authenticateGlobalRequest(this.request);
|
|
60
48
|
}
|
|
61
49
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Function, Response, amendLogContext } from '@zaiusinc/app-sdk';
|
|
2
|
-
import {
|
|
2
|
+
import { authenticateRegularRequest } from '../auth/AuthUtils';
|
|
3
3
|
import { toolsService } from '../service/Service';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -40,25 +40,9 @@ export abstract class ToolFunction extends Function {
|
|
|
40
40
|
/**
|
|
41
41
|
* Authenticate the incoming request by validating the OptiID token and organization ID
|
|
42
42
|
*
|
|
43
|
-
* @param request - The incoming request
|
|
44
43
|
* @returns true if authentication succeeds
|
|
45
44
|
*/
|
|
46
45
|
private async authorizeRequest(): Promise<boolean> {
|
|
47
|
-
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const authInfo = AuthUtils.extractAuthData(this.request);
|
|
52
|
-
if (!authInfo) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const { authData, accessToken } = authInfo;
|
|
57
|
-
|
|
58
|
-
if (!AuthUtils.validateOrganizationId(authData.credentials?.customer_id)) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return await AuthUtils.validateAccessToken(accessToken);
|
|
46
|
+
return await authenticateRegularRequest(this.request);
|
|
63
47
|
}
|
|
64
48
|
}
|