import * as uuid from 'uuid' ; import { AzureEnvironment , DeviceTokenCredentials } from 'ms-rest-azure' ; import { ServiceClientCredentials } from 'ms-rest' ; import AuthorizationManagementClient = require ( 'azure-arm-authorization' ) ; export interface IAzureHelper { assignContributorRoleOnSubscription ( principalId ) : Promise < boolean > ; assignContributorRoleOnResourceGroup ( principalId , resourceGroupName ) : Promise < boolean > ; assignOwnerRoleOnSubscription ( principalId ) : Promise < boolean > ; assignOwnerRoleOnResourceGroup ( principalId , resourceGroupName ) : Promise < boolean > ; createRoleAssignmentWithRetry ( principalId , roleId , scope ) : Promise < boolean > ; getAuthIssuserUrl ( tenantId ) : string ; getStorageEndpointSuffix ( ) : string ; getVMFQDNSuffix ( ) : string ; getServiceBusEndpointSuffix ( ) : string ; getPortalUrl ( ) : string ; getCloudType ( ) : string ; } export class AzureHelper implements IAzureHelper { private _environment : AzureEnvironment ; private _credentials : ServiceClientCredentials ; private _subscriptionId : string ; private MAX_RETRYCOUNT = 36 ; private SLEEP_TIME = 5000 ; private CONTRIBUTOR_ROLE_ID = 'b24988ac-6180-42a0-ab88-20f7382dd24c' ; private OWNER_ROLE_ID = '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' ; constructor ( environment , subscriptionId , credentials ) { this . _environment = environment ; this . _subscriptionId = subscriptionId ; this . _credentials = credentials ; } public assignContributorRoleOnSubscription ( principalId ) { const scope = `/subscriptions/${ this . _subscriptionId }` ; return this . createRoleAssignmentWithRetry ( principalId , scope , this . CONTRIBUTOR_ROLE_ID ) ; } public assignContributorRoleOnResourceGroup ( principalId , resourceGroupName ) { const scope = `/subscriptions/${ this . _subscriptionId }/resourceGroups/${ resourceGroupName }` ; return this . createRoleAssignmentWithRetry ( principalId , scope , this . CONTRIBUTOR_ROLE_ID ) ; } public assignOwnerRoleOnSubscription ( principalId ) { const scope = `/subscriptions/${ this . _subscriptionId }` ; return this . createRoleAssignmentWithRetry ( principalId , scope , this . OWNER_ROLE_ID ) ; } public assignOwnerRoleOnResourceGroup ( principalId , resourceGroupName ) { const scope = `/subscriptions/${ this . _subscriptionId }/resourceGroups/${ resourceGroupName }` ; return this . createRoleAssignmentWithRetry ( principalId , scope , this . OWNER_ROLE_ID ) ; } public createRoleAssignmentWithRetry ( principalId , scope , roleId ) { const roleDefinitionId = `${ scope }/providers/Microsoft.Authorization/roleDefinitions/${ roleId }` ; const baseUri = this . _environment ? this . _environment . resourceManagerEndpointUrl : undefined ; const authzClient = new AuthorizationManagementClient ( this . getPatchedDeviceTokenCredentials ( this . _credentials ) , this . _subscriptionId , baseUri ) ; const assignmentName = uuid . v1 ( ) ; const roleAssignment = { properties : { principalId , roleDefinitionId , scope } } ; let retryCount = 0 ; const promise = new Promise < any > ( ( resolve , reject ) => { const timer = setInterval ( ( ) => { retryCount ++ ; return authzClient . roleAssignments . create ( scope , assignmentName , roleAssignment ) . then ( ( roleResult ) => { setTimeout ( ( ) => { clearInterval ( timer ) ; resolve ( true ) ; } , this . SLEEP_TIME ) ; } ) . catch ( ( error ) => { if ( retryCount >= this . MAX_RETRYCOUNT ) { clearInterval ( timer ) ; console . log ( error ) ; reject ( error ) ; } else if ( error . statusCode && error . statusCode === 403 ) { clearInterval ( timer ) ; resolve ( false ) ; } } ) ; } , this . SLEEP_TIME ) ; } ) ; return promise ; } public getAuthIssuserUrl ( tenantId ) { switch ( this . _environment . name ) { case AzureEnvironment . AzureChina . name : return `https://sts.chinacloudapi.cn/${ tenantId }/` ; default : return `https://sts.windows.net/${ tenantId }/` ; } } public getStorageEndpointSuffix ( ) { let storageEndpointSuffix = this . _environment . storageEndpointSuffix ; if ( storageEndpointSuffix . startsWith ( '.' ) ) { storageEndpointSuffix = storageEndpointSuffix . substring ( 1 ) ; } return storageEndpointSuffix ; } public getVMFQDNSuffix ( ) { switch ( this . _environment . name ) { case AzureEnvironment . AzureChina . name : return 'cloudapp.chinacloudapi.cn' ; case AzureEnvironment . AzureGermanCloud . name : return 'cloudapp.azure.de' ; case AzureEnvironment . AzureUSGovernment . name : return 'cloudapp.azure.us' ; default : return 'cloudapp.azure.com' ; } } public getServiceBusEndpointSuffix ( ) { switch ( this . _environment . name ) { case AzureEnvironment . AzureChina . name : return 'servicebus.chinacloudapi.cn' ; default : return 'servicebus.windows.net' ; } } public getPortalUrl ( ) { return this . _environment . portalUrl || AzureEnvironment . Azure . portalUrl ; } public getCloudType ( ) { const cloudTypeMaps = { [ AzureEnvironment . Azure . name ] : 'Global' , [ AzureEnvironment . AzureChina . name ] : 'China' , [ AzureEnvironment . AzureUSGovernment . name ] : 'Fairfax' , [ AzureEnvironment . AzureGermanCloud . name ] : 'Germany' , } ; return cloudTypeMaps [ this . _environment . name ] ; } private getPatchedDeviceTokenCredentials ( options ) { const credentials = new DeviceTokenCredentials ( options ) ; if ( credentials . hasOwnProperty ( 'username' ) && credentials . username === 'user@example.com' ) { delete credentials . username ; } return credentials ; } }