• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

microsoft / botbuilder-js / 7587095843

19 Jan 2024 05:24PM CUT coverage: 84.477%. Remained the same
7587095843

push

github

web-flow
feat: Add isVisible property to AceData (#4606)

* Add isVisible property to AceData

* extra comment

* updated md

---------

Co-authored-by: aterentiev <aterentiev@microsoft.com_odspmdb>

9984 of 13103 branches covered (0.0%)

Branch coverage included in aggregate %.

20411 of 22877 relevant lines covered (89.22%)

7205.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.21
/libraries/botframework-connector/src/auth/parameterizedBotFrameworkAuthentication.ts
1
// Copyright (c) Microsoft Corporation.
2
// Licensed under the MIT License.
3

4
import { Activity, Channels, RoleTypes, StatusCodes } from 'botframework-schema';
2✔
5
import { AuthenticateRequestResult } from './authenticateRequestResult';
6
import type { AuthenticationConfiguration } from './authenticationConfiguration';
7
import { AuthenticationConstants } from './authenticationConstants';
2✔
8
import { AuthenticationError } from './authenticationError';
2✔
9
import { BotFrameworkAuthentication } from './botFrameworkAuthentication';
2✔
10
import { ConnectorClientOptions } from '../connectorApi/models';
11
import type { ConnectorFactory } from './connectorFactory';
12
import { ConnectorFactoryImpl } from './connectorFactoryImpl';
2✔
13
import type { BotFrameworkClient } from '../skills';
14
import { BotFrameworkClientImpl } from './botFrameworkClientImpl';
2✔
15
import { Claim, ClaimsIdentity } from './claimsIdentity';
2✔
16
import { EmulatorValidation } from './emulatorValidation';
2✔
17
import { JwtTokenExtractor } from './jwtTokenExtractor';
2✔
18
import { JwtTokenValidation } from './jwtTokenValidation';
2✔
19
import type { ServiceClientCredentialsFactory } from './serviceClientCredentialsFactory';
20
import { SkillValidation } from './skillValidation';
2✔
21
import { ToBotFromBotOrEmulatorTokenValidationParameters } from './tokenValidationParameters';
2✔
22
import { UserTokenClientImpl } from './userTokenClientImpl';
2✔
23
import type { UserTokenClient } from './userTokenClient';
24
import { VerifyOptions } from 'jsonwebtoken';
25
import { AseChannelValidation } from './aseChannelValidation';
2✔
26

27
function getAppId(claimsIdentity: ClaimsIdentity): string | undefined {
28
    // For requests from channel App Id is in Audience claim of JWT token. For emulator it is in AppId claim. For
29
    // unauthenticated requests we have anonymous claimsIdentity provided auth is disabled.
30
    // For Activities coming from Emulator AppId claim contains the Bot's AAD AppId.
31
    return (
22✔
32
        claimsIdentity.getClaimValue(AuthenticationConstants.AudienceClaim) ??
100✔
33
        claimsIdentity.getClaimValue(AuthenticationConstants.AppIdClaim) ??
22!
34
        undefined
35
    );
36
}
37

38
/**
39
 * @internal
40
 * Parameterized [BotFrameworkAuthentication](xref:botframework-connector.BotFrameworkAuthentication) used to authenticate Bot Framework Protocol network calls within this environment.
41
 */
42
export class ParameterizedBotFrameworkAuthentication extends BotFrameworkAuthentication {
2✔
43
    /**
44
     * @param validateAuthority The validate authority value to use.
45
     * @param toChannelFromBotLoginUrl The to Channel from bot login url.
46
     * @param toChannelFromBotOAuthScope The to Channel from bot oauth scope.
47
     * @param toBotFromChannelTokenIssuer The to bot from Channel Token Issuer.
48
     * @param oAuthUrl The OAuth url.
49
     * @param toBotFromChannelOpenIdMetadataUrl The to bot from Channel Open Id Metadata url.
50
     * @param toBotFromEmulatorOpenIdMetadataUrl The to bot from Emulator Open Id Metadata url.
51
     * @param callerId The callerId set on an authenticated [Activities](xref:botframework-schema.Activity).
52
     * @param credentialsFactory The [ServiceClientCredentialsFactory](xref:botframework-connector.ServiceClientCredentialsFactory) to use to create credentials.
53
     * @param authConfiguration The [AuthenticationConfiguration](xref:botframework-connector.AuthenticationConfiguration) to use.
54
     * @param botFrameworkClientFetch The fetch to use in BotFrameworkClient.
55
     * @param connectorClientOptions The [ConnectorClientOptions](xref:botframework-connector.ConnectorClientOptions) to use when creating ConnectorClients.
56
     */
57
    constructor(
58
        private readonly validateAuthority: boolean,
36✔
59
        private readonly toChannelFromBotLoginUrl: string,
36✔
60
        private readonly toChannelFromBotOAuthScope: string,
36✔
61
        private readonly toBotFromChannelTokenIssuer: string,
36✔
62
        private readonly oAuthUrl: string,
36✔
63
        private readonly toBotFromChannelOpenIdMetadataUrl: string,
36✔
64
        private readonly toBotFromEmulatorOpenIdMetadataUrl: string,
36✔
65
        private readonly callerId: string,
36✔
66
        private readonly credentialsFactory: ServiceClientCredentialsFactory,
36✔
67
        private readonly authConfiguration: AuthenticationConfiguration,
36✔
68
        private readonly botFrameworkClientFetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>,
36✔
69
        private readonly connectorClientOptions: ConnectorClientOptions = {}
36!
70
    ) {
71
        super();
36✔
72
    }
73

74
    /**
75
     * Gets the originating audience from Bot OAuth scope.
76
     *
77
     * @returns The originating audience.
78
     */
79
    getOriginatingAudience(): string {
80
        return this.toChannelFromBotOAuthScope;
8✔
81
    }
82

83
    /**
84
     * @param authHeader The http auth header received in the skill request.
85
     * @returns The identity validation result.
86
     */
87
    async authenticateChannelRequest(authHeader: string): Promise<ClaimsIdentity> {
88
        if (!authHeader.trim()) {
×
89
            const isAuthDisabled = await this.credentialsFactory.isAuthenticationDisabled();
×
90
            if (!isAuthDisabled) {
×
91
                throw new AuthenticationError(
×
92
                    'Unauthorized Access. Request is not authorized',
93
                    StatusCodes.UNAUTHORIZED
94
                );
95
            }
96

97
            // In the scenario where auth is disabled, we still want to have the isAuthenticated flag set in the
98
            // ClaimsIdentity. To do this requires adding in an empty claim. Since ChannelServiceHandler calls are
99
            // always a skill callback call, we set the skill claim too.
100
            return SkillValidation.createAnonymousSkillClaim();
×
101
        }
102

103
        return this.JwtTokenValidation_validateAuthHeader(authHeader, 'unknown', null);
×
104
    }
105

106
    /**
107
     * Validate Bot Framework Protocol requests.
108
     *
109
     * @param activity The inbound Activity.
110
     * @param authHeader The http auth header received in the skill request.
111
     * @returns Promise with AuthenticateRequestResult.
112
     */
113
    async authenticateRequest(activity: Activity, authHeader: string): Promise<AuthenticateRequestResult> {
114
        const claimsIdentity = await this.JwtTokenValidation_authenticateRequest(activity, authHeader);
×
115

116
        const outboundAudience = SkillValidation.isSkillClaim(claimsIdentity.claims)
×
117
            ? JwtTokenValidation.getAppIdFromClaims(claimsIdentity.claims)
×
118
            : this.toChannelFromBotOAuthScope;
119

120
        const callerId = await this.generateCallerId(this.credentialsFactory, claimsIdentity, this.callerId);
×
121

122
        const connectorFactory = new ConnectorFactoryImpl(
×
123
            getAppId(claimsIdentity),
124
            this.toChannelFromBotOAuthScope,
125
            this.toChannelFromBotLoginUrl,
126
            this.validateAuthority,
127
            this.credentialsFactory,
128
            this.connectorClientOptions
129
        );
130

131
        return {
×
132
            audience: outboundAudience,
133
            callerId,
134
            claimsIdentity,
135
            connectorFactory,
136
        };
137
    }
138

139
    /**
140
     * Validate Bot Framework Protocol requests.
141
     *
142
     * @param authHeader The http auth header received in the skill request.
143
     * @param channelIdHeader The channel Id HTTP header.
144
     * @returns Promise with AuthenticateRequestResult.
145
     */
146
    async authenticateStreamingRequest(
147
        authHeader: string,
148
        channelIdHeader: string
149
    ): Promise<AuthenticateRequestResult> {
150
        if (!channelIdHeader?.trim() && !(await this.credentialsFactory.isAuthenticationDisabled())) {
×
151
            throw new AuthenticationError("'channelIdHeader' required.", StatusCodes.UNAUTHORIZED);
×
152
        }
153

154
        const claimsIdentity = await this.JwtTokenValidation_validateAuthHeader(authHeader, channelIdHeader, null);
×
155
        const outboundAudience = SkillValidation.isSkillClaim(claimsIdentity.claims)
×
156
            ? JwtTokenValidation.getAppIdFromClaims(claimsIdentity.claims)
×
157
            : this.toChannelFromBotOAuthScope;
158
        const callerId = await this.generateCallerId(this.credentialsFactory, claimsIdentity, this.callerId);
×
159

160
        return { audience: outboundAudience, callerId, claimsIdentity };
×
161
    }
162

163
    /**
164
     * Creates the appropriate UserTokenClient instance.
165
     *
166
     * @param claimsIdentity The inbound Activity's ClaimsIdentity.
167
     * @returns Promise with UserTokenClient instance.
168
     */
169
    async createUserTokenClient(claimsIdentity: ClaimsIdentity): Promise<UserTokenClient> {
170
        const appId = getAppId(claimsIdentity);
14✔
171
        const credentials = await this.credentialsFactory.createCredentials(
14✔
172
            appId,
173
            this.toChannelFromBotOAuthScope,
174
            this.toChannelFromBotLoginUrl,
175
            this.validateAuthority
176
        );
177

178
        return new UserTokenClientImpl(appId, credentials, this.oAuthUrl, this.connectorClientOptions);
14✔
179
    }
180

181
    /**
182
     * Creates a ConnectorFactory that can be used to create ConnectorClients that can use credentials from this particular Cloud Environment.
183
     *
184
     * @param claimsIdentity The inbound Activity's ClaimsIdentity.
185
     * @returns A ConnectorFactory.
186
     */
187
    createConnectorFactory(claimsIdentity: ClaimsIdentity): ConnectorFactory {
188
        return new ConnectorFactoryImpl(
8✔
189
            getAppId(claimsIdentity),
190
            this.toChannelFromBotOAuthScope,
191
            this.toChannelFromBotLoginUrl,
192
            this.validateAuthority,
193
            this.credentialsFactory,
194
            this.connectorClientOptions
195
        );
196
    }
197

198
    /**
199
     * Creates a BotFrameworkClient used for calling Skills.
200
     *
201
     * @returns A BotFrameworkClient instance to call Skills.
202
     */
203
    createBotFrameworkClient(): BotFrameworkClient {
204
        return new BotFrameworkClientImpl(
×
205
            this.credentialsFactory,
206
            this.toChannelFromBotLoginUrl,
207
            this.botFrameworkClientFetch
208
        );
209
    }
210

211
    private async JwtTokenValidation_authenticateRequest(
212
        activity: Partial<Activity>,
213
        authHeader: string
214
    ): Promise<ClaimsIdentity> {
215
        if (!authHeader.trim()) {
×
216
            const isAuthDisabled = await this.credentialsFactory.isAuthenticationDisabled();
×
217
            if (!isAuthDisabled) {
×
218
                throw new AuthenticationError(
×
219
                    'Unauthorized Access. Request is not authorized',
220
                    StatusCodes.UNAUTHORIZED
221
                );
222
            }
223

224
            // Check if the activity is for a skill call and is coming from the Emulator.
225
            if (activity.channelId === Channels.Emulator && activity.recipient?.role === RoleTypes.Skill) {
×
226
                return SkillValidation.createAnonymousSkillClaim();
×
227
            }
228

229
            // In the scenario where Auth is disabled, we still want to have the
230
            // IsAuthenticated flag set in the ClaimsIdentity. To do this requires
231
            // adding in an empty claim.
232
            return new ClaimsIdentity([], AuthenticationConstants.AnonymousAuthType);
×
233
        }
234

235
        const claimsIdentity: ClaimsIdentity = await this.JwtTokenValidation_validateAuthHeader(
×
236
            authHeader,
237
            activity.channelId,
238
            activity.serviceUrl
239
        );
240

241
        return claimsIdentity;
×
242
    }
243

244
    private async JwtTokenValidation_validateAuthHeader(
245
        authHeader: string,
246
        channelId: string,
247
        serviceUrl = ''
×
248
    ): Promise<ClaimsIdentity> {
249
        const identity = await this.JwtTokenValidation_authenticateToken(authHeader, channelId, serviceUrl);
×
250

251
        await this.JwtTokenValidation_validateClaims(identity.claims);
×
252

253
        return identity;
×
254
    }
255

256
    private async JwtTokenValidation_validateClaims(claims: Claim[] = []): Promise<void> {
×
257
        if (this.authConfiguration.validateClaims) {
×
258
            // Call the validation method if defined (it should throw an exception if the validation fails)
259
            await this.authConfiguration.validateClaims(claims);
×
260
        } else if (SkillValidation.isSkillClaim(claims)) {
×
261
            // Skill claims must be validated using AuthenticationConfiguration validateClaims
262
            throw new AuthenticationError(
×
263
                'Unauthorized Access. Request is not authorized. Skill Claims require validation.',
264
                StatusCodes.UNAUTHORIZED
265
            );
266
        }
267
    }
268

269
    private async JwtTokenValidation_authenticateToken(
270
        authHeader: string,
271
        channelId: string,
272
        serviceUrl: string
273
    ): Promise<ClaimsIdentity | undefined> {
274
        if (AseChannelValidation.isTokenFromAseChannel(channelId)) {
×
275
            return AseChannelValidation.authenticateAseChannelToken(authHeader);
×
276
        }
277

278
        if (SkillValidation.isSkillToken(authHeader)) {
×
279
            return this.SkillValidation_authenticateChannelToken(authHeader, channelId);
×
280
        }
281

282
        if (EmulatorValidation.isTokenFromEmulator(authHeader)) {
×
283
            return this.EmulatorValidation_authenticateEmulatorToken(authHeader, channelId);
×
284
        }
285

286
        // Handle requests from BotFramework Channels
287
        return this.ChannelValidation_authenticateChannelToken(authHeader, serviceUrl, channelId);
×
288
    }
289

290
    private async SkillValidation_authenticateChannelToken(
291
        authHeader: string,
292
        channelId: string
293
    ): Promise<ClaimsIdentity> {
294
        // Add allowed token issuers from configuration.
295
        const verifyOptions: VerifyOptions = {
×
296
            ...ToBotFromBotOrEmulatorTokenValidationParameters,
297
            issuer: [
298
                ...ToBotFromBotOrEmulatorTokenValidationParameters.issuer,
299
                ...(this.authConfiguration.validTokenIssuers ?? []),
×
300
            ],
301
        };
302

303
        const tokenExtractor = new JwtTokenExtractor(
×
304
            verifyOptions,
305
            this.toBotFromEmulatorOpenIdMetadataUrl,
306
            AuthenticationConstants.AllowedSigningAlgorithms,
307
            this.connectorClientOptions?.proxySettings
×
308
        );
309

310
        const parts: string[] = authHeader.split(' ');
×
311
        const identity = await tokenExtractor.getIdentity(
×
312
            parts[0],
313
            parts[1],
314
            channelId,
315
            this.authConfiguration.requiredEndorsements
316
        );
317

318
        await this.SkillValidation_ValidateIdentity(identity);
×
319

320
        return identity;
×
321
    }
322

323
    private async SkillValidation_ValidateIdentity(identity: ClaimsIdentity): Promise<void> {
324
        if (!identity) {
×
325
            // No valid identity. Not Authorized.
326
            throw new AuthenticationError(
×
327
                'SkillValidation.validateIdentity(): Invalid identity',
328
                StatusCodes.UNAUTHORIZED
329
            );
330
        }
331

332
        if (!identity.isAuthenticated) {
×
333
            // The token is in some way invalid. Not Authorized.
334
            throw new AuthenticationError(
×
335
                'SkillValidation.validateIdentity(): Token not authenticated',
336
                StatusCodes.UNAUTHORIZED
337
            );
338
        }
339

340
        const versionClaim = identity.getClaimValue(AuthenticationConstants.VersionClaim);
×
341
        if (!versionClaim) {
×
342
            // No version claim
343
            throw new AuthenticationError(
×
344
                `SkillValidation.validateIdentity(): '${AuthenticationConstants.VersionClaim}' claim is required on skill Tokens.`,
345
                StatusCodes.UNAUTHORIZED
346
            );
347
        }
348

349
        // Look for the "aud" claim, but only if issued from the Bot Framework
350
        const audienceClaim = identity.getClaimValue(AuthenticationConstants.AudienceClaim);
×
351
        if (!audienceClaim) {
×
352
            // Claim is not present or doesn't have a value. Not Authorized.
353
            throw new AuthenticationError(
×
354
                `SkillValidation.validateIdentity(): '${AuthenticationConstants.AudienceClaim}' claim is required on skill Tokens.`,
355
                StatusCodes.UNAUTHORIZED
356
            );
357
        }
358

359
        if (!(await this.credentialsFactory.isValidAppId(audienceClaim))) {
×
360
            // The AppId is not valid. Not Authorized.
361
            throw new AuthenticationError(
×
362
                'SkillValidation.validateIdentity(): Invalid audience.',
363
                StatusCodes.UNAUTHORIZED
364
            );
365
        }
366

367
        const appId = JwtTokenValidation.getAppIdFromClaims(identity.claims);
×
368
        if (!appId) {
×
369
            // Invalid appId
370
            throw new AuthenticationError(
×
371
                'SkillValidation.validateIdentity(): Invalid appId.',
372
                StatusCodes.UNAUTHORIZED
373
            );
374
        }
375
    }
376

377
    private async EmulatorValidation_authenticateEmulatorToken(
378
        authHeader: string,
379
        channelId: string
380
    ): Promise<ClaimsIdentity> {
381
        // Add allowed token issuers from configuration.
382
        const verifyOptions: VerifyOptions = {
×
383
            ...ToBotFromBotOrEmulatorTokenValidationParameters,
384
            issuer: [
385
                ...ToBotFromBotOrEmulatorTokenValidationParameters.issuer,
386
                ...(this.authConfiguration.validTokenIssuers ?? []),
×
387
            ],
388
        };
389

390
        const tokenExtractor: JwtTokenExtractor = new JwtTokenExtractor(
×
391
            verifyOptions,
392
            this.toBotFromEmulatorOpenIdMetadataUrl,
393
            AuthenticationConstants.AllowedSigningAlgorithms,
394
            this.connectorClientOptions?.proxySettings
×
395
        );
396

397
        const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(
×
398
            authHeader,
399
            channelId,
400
            this.authConfiguration.requiredEndorsements
401
        );
402
        if (!identity) {
×
403
            // No valid identity. Not Authorized.
404
            throw new AuthenticationError('Unauthorized. No valid identity.', StatusCodes.UNAUTHORIZED);
×
405
        }
406

407
        if (!identity.isAuthenticated) {
×
408
            // The token is in some way invalid. Not Authorized.
409
            throw new AuthenticationError('Unauthorized. Is not authenticated', StatusCodes.UNAUTHORIZED);
×
410
        }
411

412
        // Now check that the AppID in the claimset matches
413
        // what we're looking for. Note that in a multi-tenant bot, this value
414
        // comes from developer code that may be reaching out to a service, hence the
415
        // Async validation.
416
        const versionClaim: string = identity.getClaimValue(AuthenticationConstants.VersionClaim);
×
417
        if (versionClaim === null) {
×
418
            throw new AuthenticationError(
×
419
                'Unauthorized. "ver" claim is required on Emulator Tokens.',
420
                StatusCodes.UNAUTHORIZED
421
            );
422
        }
423

424
        let appId = '';
×
425

426
        // The Emulator, depending on Version, sends the AppId via either the
427
        // appid claim (Version 1) or the Authorized Party claim (Version 2).
428
        if (!versionClaim || versionClaim === '1.0') {
×
429
            // either no Version or a version of "1.0" means we should look for
430
            // the claim in the "appid" claim.
431
            const appIdClaim: string = identity.getClaimValue(AuthenticationConstants.AppIdClaim);
×
432
            if (!appIdClaim) {
×
433
                // No claim around AppID. Not Authorized.
434
                throw new AuthenticationError(
×
435
                    'Unauthorized. "appid" claim is required on Emulator Token version "1.0".',
436
                    StatusCodes.UNAUTHORIZED
437
                );
438
            }
439

440
            appId = appIdClaim;
×
441
        } else if (versionClaim === '2.0') {
×
442
            // Emulator, "2.0" puts the AppId in the "azp" claim.
443
            const appZClaim: string = identity.getClaimValue(AuthenticationConstants.AuthorizedParty);
×
444
            if (!appZClaim) {
×
445
                // No claim around AppID. Not Authorized.
446
                throw new AuthenticationError(
×
447
                    'Unauthorized. "azp" claim is required on Emulator Token version "2.0".',
448
                    StatusCodes.UNAUTHORIZED
449
                );
450
            }
451

452
            appId = appZClaim;
×
453
        } else {
454
            // Unknown Version. Not Authorized.
455
            throw new AuthenticationError(
×
456
                `Unauthorized. Unknown Emulator Token version "${versionClaim}".`,
457
                StatusCodes.UNAUTHORIZED
458
            );
459
        }
460

461
        if (!(await this.credentialsFactory.isValidAppId(appId))) {
×
462
            throw new AuthenticationError(
×
463
                `Unauthorized. Invalid AppId passed on token: ${appId}`,
464
                StatusCodes.UNAUTHORIZED
465
            );
466
        }
467

468
        return identity;
×
469
    }
470

471
    private async ChannelValidation_authenticateChannelToken(
472
        authHeader: string,
473
        serviceUrl: string,
474
        channelId: string
475
    ): Promise<ClaimsIdentity> {
476
        const tokenValidationParameters = this.ChannelValidation_GetTokenValidationParameters();
×
477
        const tokenExtractor: JwtTokenExtractor = new JwtTokenExtractor(
×
478
            tokenValidationParameters,
479
            this.toBotFromChannelOpenIdMetadataUrl,
480
            AuthenticationConstants.AllowedSigningAlgorithms,
481
            this.connectorClientOptions?.proxySettings
×
482
        );
483

484
        const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(
×
485
            authHeader,
486
            channelId,
487
            this.authConfiguration.requiredEndorsements
488
        );
489

490
        return this.governmentChannelValidation_ValidateIdentity(identity, serviceUrl);
×
491
    }
492

493
    private ChannelValidation_GetTokenValidationParameters(): VerifyOptions {
494
        return {
×
495
            issuer: [this.toBotFromChannelTokenIssuer],
496
            audience: undefined, // Audience validation takes place manually in code.
497
            clockTolerance: 5 * 60,
498
            ignoreExpiration: false,
499
        };
500
    }
501

502
    private async governmentChannelValidation_ValidateIdentity(
503
        identity: ClaimsIdentity,
504
        serviceUrl: string
505
    ): Promise<ClaimsIdentity> {
506
        if (!identity) {
×
507
            // No valid identity. Not Authorized.
508
            throw new AuthenticationError('Unauthorized. No valid identity.', StatusCodes.UNAUTHORIZED);
×
509
        }
510

511
        if (!identity.isAuthenticated) {
×
512
            // The token is in some way invalid. Not Authorized.
513
            throw new AuthenticationError('Unauthorized. Is not authenticated', StatusCodes.UNAUTHORIZED);
×
514
        }
515

516
        // Now check that the AppID in the claimset matches
517
        // what we're looking for. Note that in a multi-tenant bot, this value
518
        // comes from developer code that may be reaching out to a service, hence the
519
        // Async validation.
520

521
        // Look for the "aud" claim, but only if issued from the Bot Framework
522
        if (identity.getClaimValue(AuthenticationConstants.IssuerClaim) !== this.toBotFromChannelTokenIssuer) {
×
523
            // The relevant Audiance Claim MUST be present. Not Authorized.
524
            throw new AuthenticationError('Unauthorized. Issuer Claim MUST be present.', StatusCodes.UNAUTHORIZED);
×
525
        }
526

527
        // The AppId from the claim in the token must match the AppId specified by the developer.
528
        // In this case, the token is destined for the app, so we find the app ID in the audience claim.
529
        const audClaim: string = identity.getClaimValue(AuthenticationConstants.AudienceClaim);
×
530
        if (!(await this.credentialsFactory.isValidAppId(audClaim || ''))) {
×
531
            // The AppId is not valid or not present. Not Authorized.
532
            throw new AuthenticationError(
×
533
                `Unauthorized. Invalid AppId passed on token: ${audClaim}`,
534
                StatusCodes.UNAUTHORIZED
535
            );
536
        }
537

538
        if (serviceUrl) {
×
539
            const serviceUrlClaim = identity.getClaimValue(AuthenticationConstants.ServiceUrlClaim);
×
540
            if (serviceUrlClaim !== serviceUrl) {
×
541
                // Claim must match. Not Authorized.
542
                throw new AuthenticationError('Unauthorized. ServiceUrl claim do not match.', StatusCodes.UNAUTHORIZED);
×
543
            }
544
        }
545

546
        return identity;
×
547
    }
548
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc