Skip to content
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
7 changes: 7 additions & 0 deletions packages/agents-hosting/src/auth/authConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export interface AuthConfiguration {
* An optional alternative blueprint Connection name used when constructing a connector client.
*/
altBlueprintConnectionName?: string

/**
* The path to K8s provided token.
*/
WIDAssertionFile?: string
}

/**
Expand Down Expand Up @@ -180,6 +185,7 @@ export const loadPrevAuthConfigFromEnv: () => AuthConfiguration = () => {
authority,
issuers: getDefaultIssuers(process.env.MicrosoftAppTenantId ?? '', authority),
altBlueprintConnectionName: process.env.altBlueprintConnectionName,
WIDAssertionFile: process.env.WIDAssertionFile,
}
envConnections.connections.set(DEFAULT_CONNECTION, authConfig)
envConnections.connectionsMap.push({
Expand Down Expand Up @@ -344,6 +350,7 @@ function buildLegacyAuthConfig (envPrefix: string = '', customConfig?: AuthConfi
authority,
issuers: customConfig?.issuers ?? getDefaultIssuers(tenantId as string, authority),
altBlueprintConnectionName: customConfig?.altBlueprintConnectionName ?? process.env[`${prefix}altBlueprintConnectionName`],
WIDAssertionFile: customConfig?.WIDAssertionFile ?? process.env[`${prefix}WIDAssertionFile`]
}
}

Expand Down
26 changes: 25 additions & 1 deletion packages/agents-hosting/src/auth/msalTokenProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export class MsalTokenProvider implements AuthProvider {
return ''
}
let token
if (authConfig.FICClientId !== undefined) {
if (authConfig.WIDAssertionFile !== undefined) {
token = await this.acquireAccessTokenViaWID(authConfig, actualScope)
} else if (authConfig.FICClientId !== undefined) {
token = await this.acquireAccessTokenViaFIC(authConfig, actualScope)
} else if (authConfig.clientSecret !== undefined) {
token = await this.acquireAccessTokenViaSecret(authConfig, actualScope)
Expand Down Expand Up @@ -373,6 +375,28 @@ export class MsalTokenProvider implements AuthProvider {
return token?.accessToken as string
}

/**
* Acquires a token using a Workload Identity client assertion.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
private async acquireAccessTokenViaWID (authConfig: AuthConfiguration, scope: string) : Promise<string> {
const scopes = [`${scope}/.default`]
const clientAssertion = fs.readFileSync(authConfig.WIDAssertionFile as string, 'utf8')
const cca = new ConfidentialClientApplication({
auth: {
clientId: authConfig.clientId as string,
authority: `https://login.microsoftonline.com/${authConfig.tenantId}`,
clientAssertion
},
system: this.sysOptions
})
const token = await cca.acquireTokenByClientCredential({ scopes })
logger.info('got token using WID client assertion')
return token?.accessToken as string
}

/**
* Fetches an external token.
* @param FICClientId The FIC client ID.
Expand Down
12 changes: 12 additions & 0 deletions packages/agents-hosting/test/hosting/msalTokenProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ describe('MsalTokenProvider', () => {
acquireTokenStub.restore()
})

it('should acquire token with WID', async () => {
authConfig.clientSecret = undefined
authConfig.certPemFile = undefined
authConfig.certKeyFile = undefined
authConfig.WIDAssertionFile = '/etc/issue'
// @ts-ignore
const acquireTokenStub = sinon.stub(ConfidentialClientApplication.prototype, 'acquireTokenByClientCredential').resolves({ accessToken: 'test-token' })
const token = await msalTokenProvider.getAccessToken(authConfig, 'scope')
assert.strictEqual(token, 'test-token')
acquireTokenStub.restore()
})

it('should throw error for invalid authConfig', async () => {
authConfig.tenantId = undefined
authConfig.clientId = '1111'
Expand Down