Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: USGovSingleTenant OAuthEndpoint #4588

Merged
merged 2 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions libraries/botbuilder/src/botFrameworkAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
GovernmentConstants,
JwtTokenValidation,
MicrosoftAppCredentials,
MicrosoftGovernmentAppCredentials,
SignInUrlResponse,
SimpleCredentialProvider,
SkillValidation,
Expand Down Expand Up @@ -254,11 +255,19 @@ export class BotFrameworkAdapter
);
this.credentialsProvider = new SimpleCredentialProvider(this.credentials.appId, '');
} else {
this.credentials = new MicrosoftAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
this.credentials = new MicrosoftGovernmentAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
} else {
this.credentials = new MicrosoftAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
}
this.credentialsProvider = new SimpleCredentialProvider(
this.credentials.appId,
this.settings.appPassword || ''
Expand All @@ -280,10 +289,6 @@ export class BotFrameworkAdapter
ChannelValidation.OpenIdMetadataEndpoint = this.settings.openIdMetadata;
GovernmentChannelValidation.OpenIdMetadataEndpoint = this.settings.openIdMetadata;
}
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
this.credentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
this.credentials.oAuthScope = GovernmentConstants.ToChannelFromBotOAuthScope;
}

// If a NodeWebSocketFactoryBase was passed in, set it on the BotFrameworkAdapter.
if (this.settings.webSocketFactory) {
Expand Down Expand Up @@ -1627,12 +1632,21 @@ export class BotFrameworkAdapter
this.settings.channelAuthTenant
);
} else {
credentials = new MicrosoftAppCredentials(appId, appPassword, this.settings.channelAuthTenant, oAuthScope);
}

if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
credentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
credentials.oAuthScope = oAuthScope || GovernmentConstants.ToChannelFromBotOAuthScope;
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
credentials = new MicrosoftGovernmentAppCredentials(
appId,
appPassword,
this.settings.channelAuthTenant,
oAuthScope
);
} else {
credentials = new MicrosoftAppCredentials(
appId,
appPassword,
this.settings.channelAuthTenant,
oAuthScope
);
}
}

return credentials;
Expand Down
6 changes: 2 additions & 4 deletions libraries/botbuilder/src/botFrameworkHttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import {
AppCredentials,
AuthenticationConstants,
ConversationConstants,
GovernmentConstants,
ICredentialProvider,
JwtTokenValidation,
MicrosoftAppCredentials,
MicrosoftGovernmentAppCredentials,
} from 'botframework-connector';

import { USER_AGENT } from './botFrameworkAdapter';
Expand Down Expand Up @@ -158,9 +158,7 @@ export class BotFrameworkHttpClient implements BotFrameworkClient {
protected async buildCredentials(appId: string, oAuthScope?: string): Promise<AppCredentials> {
const appPassword = await this.credentialProvider.getAppPassword(appId);
if (JwtTokenValidation.isGovernment(this.channelService)) {
const appCredentials = new MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
appCredentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
return appCredentials;
return new MicrosoftGovernmentAppCredentials(appId, appPassword, undefined, oAuthScope);
} else {
return new MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
}
Expand Down
24 changes: 16 additions & 8 deletions libraries/botframework-connector/src/auth/appCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,11 @@ export abstract class AppCredentials implements ServiceClientCredentials {
* @param channelAuthTenant Optional. The oauth token tenant.
* @param oAuthScope The scope for the token.
*/
constructor(
appId: string,
channelAuthTenant?: string,
oAuthScope: string = AuthenticationConstants.ToBotFromChannelTokenIssuer
) {
constructor(appId: string, channelAuthTenant?: string, oAuthScope: string = null) {
this.appId = appId;
this.tenant = channelAuthTenant;
this.oAuthEndpoint = AuthenticationConstants.ToChannelFromBotLoginUrlPrefix + this.tenant;
this.oAuthScope = oAuthScope;
this.oAuthEndpoint = this.GetToChannelFromBotLoginUrlPrefix() + this.tenant;
this.oAuthScope = oAuthScope && oAuthScope.length > 0 ? oAuthScope : this.GetToChannelFromBotOAuthScope();
}

/**
Expand All @@ -69,7 +65,7 @@ export abstract class AppCredentials implements ServiceClientCredentials {
* Sets tenant to be used for channel authentication.
*/
private set tenant(value: string) {
this._tenant = value && value.length > 0 ? value : AuthenticationConstants.DefaultChannelAuthTenant;
this._tenant = value && value.length > 0 ? value : this.GetDefaultChannelAuthTenant();
}

/**
Expand Down Expand Up @@ -191,6 +187,18 @@ export abstract class AppCredentials implements ServiceClientCredentials {
}
}

protected GetToChannelFromBotOAuthScope(): string {
return AuthenticationConstants.ToChannelFromBotOAuthScope;
}

protected GetToChannelFromBotLoginUrlPrefix(): string {
return AuthenticationConstants.ToChannelFromBotLoginUrlPrefix;
}

protected GetDefaultChannelAuthTenant(): string {
return AuthenticationConstants.DefaultChannelAuthTenant;
}

protected abstract refreshToken(): Promise<AuthenticatorResult>;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,21 @@ export namespace GovernmentConstants {

/**
* TO CHANNEL FROM BOT: Login URL
*
* DEPRECATED: DO NOT USE
*/
export const ToChannelFromBotLoginUrl = 'https://login.microsoftonline.us/MicrosoftServices.onmicrosoft.us';

/**
* TO CHANNEL FROM BOT: Login URL prefix
*/
export const ToChannelFromBotLoginUrlPrefix = 'https://login.microsoftonline.us/';

/**
* TO CHANNEL FROM BOT: Default tenant from which to obtain a token for bot to channel communication
*/
export const DefaultChannelAuthTenant = 'MicrosoftServices.onmicrosoft.us';

/**
* TO CHANNEL FROM BOT: OAuth scope to request
*/
Expand Down
1 change: 1 addition & 0 deletions libraries/botframework-connector/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './managedIdentityAppCredentials';
export * from './managedIdentityAuthenticator';
export * from './managedIdentityServiceClientCredentialsFactory';
export * from './microsoftAppCredentials';
export * from './microsoftGovernmentAppCredentials';
export * from './passwordServiceClientCredentialFactory';
export * from './serviceClientCredentialsFactory';
export * from './skillValidation';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @module botframework-connector
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { GovernmentConstants } from './governmentConstants';
import { MicrosoftAppCredentials } from './microsoftAppCredentials';

/**
* MicrosoftGovermentAppCredentials auth implementation
*/
export class MicrosoftGovernmentAppCredentials extends MicrosoftAppCredentials {
/**
* Initializes a new instance of the [MicrosoftGovernmentAppCredentials](xref:botframework-connector.MicrosoftGovernmentAppCredentials) class.
*
* @param {string} appId The Microsoft app ID.
* @param {string} appPassword The Microsoft app password.
* @param {string} channelAuthTenant Optional. The oauth token tenant.
* @param {string} oAuthScope Optional. The scope for the token.
*/
constructor(appId: string, public appPassword: string, channelAuthTenant?: string, oAuthScope?: string) {
super(appId, appPassword, channelAuthTenant, oAuthScope);
}

protected GetToChannelFromBotOAuthScope(): string {
return GovernmentConstants.ToChannelFromBotOAuthScope;
}

protected GetToChannelFromBotLoginUrlPrefix(): string {
return GovernmentConstants.ToChannelFromBotLoginUrlPrefix;
}

protected GetDefaultChannelAuthTenant(): string {
return GovernmentConstants.DefaultChannelAuthTenant;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export class MsalServiceClientCredentialsFactory implements ServiceClientCredent
);
}

if (normalizedEndpoint === GovernmentConstants.ToChannelFromBotLoginUrl.toLowerCase()) {
if (normalizedEndpoint.startsWith(GovernmentConstants.ToChannelFromBotLoginUrlPrefix)) {
return new MsalAppCredentials(
this.clientApplication,
appId,
GovernmentConstants.ToChannelFromBotLoginUrl,
undefined,
audience || GovernmentConstants.ToChannelFromBotOAuthScope
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { ServiceClientCredentials } from '@azure/core-http';
import { AuthenticationConstants } from './authenticationConstants';
import { GovernmentConstants } from './governmentConstants';
import { MicrosoftAppCredentials } from './microsoftAppCredentials';
import { MicrosoftGovernmentAppCredentials } from './microsoftGovernmentAppCredentials';
import { ServiceClientCredentialsFactory } from './serviceClientCredentialsFactory';
import { stringExt } from 'botbuilder-stdlib';

Expand Down Expand Up @@ -111,9 +112,8 @@ export class PasswordServiceClientCredentialFactory implements ServiceClientCred

if (normalizedEndpoint?.startsWith(AuthenticationConstants.ToChannelFromBotLoginUrlPrefix)) {
credentials = new MicrosoftAppCredentials(appId, this.password, this.tenantId, audience);
} else if (normalizedEndpoint === GovernmentConstants.ToChannelFromBotLoginUrl.toLowerCase()) {
credentials = new MicrosoftAppCredentials(appId, this.password, this.tenantId, audience);
credentials.oAuthEndpoint = loginEndpoint;
} else if (normalizedEndpoint?.startsWith(GovernmentConstants.ToChannelFromBotLoginUrlPrefix)) {
credentials = new MicrosoftGovernmentAppCredentials(appId, this.password, this.tenantId, audience);
} else {
credentials = new PrivateCloudAppCredentials(
appId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { MicrosoftAppCredentials, AuthenticationConstants } = require('../..');
const assert = require('assert');

describe('MicrosoftAppCredentialsTestSuite', function () {
describe('MicrosoftAppCredentialsTestCase', function () {
it('AssertOAuthEndpointAndOAuthScope', function () {
const credentials1 = new MicrosoftAppCredentials('appId', 'password', 'tenantId', 'audience');
assert.strictEqual(
AuthenticationConstants.ToChannelFromBotLoginUrlPrefix + 'tenantId',
credentials1.oAuthEndpoint
);
assert.strictEqual('audience', credentials1.oAuthScope);

const credentials2 = new MicrosoftAppCredentials('appId', 'password');
assert.strictEqual(
AuthenticationConstants.ToChannelFromBotLoginUrlPrefix +
AuthenticationConstants.DefaultChannelAuthTenant,
credentials2.oAuthEndpoint
);
assert.strictEqual(AuthenticationConstants.ToChannelFromBotOAuthScope, credentials2.oAuthScope);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { MicrosoftGovernmentAppCredentials, GovernmentConstants } = require('../..');
const assert = require('assert');

describe('MicrosoftGovernmentAppCredentialsTestSuite', function () {
describe('MicrosoftGovernmentAppCredentialsTestCase', function () {
it('AssertOAuthEndpointAndOAuthScope', function () {
const credentials1 = new MicrosoftGovernmentAppCredentials('appId', 'password', 'tenantId', 'audience');
assert.strictEqual(
GovernmentConstants.ToChannelFromBotLoginUrlPrefix + 'tenantId',
credentials1.oAuthEndpoint
);
assert.strictEqual('audience', credentials1.oAuthScope);

const credentials2 = new MicrosoftGovernmentAppCredentials('appId', 'password');
assert.strictEqual(
GovernmentConstants.ToChannelFromBotLoginUrlPrefix + GovernmentConstants.DefaultChannelAuthTenant,
credentials2.oAuthEndpoint
);
assert.strictEqual(GovernmentConstants.ToChannelFromBotOAuthScope, credentials2.oAuthScope);
});
});
});
Loading