Skip to content

Commit

Permalink
plumb through authConfig in bf-connector/auth (#1470)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengum authored Dec 5, 2019
1 parent 1f236f3 commit 8a32d65
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 21 deletions.
17 changes: 12 additions & 5 deletions libraries/botframework-connector/src/auth/channelValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Licensed under the MIT License.
*/
import { VerifyOptions } from 'jsonwebtoken';
import { ClaimsIdentity } from './claimsIdentity';
import { AuthenticationConstants } from './authenticationConstants';
import { AuthenticationConfiguration } from './authenticationConfiguration';
import { ClaimsIdentity } from './claimsIdentity';
import { ICredentialProvider } from './credentialProvider';
import { JwtTokenExtractor } from './jwtTokenExtractor';

Expand All @@ -31,16 +32,19 @@ export namespace ChannelValidation {
* @param {string} authHeader The raw HTTP header in the format: "Bearer [longString]"
* @param {ICredentialProvider} credentials The user defined set of valid credentials, such as the AppId.
* @param {string} serviceUrl The ServiceUrl Claim value that must match in the identity.
* @param {string} channelId
* @param {AuthenticationConfiguration} authConfig
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
*/
export async function authenticateChannelTokenWithServiceUrl(
authHeader: string,
credentials: ICredentialProvider,
serviceUrl: string,
channelId: string
channelId: string,
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {

const identity: ClaimsIdentity = await authenticateChannelToken(authHeader, credentials, channelId);
const identity: ClaimsIdentity = await authenticateChannelToken(authHeader, credentials, channelId, authConfig);

const serviceUrlClaim: string = identity.getClaimValue(AuthenticationConstants.ServiceUrlClaim);
if (serviceUrlClaim !== serviceUrl) {
Expand All @@ -56,20 +60,23 @@ export namespace ChannelValidation {
* A token issued by the Bot Framework emulator will FAIL this check.
* @param {string} authHeader The raw HTTP header in the format: "Bearer [longString]"
* @param {ICredentialProvider} credentials The user defined set of valid credentials, such as the AppId.
* @param {string} channelId
* @param {AuthenticationConfiguration} authConfig
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
*/
export async function authenticateChannelToken(
authHeader: string,
credentials: ICredentialProvider,
channelId: string
channelId: string,
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {

const tokenExtractor: JwtTokenExtractor = new JwtTokenExtractor(
ToBotFromChannelTokenValidationParameters,
OpenIdMetadataEndpoint ? OpenIdMetadataEndpoint : AuthenticationConstants.ToBotFromChannelOpenIdMetadataUrl,
AuthenticationConstants.AllowedSigningAlgorithms);

const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId);
const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId, authConfig.requiredEndorsements);

return await validateIdentity(identity, credentials);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { decode, VerifyOptions } from 'jsonwebtoken';
import { ClaimsIdentity } from './claimsIdentity';
import { AuthenticationConstants } from './authenticationConstants';
import { AuthenticationConfiguration } from './authenticationConfiguration';
import { GovernmentConstants } from './governmentConstants';
import { ICredentialProvider } from './credentialProvider';
import { JwtTokenExtractor } from './jwtTokenExtractor';
Expand Down Expand Up @@ -95,13 +96,16 @@ export namespace EmulatorValidation {
* @param {string} authHeader The raw HTTP header in the format: "Bearer [longString]"
* @param {ICredentialProvider} credentials The user defined set of valid credentials, such as the AppId.
* @param {string} channelService The channelService value that distinguishes public Azure from US Government Azure.
* @param {string} channelId
* @param {AuthenticationConfiguration} authConfig
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
*/
export async function authenticateEmulatorToken(
authHeader: string,
credentials: ICredentialProvider,
channelService: string,
channelId: string
channelId: string,
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {
const openIdMetadataUrl = (channelService !== undefined && JwtTokenValidation.isGovernment(channelService)) ?
GovernmentConstants.ToBotFromEmulatorOpenIdMetadataUrl :
Expand All @@ -112,7 +116,7 @@ export namespace EmulatorValidation {
openIdMetadataUrl,
AuthenticationConstants.AllowedSigningAlgorithms);

const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId);
const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId, authConfig.requiredEndorsements);
if (!identity) {
// No valid identity. Not Authorized.
throw new Error('Unauthorized. No valid identity.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* Licensed under the MIT License.
*/
import { VerifyOptions } from 'jsonwebtoken';
import { AuthenticationConfiguration } from './authenticationConfiguration';
import { AuthenticationConstants } from './authenticationConstants';
import { ChannelValidation } from './channelValidation';
import { ClaimsIdentity } from './claimsIdentity';
import { AuthenticationConstants } from './authenticationConstants';
import { ICredentialProvider } from './credentialProvider';
import { JwtTokenExtractor } from './jwtTokenExtractor';

Expand Down Expand Up @@ -62,7 +63,8 @@ export namespace EnterpriseChannelValidation {
authHeader: string,
credentials: ICredentialProvider,
channelId: string,
channelService: string
channelService: string,
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {

const tokenExtractor: JwtTokenExtractor = new JwtTokenExtractor(
Expand All @@ -72,7 +74,7 @@ export namespace EnterpriseChannelValidation {
AuthenticationConstants.ToBotFromEnterpriseChannelOpenIdMetadataUrlFormat.replace('{channelService}', channelService),
AuthenticationConstants.AllowedSigningAlgorithms);

const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId);
const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId, authConfig.requiredEndorsements);

return await validateIdentity(identity, credentials);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Licensed under the MIT License.
*/
import { VerifyOptions } from 'jsonwebtoken';
import { ClaimsIdentity } from './claimsIdentity';
import { AuthenticationConfiguration } from './authenticationConfiguration';
import { AuthenticationConstants } from './authenticationConstants';
import { ClaimsIdentity } from './claimsIdentity';
import { ICredentialProvider } from './credentialProvider';
import { GovernmentConstants } from './governmentConstants';
import { JwtTokenExtractor } from './jwtTokenExtractor';
Expand Down Expand Up @@ -57,12 +58,15 @@ export namespace GovernmentChannelValidation {
* A token issued by the Bot Framework emulator will FAIL this check.
* @param {string} authHeader The raw HTTP header in the format: "Bearer [longString]"
* @param {ICredentialProvider} credentials The user defined set of valid credentials, such as the AppId.
* @param {string} channelId
* @param {AuthenticationConfiguration} authConfig
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
*/
export async function authenticateChannelToken(
authHeader: string,
credentials: ICredentialProvider,
channelId: string
channelId: string,
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {

const tokenExtractor: JwtTokenExtractor = new JwtTokenExtractor(
Expand All @@ -71,7 +75,7 @@ export namespace GovernmentChannelValidation {
OpenIdMetadataEndpoint : GovernmentConstants.ToBotFromChannelOpenIdMetadataUrl,
AuthenticationConstants.AllowedSigningAlgorithms);

const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId);
const identity: ClaimsIdentity = await tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId, authConfig.requiredEndorsements);

return await validateIdentity(identity, credentials);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ export class JwtTokenExtractor {
return null;
}

public async getIdentity(scheme: string, parameter: string, channelId: string, requiredEndorsements: string[]): Promise<ClaimsIdentity | null> {
if (!requiredEndorsements) {
throw new Error('JwtTokenExtractor.getIdentity() must be called valid a requiredEndorsements parameter');
}
public async getIdentity(scheme: string, parameter: string, channelId: string, requiredEndorsements: string[] = []): Promise<ClaimsIdentity | null> {

// No header in correct scheme or no token
if (scheme !== 'Bearer' || !parameter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,9 @@ export namespace JwtTokenValidation {
channelService: string,
channelId: string,
serviceUrl: string = '',
authConfig?: AuthenticationConfiguration
authConfig: AuthenticationConfiguration = new AuthenticationConfiguration()
): Promise<ClaimsIdentity> {
if (!authHeader.trim()) { throw new Error('\'authHeader\' required.'); }
if (!authConfig) {
authConfig = new AuthenticationConfiguration();
}

const identity = await authenticateToken(authHeader, credentials, channelService, channelId, authConfig, serviceUrl);

Expand Down

0 comments on commit 8a32d65

Please sign in to comment.