Skip to content

Commit d6e3f74

Browse files
authored
Merge pull request #55 from ruromero/feat/generic-scripts
feat!: make authentication generic and add scripts
2 parents 4c9616b + d3e4c2e commit d6e3f74

16 files changed

+354
-495
lines changed

README.md

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -51,60 +51,25 @@ This node currently supports the following operations:
5151

5252
## Credentials
5353

54-
This node supports two OAuth2 credential types for authenticating with Red Hat Dependency Analytics:
54+
This node supports Client Credentials OAuth2 type for authenticating with Red Hat Dependency Analytics.
5555

56-
### 1. Trustify (Authorization Code - User Authentication) OAuth2 API
56+
### RHTPA Client Credentials
5757

58-
**Purpose:** User authentication flow where individual users authenticate through Red Hat SSO. This is ideal for interactive workflows where users need to authenticate themselves.
58+
- Use when connecting to RHTPA cloud services
59+
- Required parameters: (Provided by the RHTPA team upon request)
60+
- Client ID
61+
- Client Secret
5962

60-
**Configuration:**
61-
- **Authorization URL:** `https://sso.example.com/auth/realms/trustify/protocol/openid-connect/auth`
62-
- **Access Token URL:** `https://sso.example.com/auth/realms/trustify/protocol/openid-connect/token`
63-
- **Grant Type:** `authorizationCode`
64-
- **Authentication:** `header`
63+
### Trustify Client Credentials
6564

66-
### 2. Trustify Client Credentials (Machine-to-Machine) OAuth2 API
67-
68-
**Purpose:** Machine-to-machine authentication using client credentials. This is ideal for automated workflows, CI/CD pipelines, and server-to-server communication where no user interaction is required.
69-
70-
**Configuration:**
71-
- **Access Token URL:** `https://sso.example.com/auth/realms/trustify/protocol/openid-connect/token`
72-
- **Grant Type:** `clientCredentials`
73-
- **Authentication:** `header`
74-
75-
### Environment Variables
76-
77-
Both credential types support the following environment variables for configuration:
78-
79-
| Environment Variable | Description | Default Value |
80-
|---------------------|-------------|---------------|
81-
| `TRUSTIFY_SSO_URL` | Base SSO URL (suffixed with `/protocol/openid-connect/auth` and `/protocol/openid-connect/token`) | `https://sso.example.com/auth/realms/trustify` |
82-
| `TRUSTIFY_CLIENT_ID` | OAuth2 client ID | Empty string |
83-
| `TRUSTIFY_CLIENT_SECRET` | OAuth2 client secret | Empty string |
84-
| `TRUSTIFY_SCOPE` | OAuth2 scopes (space-separated) | `openid` |
85-
86-
**Note:** When `TRUSTIFY_SSO_URL` is defined, it automatically generates:
87-
- Authorization URL: `${TRUSTIFY_SSO_URL}/protocol/openid-connect/auth`
88-
- Access Token URL: `${TRUSTIFY_SSO_URL}/protocol/openid-connect/token`
89-
90-
### Environment Variable Behavior
91-
92-
- **When defined:** The corresponding credential field becomes hidden in the n8n UI and uses the environment variable value
93-
- **When not defined:** The credential field is visible in the n8n UI and can be configured manually
94-
95-
### Choosing Between Credential Types
96-
97-
- **Use Authorization Code OAuth2** when:
98-
- Users need to authenticate individually
99-
- Interactive workflows requiring user consent
100-
- Personal or user-specific data access
101-
102-
- **Use Client Credentials OAuth2** when:
103-
- Automated workflows and CI/CD pipelines
104-
- Server-to-server communication
105-
- No user interaction required
106-
- Service account authentication
65+
- Use when connecting to:
66+
- On premise Trustify instance
67+
- Local development
68+
- It requires that in your SSO provider a confidential client exists
69+
- The Trustify instance accepts this client id
70+
- The Trustify instance can map the client or scope to the necessary permissions
10771

72+
For more information refer to the [Trustify - OIDC Docs](https://github.com/guacsec/trustify/blob/main/docs/oidc.md)
10873

10974
## Compatibility
11075

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { ICredentialType, INodeProperties } from 'n8n-workflow';
2+
3+
export class RHTPAClientCredsOAuth2Api implements ICredentialType {
4+
name = 'rhtpaClientCredsOAuth2Api';
5+
displayName = 'Red Hat Trusted Profile Analyzer (Client Credentials) OAuth2 API';
6+
documentationUrl = 'https://access.redhat.com/products/red-hat-trusted-profile-analyzer';
7+
extends = ['oAuth2Api'];
8+
properties: INodeProperties[] = [
9+
{
10+
displayName: 'Access Token URL',
11+
name: 'accessTokenUrl',
12+
type: 'hidden' as const,
13+
default: 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token',
14+
description: 'URL for exchanging credentials for access token',
15+
required: true,
16+
},
17+
{
18+
displayName: 'Client ID',
19+
name: 'clientId',
20+
type: 'string' as const,
21+
default: '',
22+
description: 'OAuth2 client ID',
23+
required: true,
24+
},
25+
{
26+
displayName: 'Client Secret',
27+
name: 'clientSecret',
28+
type: 'string' as const,
29+
default: '',
30+
description: 'OAuth2 client secret',
31+
required: true,
32+
typeOptions: { password: true },
33+
},
34+
{
35+
displayName: 'Scope',
36+
name: 'scope',
37+
type: 'hidden' as const,
38+
default: 'openid',
39+
description: 'OAuth2 scopes to request (space-separated)',
40+
required: true,
41+
placeholder: 'e.g. openid',
42+
},
43+
{
44+
displayName: 'Grant Type',
45+
name: 'grantType',
46+
type: 'hidden' as const,
47+
default: 'clientCredentials',
48+
},
49+
{
50+
displayName: 'Authentication',
51+
name: 'authentication',
52+
type: 'hidden' as const,
53+
default: 'header',
54+
},
55+
];
56+
}

credentials/TrustifyAuthCodeOAuth2Api.credentials.ts

Lines changed: 0 additions & 68 deletions
This file was deleted.

credentials/TrustifyClientCredsOAuth2Api.credentials.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,41 @@ import { ICredentialType, INodeProperties } from 'n8n-workflow';
22

33
export class TrustifyClientCredsOAuth2Api implements ICredentialType {
44
name = 'trustifyClientCredsOAuth2Api';
5-
displayName = 'Trustify Client Credentials (Machine-to-Machine) OAuth2 API';
5+
displayName = 'Trustify (Client Credentials) OAuth2 API';
66
documentationUrl = 'https://access.redhat.com/products/red-hat-trusted-profile-analyzer';
77
extends = ['oAuth2Api'];
88
properties: INodeProperties[] = [
99
{
1010
displayName: 'Access Token URL',
1111
name: 'accessTokenUrl',
12-
type: process.env['TRUSTIFY_SSO_URL'] ? ('hidden' as const) : ('string' as const),
13-
default: process.env['TRUSTIFY_SSO_URL']
14-
? `${process.env['TRUSTIFY_SSO_URL']}/protocol/openid-connect/token`
15-
: 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token',
12+
type: 'string' as const,
13+
default: 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token',
1614
description: 'URL for exchanging credentials for access token',
1715
required: true,
1816
},
1917
{
2018
displayName: 'Client ID',
2119
name: 'clientId',
22-
type: process.env['TRUSTIFY_CLIENT_ID'] ? ('hidden' as const) : ('string' as const),
23-
default: process.env['TRUSTIFY_CLIENT_ID'] ?? '',
20+
type: 'string' as const,
21+
default: '',
2422
description: 'OAuth2 client ID',
2523
required: true,
2624
},
2725
{
2826
displayName: 'Client Secret',
2927
name: 'clientSecret',
30-
type: process.env['TRUSTIFY_CLIENT_SECRET'] ? ('hidden' as const) : ('string' as const),
31-
default: process.env['TRUSTIFY_CLIENT_SECRET'] ?? '',
28+
type: 'string' as const,
29+
default: '',
3230
description: 'OAuth2 client secret',
3331
required: true,
3432
typeOptions: { password: true },
3533
},
3634
{
3735
displayName: 'Scope',
3836
name: 'scope',
39-
type: process.env['TRUSTIFY_SCOPE'] ? ('hidden' as const) : ('string' as const),
40-
default: process.env['TRUSTIFY_SCOPE'] ?? 'openid',
41-
description: 'Scopes to request (space-separated)',
37+
type: 'string' as const,
38+
default: 'openid',
39+
description: 'OAuth2 scopes to request (space-separated)',
4240
required: true,
4341
placeholder: 'e.g. openid',
4442
},

nodes/DependencyAnalytics/DependencyAnalytics.node.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ import {
1010
import { properties } from './descriptions';
1111
import { dispatch } from './actions';
1212

13-
const trustifyCredentials: INodeCredentialDescription[] = [
13+
const credentials: INodeCredentialDescription[] = [
1414
{
1515
name: 'trustifyClientCredsOAuth2Api',
1616
required: true,
1717
displayOptions: {
1818
show: {
19-
authMethod: ['clientCredentials'],
19+
authMethod: ['trustifyClientCredentials'],
2020
},
2121
},
2222
},
2323
{
24-
name: 'trustifyAuthCodeOAuth2Api',
24+
name: 'rhtpaClientCredsOAuth2Api',
2525
required: true,
2626
displayOptions: {
2727
show: {
28-
authMethod: ['authorizationCode'],
28+
authMethod: ['rhtpaClientCredentials'],
2929
},
3030
},
3131
},
@@ -46,10 +46,9 @@ export class DependencyAnalytics implements INodeType {
4646
inputs: [NodeConnectionType.Main],
4747
outputs: [NodeConnectionType.Main],
4848
usableAsTool: true,
49-
credentials: trustifyCredentials,
49+
credentials: credentials,
5050
requestDefaults: {
51-
// baseURL: 'https://server-tpa.apps.tpaqe-1.lab.eng.rdu2.redhat.com',
52-
baseURL: process.env['TRUSTIFY_BASE_URL'] || 'https://rhtpa.stage.redhat.com/api/v2/',
51+
baseURL: 'https://rhtpa.stage.redhat.com/api/v2/',
5352
headers: {
5453
Accept: 'application/json',
5554
'Content-Type': 'application/json',

nodes/DependencyAnalytics/Properties.spec.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@ describe('Tests for common.properties.ts', () => {
1414
const authMethod = commonProperties.find((p) => p.name === 'authMethod');
1515
expect(authMethod).toBeDefined();
1616
expect(authMethod?.type).toBe('options');
17+
expect(authMethod?.options).toHaveLength(2);
1718
expect(authMethod?.options).toEqual(
1819
expect.arrayContaining([
19-
expect.objectContaining({ name: 'Authorization Code', value: 'authorizationCode' }),
20-
expect.objectContaining({ name: 'Client Credentials', value: 'clientCredentials' }),
20+
expect.objectContaining({
21+
name: 'Trustify Client Credentials',
22+
value: 'trustifyClientCredentials',
23+
}),
24+
expect.objectContaining({
25+
name: 'RHTPA Client Credentials',
26+
value: 'rhtpaClientCredentials',
27+
}),
2128
]),
2229
);
23-
expect(authMethod?.default).toBe('authorizationCode');
30+
expect(authMethod?.default).toBe('rhtpaClientCredentials');
2431
});
2532

2633
test('It should include baseURL property with default and description', () => {

nodes/DependencyAnalytics/Utils.spec.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,11 @@ describe('Tests for http.ts', () => {
424424
getNodeParameter: jest.fn().mockReturnValue('https://api.foobar.com///'),
425425
};
426426
const result = getBase(mockCtx as any, 0);
427-
expect(mockCtx.getNodeParameter).toHaveBeenCalledWith('baseURL', 0);
427+
expect(mockCtx.getNodeParameter).toHaveBeenCalledWith(
428+
'baseURL',
429+
0,
430+
'https://rhtpa.stage.devshift.net/api/v2/',
431+
);
428432
expect(result).toBe('https://api.foobar.com');
429433
});
430434

@@ -436,9 +440,9 @@ describe('Tests for http.ts', () => {
436440
expect(result).toBe('https://api.foobar.com');
437441
});
438442

439-
test('It should return `trustifyClientOAuth2Api`', () => {
443+
test('It should return `trustifyClientCredsOAuth2Api`', () => {
440444
const mockCtx = {
441-
getNodeParameter: jest.fn().mockReturnValue('clientCredentials'),
445+
getNodeParameter: jest.fn().mockReturnValue('trustifyClientCredentials'),
442446
};
443447
const result = chooseCredential(mockCtx as any, 1);
444448
expect(result).toBe('trustifyClientCredsOAuth2Api');

nodes/DependencyAnalytics/descriptions/common.properties.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,26 @@ export const commonProperties: INodeProperties[] = [
66
name: 'authMethod',
77
type: 'options',
88
options: [
9-
{ name: 'Authorization Code', value: 'authorizationCode' },
10-
{ name: 'Client Credentials', value: 'clientCredentials' },
9+
{ name: 'Trustify Client Credentials', value: 'trustifyClientCredentials' },
10+
{ name: 'RHTPA Client Credentials', value: 'rhtpaClientCredentials' },
1111
],
12-
default: 'authorizationCode',
13-
description: 'Choose how to authenticate to Trustify API',
12+
default: 'rhtpaClientCredentials',
13+
description: 'Choose how to authenticate to the API',
14+
required: true,
1415
},
1516
{
1617
displayName: 'Base URL',
1718
name: 'baseURL',
1819
type: 'string',
1920
default: 'http://localhost:8080/api/v2/',
20-
placeholder: 'e.g. https://your-trustify-instance.com/api/v2/',
21+
placeholder: 'e.g. http://localhost:8080/api/v2/',
2122
description: 'The base URL for your Trustify API instance',
2223
required: true,
24+
displayOptions: {
25+
show: {
26+
authMethod: ['trustifyClientCredentials'],
27+
},
28+
},
2329
},
2430
{
2531
displayName: 'Resource',

0 commit comments

Comments
 (0)