Skip to content

Commit

Permalink
WIP: added usernamepassword authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
sksadjad committed Jun 17, 2022
1 parent fcef61d commit 9fefae8
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 107 deletions.
6 changes: 4 additions & 2 deletions packages/ms-vc-api-issuer/__tests__/localAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { createObjects } from '@veramo/cli/build/lib/objectCreator'

jest.setTimeout(30000)

import vcApiIssuerAgentLogic from './shared/vcApiIssuerAgentLogic'
import vcApiIssuerUsernamePasswordAgentLogic from './shared/vcApiIssuerUsernamePasswordAgentLogic'
import vcApiIssuerClientCredentialAgentLogic from './shared/vcApiIssuerClientCredentialAgentLogic'

let agent: any

Expand All @@ -23,5 +24,6 @@ const getAgent = () => agent
const testContext = { getAgent, setup, tearDown }

describe('ms-vc-api-isuuer-Local integration tests', () => {
vcApiIssuerAgentLogic(testContext)
vcApiIssuerUsernamePasswordAgentLogic(testContext)
vcApiIssuerClientCredentialAgentLogic(testContext)
})

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { TAgent, createAgent } from '@veramo/core'
import { IMsVcApiIssuer, MsAuthenticationTypeEnum, MsVcApiIssuer } from '../../src'

type ConfiguredAgent = TAgent<IMsVcApiIssuer>

export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Promise<boolean>; tearDown: () => Promise<boolean> }) => {
describe('Issuer Agent Plugin', () => {
let agent: TAgent<IMsVcApiIssuer>
agent = createAgent({
plugins:[
new MsVcApiIssuer({
authenticationType: MsAuthenticationTypeEnum.ClientCredential,
authenticationArgs: {
azClientId: '<client_id>',
azClientSecret:'<client_secret>',
azTenantId: '<tenant_id>',
credentialManifest:'<credential_manifest>'
}})]
})
beforeAll(async () => {
await testContext.setup()
agent = testContext.getAgent()
})

afterAll(async () => {
await new Promise<void>((resolve) => setTimeout(() => resolve(), 10000)) // avoid jest open handle error
await testContext.tearDown()
})

it('should authenticate to Microsoft Azure Active Directory with ClientCredential', async () => {
return await expect(
agent.authenticateMsVcApi()
).resolves.not.toBeNull()
});
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {TAgent, createAgent} from '@veramo/core'
import {MsVcApiIssuer, IMsVcApiIssuer, MsAuthenticationTypeEnum} from '../../src'


type ConfiguredAgent = TAgent<IMsVcApiIssuer>

export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Promise<boolean>; tearDown: () => Promise<boolean> }) => {
describe('Issuer Agent Plugin', () => {
let agent: TAgent<IMsVcApiIssuer>
agent = createAgent({
plugins:[
new MsVcApiIssuer({
authenticationType: MsAuthenticationTypeEnum.UsernamePassword,
authenticationArgs: {
azTenantId: '<tenant_id>',
azClientId: '<client_id>',
scopes: ["user.read"],
username: '<username>',
password:'<password>',
}})]
})
beforeAll(async () => {
await testContext.setup()
agent = testContext.getAgent()
})

afterAll(async () => {
await new Promise<void>((resolve) => setTimeout(() => resolve(), 10000)) // avoid jest open handle error
await testContext.tearDown()
})


it('should authenticate to Microsoft Azure Active Directory with UsernamePassword', async () => {
const result = await agent.authenticateMsVcApi();
console.log(result)
return await expect(
agent.authenticateMsVcApi()
).resolves.not.toBeNull()
});
})
}
6 changes: 4 additions & 2 deletions packages/ms-vc-api-issuer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"generate-plugin-schema": "yarn veramo dev generate-plugin-schema"
},
"dependencies": {
"@azure/msal-common": "^7.0.0",
"@azure/msal-node": "^1.10.0",
"@veramo/core": "3.1.2-next.84",
"cross-fetch": "^3.1.5"
},
Expand All @@ -23,8 +25,7 @@
"jest": "^27.3.1",
"prettier": "^2.4.1",
"ts-jest": "^27.0.7",
"typescript": "^4.4.3",
"@azure/msal-node": "^1.3.0"
"typescript": "^4.4.3"
},
"files": [
"dist/**/*",
Expand All @@ -41,6 +42,7 @@
"license": "Apache-2.0",
"keywords": [
"Microsoft",
"msal",
"Active Directory",
"Sphereon",
"SSI",
Expand Down
25 changes: 1 addition & 24 deletions packages/ms-vc-api-issuer/plugin.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,6 @@
"IMsVcApiIssuer": {
"components": {
"schemas": {
"IMsAuthenticationArgs": {
"type": "object",
"properties": {
"azClientId": {
"type": "string"
},
"azClientSecret": {
"type": "string"
},
"azTenantId": {
"type": "string"
},
"credentialManifest": {
"type": "string"
}
},
"required": [
"azClientId",
"azClientSecret",
"azTenantId",
"credentialManifest"
]
},
"IMsAuthenticationResponse": {
"type": "object",
"properties": {
Expand All @@ -44,7 +21,7 @@
"authenticateMsVcApi": {
"description": "",
"arguments": {
"$ref": "#/components/schemas/IMsAuthenticationArgs"
"type": "object"
},
"returnType": {
"$ref": "#/components/schemas/IMsAuthenticationResponse"
Expand Down
121 changes: 79 additions & 42 deletions packages/ms-vc-api-issuer/src/agent/MsVcApiIssuer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { IAgentPlugin } from '@veramo/core'
import { LogLevel, ConfidentialClientApplication } from '@azure/msal-node'
import { schema } from '../index'
import { IMsAuthenticationArgs, IMsAuthenticationResponse, IMsVcApiIssuer, IRequiredContext } from '../types/IMsVcApiIssuer'
import { ConfidentialClientApplication, LogLevel, PublicClientApplication, UsernamePasswordRequest } from '@azure/msal-node'
import {
IMsAuthenticationAuthorizationCodeArgs,
IMsAuthenticationClientCredentialArgs,
IMsAuthenticationOnBehalfOfArgs,
IMsAuthenticationUsernamePasswordArgs,
MsAuthenticationTypeEnum,
schema,
} from '../index'
import { IMsAuthenticationResponse, IMsAuthenticationWrapperArgs, IMsVcApiIssuer } from '../types/IMsVcApiIssuer'

/**
* {@inheritDoc IMsVcApiIssuer}
Expand All @@ -11,72 +18,102 @@ export class MsVcApiIssuer implements IAgentPlugin {
readonly methods: IMsVcApiIssuer = {
authenticateMsVcApi: this.authenticateMsVcApi.bind(this),
}
private readonly azClientId: string
private readonly azClientSecret: string
private readonly azTenantId: string
private readonly credentialManifest: string
private msIdentityHostName = ''
private readonly authenticationType: MsAuthenticationTypeEnum
private readonly authenticationArgs:
| IMsAuthenticationClientCredentialArgs
| IMsAuthenticationUsernamePasswordArgs
| IMsAuthenticationAuthorizationCodeArgs
| IMsAuthenticationOnBehalfOfArgs

constructor(options: IMsAuthenticationArgs) {
this.azClientId = options.azClientId
this.azClientSecret = options.azClientSecret
this.azTenantId = options.azTenantId
this.credentialManifest = options.credentialManifest
constructor(options: IMsAuthenticationWrapperArgs) {
this.authenticationType = options.authenticationType
this.authenticationArgs = options.authenticationArgs
}

/** {@inheritDoc IMsVcApiIssuer.authenticateMsVcApi} */
public async authenticateMsVcApi(args: IMsAuthenticationArgs, context: IRequiredContext): Promise<IMsAuthenticationResponse> {
public async authenticateMsVcApi(): Promise<IMsAuthenticationResponse> {
let accessToken = ''
console.log('authenticationType:',this.authenticationType, 'authenticationArgs:',this.authenticationArgs)
/*this.authenticationType = args.authenticationType
this.authenticationArgs = args.authenticationArgs*/
if (this.authenticationType === 'ClientCredential') {
accessToken = await this.authenticateWithClientCredential(this.authenticationArgs as IMsAuthenticationClientCredentialArgs)
} else if (this.authenticationType === 'UsernamePassword') {
accessToken = await this.authenticateWithUsernamePassword(this.authenticationArgs as IMsAuthenticationUsernamePasswordArgs)
} else {
throw new Error(`method of authentication ${this.authenticationType} is not supported!`)
}
return accessToken as IMsAuthenticationResponse
}

private async authenticateWithClientCredential(authneticationArgs: IMsAuthenticationClientCredentialArgs) {
var msalConfig = {
auth: {
clientId: this.azClientId,
authority: 'https://login.microsoftonline.com/' + this.azTenantId,
clientSecret: this.azClientSecret,
clientId: authneticationArgs.azClientId,
authority: 'https://login.microsoftonline.com/' + authneticationArgs.azTenantId,
clientSecret: authneticationArgs.azClientSecret,
},
system: {
loggerOptions: {
piiLoggingEnabled: false,
logLevel: LogLevel.Verbose,
}
}
};
}

const cca = new ConfidentialClientApplication(msalConfig);
const cca = new ConfidentialClientApplication(msalConfig)
const msalClientCredentialRequest = {
scopes: ["3db474b9-6a0c-4840-96ac-1fceb342124f/.default"],
scopes: ['3db474b9-6a0c-4840-96ac-1fceb342124f/.default'],
skipCache: false,
};

var accessToken = "";

await fetch('https://login.microsoftonline.com/' + this.azTenantId + '/v2.0/.well-known/openid-configuration', { method: 'GET' })
.then(res => res.json())
}
await fetch('https://login.microsoftonline.com/' + authneticationArgs.azTenantId + '/v2.0/.well-known/openid-configuration', { method: 'GET' })
.then((res) => res.json())
.then(async (resp) => {
console.log(`tenant_region_scope = ${resp.tenant_region_scope}`);
this.msIdentityHostName = "https://beta.did.msidentity.com/v1.0/";
if (resp.tenant_region_scope == "EU") {
this.msIdentityHostName = "https://beta.eu.did.msidentity.com/v1.0/";
console.log(`tenant_region_scope = ${resp.tenant_region_scope}`)
let msIdentityHostName = 'https://beta.did.msidentity.com/v1.0/'
if (resp.tenant_region_scope == 'EU') {
msIdentityHostName = 'https://beta.eu.did.msidentity.com/v1.0/'
}
// Check that the Credential Manifest URL is in the same tenant Region and throw an error if it's not
if (!this.credentialManifest.startsWith(this.msIdentityHostName)) {
throw new Error(`Error in config file. CredentialManifest URL configured for wrong tenant region. Should start with:` + this.msIdentityHostName);
if (!authneticationArgs.credentialManifest.startsWith(msIdentityHostName)) {
throw new Error(`Error in config file. CredentialManifest URL configured for wrong tenant region. Should start with:` + msIdentityHostName)
}


// get the Access Token
try {
const result = await cca.acquireTokenByClientCredential(msalClientCredentialRequest);
const result = await cca.acquireTokenByClientCredential(msalClientCredentialRequest)
if (result) {
accessToken = result.accessToken;
return result.accessToken
}
} catch {
console.log("failed to get access token");
console.log('failed to get access token')
resp.status(401).json({
'error': 'Could not acquire credentials to access your Azure Key Vault'
});
return;
error: 'Could not acquire credentials to access your Azure Key Vault',
})
return
}
console.log(`accessToken: ${accessToken}`);
});
return accessToken as IMsAuthenticationResponse;
return ''
})
return ''
}

private async authenticateWithUsernamePassword(authenticationArgs: IMsAuthenticationUsernamePasswordArgs) {
const msalConfig = {
auth: {
clientId: authenticationArgs.azClientId,
authority: 'https://login.microsoftonline.com/' + authenticationArgs.azTenantId,
},
}
const pca = new PublicClientApplication(msalConfig)
//TODO(sksadjad): see if it's necessary need to fill in the scopes here
return await pca
.acquireTokenByUsernamePassword(authenticationArgs as UsernamePasswordRequest)
.then((response: any) => {
console.log('acquired token by password grant', response)
return response
})
.catch((error: any) => {
console.log(error)
})
}
}
Loading

0 comments on commit 9fefae8

Please sign in to comment.