Skip to content

Commit b3b1f65

Browse files
authored
add the support for every possible issuer in Single Tenant for emulator (#4847)
1 parent 31c72e9 commit b3b1f65

File tree

4 files changed

+81
-13
lines changed

4 files changed

+81
-13
lines changed

libraries/botframework-connector/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"botbuilder-test-utils": "0.0.0",
5050
"dotenv": "^16.4.5",
5151
"nock": "^13.5.5",
52-
"should": "^13.2.3"
52+
"should": "^13.2.3",
53+
"uuid": "^11.0.5"
5354
},
5455
"scripts": {
5556
"build": "tsc -b",

libraries/botframework-connector/src/auth/emulatorValidation.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -75,28 +75,29 @@ export namespace EmulatorValidation {
7575
return false;
7676
}
7777

78+
const validTokenIssuers = ToBotFromBotOrEmulatorTokenValidationParameters.issuer;
79+
7880
//Validation to manage the issuer object as a string.
79-
if (Array.isArray(ToBotFromBotOrEmulatorTokenValidationParameters.issuer)) {
81+
if (Array.isArray(validTokenIssuers)) {
8082
const tenantId = token?.payload[AuthenticationConstants.TenantIdClaim] ?? '';
8183

8284
//Validate if there is an existing issuer with the same tid value.
83-
if (
84-
tenantId != '' &&
85-
ToBotFromBotOrEmulatorTokenValidationParameters.issuer.find((issuer) => issuer.includes(tenantId)) ==
86-
null
87-
) {
85+
if (tenantId != '' && validTokenIssuers.find((issuer) => issuer.includes(tenantId)) == null) {
8886
//If the issuer doesn't exist, this is added using the Emulator token issuer structure.
8987
//This allows use of the SingleTenant authentication through Emulator.
90-
const newIssuer = AuthenticationConstants.ValidTokenIssuerUrlTemplateV1 + `${tenantId}/`;
91-
ToBotFromBotOrEmulatorTokenValidationParameters.issuer.push(newIssuer);
88+
validTokenIssuers.push(`${AuthenticationConstants.ValidTokenIssuerUrlTemplateV1}${tenantId}/`);
89+
validTokenIssuers.push(`${AuthenticationConstants.ValidTokenIssuerUrlTemplateV2}${tenantId}/v2.0`);
90+
validTokenIssuers.push(
91+
`${AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1}${tenantId}/`,
92+
);
93+
validTokenIssuers.push(
94+
`${AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2}${tenantId}/v2.0`,
95+
);
9296
}
9397
}
9498

9599
// Is the token issues by a source we consider to be the emulator?
96-
if (
97-
ToBotFromEmulatorTokenValidationParameters.issuer &&
98-
ToBotFromEmulatorTokenValidationParameters.issuer.indexOf(issuer) === -1
99-
) {
100+
if (validTokenIssuers && validTokenIssuers.indexOf(issuer) === -1) {
100101
// Not a Valid Issuer. This is NOT a Bot Framework Emulator Token.
101102
return false;
102103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const jwt = require('jsonwebtoken');
2+
const { v4: uuidv4 } = require('uuid');
3+
const { EmulatorValidation, AuthenticationConstants } = require('../..');
4+
const { strictEqual } = require('assert');
5+
6+
function generateMockBearerToken(issuer) {
7+
const secretKey = 'ThisIsASuperMockSecretKey123456789';
8+
const tenantId = uuidv4();
9+
const completeIssuer = issuer ? issuer.replace('{0}', tenantId) : null;
10+
11+
const payload = {
12+
name: 'John Doe',
13+
role: 'Admin',
14+
tid: tenantId,
15+
iss: completeIssuer,
16+
aud: 'https://api.example.com',
17+
};
18+
19+
const options = {
20+
expiresIn: '1h',
21+
};
22+
23+
return `Bearer ${jwt.sign(payload, secretKey, options)}`;
24+
}
25+
26+
describe('EmulatorValidation', function () {
27+
it('should return false on token BadFormat', function () {
28+
// Token with bad format is not processed
29+
let authHeader = '';
30+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), false);
31+
32+
// If the token doesn't contain an issuer value, it returns false
33+
authHeader = generateMockBearerToken(null);
34+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), false);
35+
});
36+
37+
it('should return false on invalid token issuer', function () {
38+
const authHeader = generateMockBearerToken('https://mockIssuer.com');
39+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), false);
40+
});
41+
42+
it('should return true on valid token issuer', function () {
43+
// Validate issuer with V1 Token
44+
let authHeader = generateMockBearerToken(`${AuthenticationConstants.ValidTokenIssuerUrlTemplateV1}{0}/`);
45+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), true);
46+
47+
// Validate issuer with V2 Token
48+
authHeader = generateMockBearerToken(`${AuthenticationConstants.ValidTokenIssuerUrlTemplateV2}{0}/v2.0`);
49+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), true);
50+
51+
// Validate Government issuer with V1 Token
52+
authHeader = generateMockBearerToken(`${AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1}{0}/`);
53+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), true);
54+
55+
// Validate Government issuer with V2 Token
56+
authHeader = generateMockBearerToken(
57+
`${AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2}{0}/v2.0`,
58+
);
59+
strictEqual(EmulatorValidation.isTokenFromEmulator(authHeader), true);
60+
});
61+
});

yarn.lock

+5
Original file line numberDiff line numberDiff line change
@@ -15502,6 +15502,11 @@ uuid@^10.0.0:
1550215502
resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294"
1550315503
integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==
1550415504

15505+
uuid@^11.0.5:
15506+
version "11.0.5"
15507+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.0.5.tgz#07b46bdfa6310c92c3fb3953a8720f170427fc62"
15508+
integrity sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==
15509+
1550515510
uuid@^3.3.3:
1550615511
version "3.4.0"
1550715512
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"

0 commit comments

Comments
 (0)