diff --git a/CurrentReleaseNotes.md b/CurrentReleaseNotes.md index 979d3cd..2621ee6 100644 --- a/CurrentReleaseNotes.md +++ b/CurrentReleaseNotes.md @@ -1,7 +1,5 @@ ## Related Issues -- ### [Issue0038](https://github.com/expertasolutions/AzureADApplicationExtensions/issues/38) +- ### [Issue0041](https://github.com/expertasolutions/AzureADApplicationExtensions/issues/41) - - Add the Release notes support for GitHub release to the VisualStudio Marketplace page - - ![Issue0038-01](_ReleaseNotes/Issue0038/Issue0038-01.png) \ No newline at end of file + - Add the ability to update Azure AD Application Owner and Permissions \ No newline at end of file diff --git a/ManageAzureAdApplication/index.ts b/ManageAzureAdApplication/index.ts index 45dee4c..09156b2 100644 --- a/ManageAzureAdApplication/index.ts +++ b/ManageAzureAdApplication/index.ts @@ -1,6 +1,10 @@ import tl = require('azure-pipelines-task-lib/task'); import msRestNodeAuth = require('@azure/ms-rest-nodeauth'); import azureGraph = require('@azure/graph'); +import { RequiredResourceAccess, ServicePrincipal, OAuth2PermissionGrantListOptionalParams } from '@azure/graph/src/models'; +import { ServicePrincipalObjectResult } from '@azure/graph/esm/models/mappers'; +import { async, race } from 'q'; +import { RequestPrepareOptions } from '@azure/ms-rest-js'; function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); @@ -23,6 +27,26 @@ async function FindAzureAdApplication(applicationName:string, graphClient:azureG } } +async function FindServicePrincipal ( + applicationId:string + , graphClient:azureGraph.GraphRbacManagementClient +) { + console.log("List Service Principal ..."); + + var resourceAppFilter = { + filter: "appId eq '" + applicationId + "'" + }; + + let searchResults = await graphClient.servicePrincipals.list(resourceAppFilter); + if(searchResults.length === 0){ + return undefined; + } else { + let srvPrincipal = searchResults[0]; + srvPrincipal = await graphClient.servicePrincipals.get(srvPrincipal.objectId); + return srvPrincipal; + } +} + async function CreateServicePrincipal( applicationName:string , applicationId:string @@ -34,6 +58,7 @@ async function CreateServicePrincipal( appId: applicationId }; let result = await graphClient.servicePrincipals.create(serviceParms); + // Delay for the Azure AD Application and Service Principal... await delay(60000); return result; @@ -45,11 +70,20 @@ async function AddADApplicationOwner( , tenantId:string , graphClient:azureGraph.GraphRbacManagementClient) { + console.log("Add Application Owner ... "); + let urlGraph = 'https://graph.windows.net/' + tenantId + '/directoryObjects/' + ownerId; var ownerParm = { - url: 'https://graph.windows.net/' + tenantId + '/directoryObjects/' + ownerId + url: urlGraph }; - console.log(" Adding owner to Azure ActiveDirectory Application ..."); - return await graphClient.applications.addOwner(applicationObjectId, ownerParm); + + let owners = await graphClient.applications.listOwners(applicationObjectId); + if(owners.find(x=> x.objectId === ownerId)) { + console.log(" Owner already existing on the Azure ActiveDirectory Application"); + return undefined; + } else { + console.log(" Adding owner to Azure ActiveDirectory Application ..."); + return await graphClient.applications.addOwner(applicationObjectId, ownerParm); + } } async function CreateOrUpdateADApplication( @@ -94,36 +128,52 @@ async function CreateOrUpdateADApplication( }; if(appObjectId == null){ - let createResult = await graphClient.applications.create(newAppParms); + await graphClient.applications.create(newAppParms); // Delay for the Azure AD Application and Service Principal... await delay(10000); return await FindAzureAdApplication(applicationName, graphClient); } else { - let updateResult = await graphClient.applications.patch(appObjectId, newAppParms); - + await graphClient.applications.patch(appObjectId, newAppParms); // Delay for the Azure AD Application and Service Principal... await delay(10000); - return await FindAzureAdApplication(applicationName, graphClient); } } +async function deleteAuth2Permissions ( + objectId: string +, graphClient:azureGraph.GraphRbacManagementClient +) { + console.log("Delete Auth2Permissions ... of : " + objectId); + let options: OAuth2PermissionGrantListOptionalParams = { + filters: objectId + }; + + let result = graphClient.oAuth2PermissionGrant.list(options); + + console.log("------"); + console.log(JSON.stringify(result)); + console.log("------"); + return await graphClient.oAuth2PermissionGrant.deleteMethod(objectId) +} + async function grantAuth2Permissions ( rqAccess: any , servicePrincipalId:string , graphClient:azureGraph.GraphRbacManagementClient ) { - console.log("Grant Auth2Permissions ..."); + console.log("Grant Auth2Permissions '" + rqAccess.resourceAppId + "' ..."); var resourceAppFilter = { filter: "appId eq '" + rqAccess.resourceAppId + "'" }; - var rs = await graphClient.servicePrincipals.list(resourceAppFilter); - var srv = rs[0]; - var desiredScope = ""; - for(var i=0;i { @@ -135,7 +185,7 @@ async function grantAuth2Permissions ( var now = new Date(); const nextYear = new Date(now.getFullYear()+1, now.getMonth(), now.getDay()); - + var permissions = { body: { clientId: servicePrincipalId, @@ -145,7 +195,13 @@ async function grantAuth2Permissions ( expiryTime: nextYear.toISOString() } } as azureGraph.GraphRbacManagementModels.OAuth2PermissionGrantCreateOptionalParams; - return await graphClient.oAuth2PermissionGrant.create(permissions) + + try { + await graphClient.oAuth2PermissionGrant.create(permissions); + console.log(" Permissions granted for '" + rqAccess.resourceAppId + "'"); + } catch { + console.log(" Permissions already granted for '" + rqAccess.resourceAppId + "'"); + } } async function run() { @@ -183,37 +239,57 @@ async function run() { var graphClient = new azureGraph.GraphRbacManagementClient(pipeCreds, tenantId, { baseUri: 'https://graph.windows.net' }); let applicationInstance = await FindAzureAdApplication(applicationName, graphClient); - if(applicationInstance === null){ + if(applicationInstance === null) { // Create new Azure AD Application applicationInstance = await CreateOrUpdateADApplication(null, applicationName, rootDomain, applicationSecret, homeUrl, taskReplyUrls, requiredResource, graphClient); - // Add Owner to new Azure AD Application - await AddADApplicationOwner(applicationInstance.objectId as string, ownerId, tenantId, graphClient); - // Create Service Principal for Azure AD Application let newServicePrincipal = await CreateServicePrincipal(applicationName, applicationInstance.appId as string, graphClient); - // Set Application Permission + // Set Application Permissions for(var i=0;i x.clientId === service.objectId); + console.log("-----"); + console.log(JSON.stringify(currentGrants)); + console.log("-----") + for(let i=0;i=0.6.0", - "util.promisify": "~1.0.0", "xmlbuilder": "~11.0.0" } }, @@ -823,9 +842,9 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.3.0.tgz", + "integrity": "sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==" }, "xpath.js": { "version": "1.1.0", diff --git a/ManageAzureAdApplication/package.json b/ManageAzureAdApplication/package.json index 4c0e1b7..d0f768d 100644 --- a/ManageAzureAdApplication/package.json +++ b/ManageAzureAdApplication/package.json @@ -11,10 +11,10 @@ "author": "Solutions Experta Inc.", "license": "MIT", "dependencies": { - "@azure/graph": "^5.0.0", + "@azure/graph": "^5.0.1", "@azure/ms-rest-nodeauth": "^2.0.5", "azure-pipelines-task-lib": "^2.9.3", - "typescript": "^3.7.2" + "typescript": "^3.9.5" }, "devDependencies": { "@types/node": "^12.12.7",