Skip to content

Commit 3af6f10

Browse files
committed
feat(auth): add EntraId integration tests
- Add integration tests for token renewal and re-authentication flows - Update credentials provider to use uniqueId as username instead of account username - Add test utilities for loading Redis endpoint configurations - Split TypeScript configs into separate files for samples and integration tests
1 parent ac972bd commit 3af6f10

File tree

7 files changed

+118
-6
lines changed

7 files changed

+118
-6
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { BasicAuth } from '@redis/authx';
2+
import { createClient } from '@redis/client';
3+
import { EntraIdCredentialsProviderFactory } from '../lib/entra-id-credentials-provider-factory';
4+
import { strict as assert } from 'node:assert';
5+
import { spy } from 'sinon';
6+
import { randomUUID } from 'crypto';
7+
import { loadFromJson } from '@redis/test-utils/lib/cae-client-testing'
8+
9+
describe('EntraID Integration Tests', () => {
10+
11+
it('should automatically re-authenticate when token is renewed', async () => {
12+
13+
if (!process.env.REDIS_ENDPOINTS_CONFIG_PATH) {
14+
throw new Error('REDIS_ENDPOINTS_CONFIG_PATH environment variable must be set');
15+
}
16+
if (!process.env.AZURE_CLIENT_ID) {
17+
throw new Error('AZURE_CLIENT_ID environment variable must be set');
18+
}
19+
if (!process.env.AZURE_TENANT_ID) {
20+
throw new Error('AZURE_TENANT_ID environment variable must be set');
21+
}
22+
if (!process.env.AZURE_CLIENT_SECRET) {
23+
throw new Error('AZURE_CLIENT_SECRET environment variable must be set');
24+
}
25+
26+
const endpoints = loadFromJson(process.env.REDIS_ENDPOINTS_CONFIG_PATH)
27+
const clientId = process.env.AZURE_CLIENT_ID;
28+
const tenantId = process.env.AZURE_TENANT_ID;
29+
const clientSecret = process.env.AZURE_CLIENT_SECRET;
30+
31+
const entraidCredentialsProvider = EntraIdCredentialsProviderFactory.createForClientCredentials({
32+
clientId: clientId,
33+
clientSecret: clientSecret,
34+
authorityConfig: { type: 'multi-tenant', tenantId: tenantId },
35+
tokenManagerConfig: {
36+
expirationRefreshRatio: 0.001
37+
}
38+
});
39+
40+
const client = createClient({
41+
url: endpoints['standalone-entraid-acl'].endpoints[0],
42+
credentialsProvider: entraidCredentialsProvider
43+
});
44+
45+
const reAuthSpy = spy(client, <any>'reAuthenticate');
46+
47+
try {
48+
await client.connect();
49+
50+
const startTime = Date.now();
51+
while (Date.now() - startTime < 200) {
52+
const key = randomUUID();
53+
await client.set(key, 'value');
54+
const value = await client.get(key);
55+
assert.equal(value, 'value');
56+
await client.del(key);
57+
}
58+
59+
assert(reAuthSpy.callCount >= 1, `reAuthenticate should have been called at least once, but was called ${reAuthSpy.callCount} times`);
60+
61+
const uniqueCredentials = new Set(
62+
reAuthSpy.getCalls().map(call => {
63+
const creds = call.args[0] as BasicAuth;
64+
return `${creds.username}:${creds.password}`;
65+
})
66+
);
67+
68+
assert.equal(
69+
uniqueCredentials.size,
70+
reAuthSpy.callCount,
71+
`Expected ${reAuthSpy.callCount} different credentials, but got ${uniqueCredentials.size} unique credentials`
72+
);
73+
74+
} finally {
75+
client.destroy();
76+
}
77+
});
78+
});

packages/entraid/lib/entraid-credentials-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class EntraidCredentialsProvider implements StreamingCredentialsProvider
3434
this.onReAuthenticationError = options.onReAuthenticationError ??
3535
((error) => console.error('ReAuthenticationError', error));
3636
this.credentialsMapper = options.credentialsMapper ?? ((token) => ({
37-
username: token.account?.username ?? undefined,
37+
username: token.uniqueId,
3838
password: token.accessToken
3939
}));
4040

packages/entraid/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"scripts": {
1212
"clean": "rimraf dist",
1313
"build": "npm run clean && tsc",
14-
"start:auth-pkce": "npm run build && node dist/samples/auth-code-pkce/index.js",
14+
"start:auth-pkce": "tsx --tsconfig tsconfig.samples.json ./samples/auth-code-pkce/index.ts",
15+
"test-integration": "mocha -r tsx --tsconfig tsconfig.integration-tests.json './integration-tests/**/*.spec.ts'",
1516
"test": "nyc -r text-summary -r lcov mocha -r tsx './lib/**/*.spec.ts'"
1617
},
1718
"dependencies": {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"include": [
4+
"./integration-tests/**/*.ts",
5+
"./lib/**/*.ts"
6+
],
7+
"compilerOptions": {
8+
"noEmit": true
9+
},
10+
}

packages/entraid/tsconfig.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44
"outDir": "./dist"
55
},
66
"include": [
7-
"./samples/**/*.ts",
87
"./lib/**/*.ts"
98
],
109
"exclude": [
11-
"./lib/test-utils.ts",
1210
"./lib/**/*.spec.ts",
13-
"./lib/sentinel/test-util.ts"
11+
"./lib/test-util.ts",
1412
],
1513
"typedocOptions": {
1614
"entryPoints": [
17-
"./index.ts",
1815
"./lib"
1916
],
2017
"entryPointStrategy": "expand",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"include": [
4+
"./samples/**/*.ts",
5+
"./lib/**/*.ts"
6+
],
7+
"compilerOptions": {
8+
"noEmit": true
9+
}
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
interface RawRedisEndpoint {
2+
username?: string;
3+
password?: string;
4+
tls: boolean;
5+
endpoints: string[];
6+
}
7+
8+
type RedisEndpointsConfig = Record<string, RawRedisEndpoint>;
9+
10+
export function loadFromJson(jsonString: string): RedisEndpointsConfig {
11+
try {
12+
return JSON.parse(jsonString) as RedisEndpointsConfig;
13+
} catch (error) {
14+
throw new Error(`Invalid JSON configuration: ${error}`);
15+
}
16+
}

0 commit comments

Comments
 (0)