-
Notifications
You must be signed in to change notification settings - Fork 686
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #112 from ali92hm/master
Added instructions for programatic api access
- Loading branch information
Showing
5 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
246 changes: 246 additions & 0 deletions
246
blockchain-workbench/scripts/workbench-serviceprincipal/createWorkbenchServicePrincipal.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
<# | ||
.SYNOPSIS | ||
This script creates a service principal that can be used to access Workbench's API programmatically | ||
.DESCRIPTION | ||
The script performs the following tasks: | ||
- Creates a Service Principal and assigns it to Workbench | ||
- Can assign the service principal to be an Admin on Workbench | ||
.INPUTS | ||
None. You cannot pipe objects to this script. | ||
.OUTPUTS | ||
The status of the update | ||
.EXAMPLE | ||
createServicePrincipal.ps1 -TenantName [blockchaindemos.onmicrosoft.com] -WorkbenchAppId [My Workbench AppId] | ||
#> | ||
|
||
param( | ||
[Parameter(Mandatory=$true)][string]$TenantName, | ||
[Parameter(Mandatory=$true)][string]$WorkbenchAppId, | ||
[Parameter(Mandatory=$false)][string]$SpName="Service Principal for Workbench API", | ||
[Parameter(Mandatory=$false)][switch]$MakeAdmin | ||
) | ||
|
||
function Log-Debug { | ||
param( | ||
[Parameter(Mandatory=$false)][string]$Message | ||
) | ||
|
||
if ($Message) { | ||
Write-Verbose $Message | ||
} | ||
} | ||
|
||
function Log-Info { | ||
param( | ||
[Parameter(Mandatory=$false)][string]$Message | ||
) | ||
|
||
if ($Message) { | ||
Write-Host "INFO:", $Message | ||
} | ||
} | ||
|
||
function Log-Success { | ||
param( | ||
[Parameter(Mandatory=$false)][string]$Message | ||
) | ||
|
||
if ($Message) { | ||
Write-Host "SUCCESS:", $Message -foregroundcolor green | ||
} | ||
} | ||
|
||
function Log-Warning { | ||
param( | ||
[Parameter(Mandatory=$false)][string]$Message, | ||
[Parameter(Mandatory=$false)][string]$Exception | ||
) | ||
|
||
if ($Message) { | ||
Write-Warning $Message | ||
} | ||
|
||
if ($Exception) { | ||
Write-Host "ERROR MESSAGE:" $Exception -foregroundcolor yellow | ||
} | ||
} | ||
|
||
function Log-Error { | ||
param( | ||
[Parameter(Mandatory=$false)][string]$Message, | ||
[Parameter(Mandatory=$false)][string]$Exception, | ||
[Parameter(Mandatory=$false)][switch]$Exit | ||
) | ||
|
||
if ($Message) { | ||
Write-Host "ERROR:" $Message -foregroundcolor red | ||
} | ||
|
||
if ($Exception) { | ||
Write-Host "ERROR MESSAGE:" $Exception -foregroundcolor red | ||
} | ||
|
||
if ($Exit) { | ||
exit 1 | ||
} | ||
} | ||
|
||
################################################################################# | ||
# Import Azure tools | ||
################################################################################# | ||
# For CloudShell | ||
if (Get-Module -ListAvailable -Name "AzureAD.Standard.Preview") { | ||
Log-Debug "Importing module AzureAD.Standard.Preview" | ||
Import-Module "AzureAD.Standard.Preview" | ||
# For Windows PowerShell | ||
} elseif (Get-Module -ListAvailable -Name "AzureADPreview") { | ||
Log-Debug "Importing module AzureADPreview" | ||
Import-Module "AzureADPreview" | ||
} elseif (Get-Module -ListAvailable -Name "AzureAD") { | ||
Log-Debug "Importing module AzureAD" | ||
Import-Module "AzureAD" | ||
} else { | ||
Log-Error "This script is not compatible with your computer, Please use Azure CloudShell https://shell.azure.com/powershell" -Exit | ||
} | ||
|
||
Log-Debug "Running script with params:" | ||
Log-Debug "TenantName: $TenantName" | ||
Log-Debug "AppId: $WorkbenchAppId" | ||
|
||
try { | ||
Log-Debug "Trying to login to $TenantName" | ||
Log-Info "Logging in to AAD" | ||
$currentUser = Connect-AzureAD -TenantId $TenantName -ErrorAction SilentlyContinue | ||
Log-Debug $currentUser | ||
} catch { | ||
Log-Error "There was a problem with login. Please try again." -Exception $_ -Exit | ||
} | ||
|
||
################################################################################# | ||
# Retrieving Workbench Application and Service Principal | ||
################################################################################# | ||
|
||
try { | ||
$workbenchApplication = Get-AzureADApplication -Filter "AppId eq '$WorkbenchAppId'" | ||
Log-Debug $workbenchApplication | ||
} catch { | ||
Log-Error "Could not find an application with Id $WorkbenchAppId in directory $TenantName" -Exception $_ -Exit | ||
} | ||
|
||
try { | ||
$workbenchSP = Get-AzureADServicePrincipal -Filter "AppId eq '$WorkbenchAppId'" | ||
Log-Debug $workbenchSP | ||
} catch { | ||
Log-Error "Could not find a service principal with Id $WorkbenchAppId in directory $TenantName" -Exception $_ -Exit | ||
} | ||
|
||
################################################################################# | ||
# Creating the App Registration | ||
################################################################################# | ||
|
||
try { | ||
Log-Info 'Creating the App registration' | ||
$application = New-AzureADApplication ` | ||
-DisplayName $SpName ` | ||
-IdentifierUris "https://$TenantName/$([System.GUID]::NewGuid().ToString())" ` | ||
-PasswordCredentials $appSecret | ||
|
||
$password = New-AzureADApplicationPasswordCredential ` | ||
-ObjectId $application.ObjectId ` | ||
-EndDate $(Get-Date).AddYears(2) | ||
} catch { | ||
# The user cannot create apps in their directory | ||
if ($_.Exception.Message -like "*Authorization_RequestDenied*") { | ||
Log-Error "You do not have sufficient privileges to create an application in this tenant. Please chose another tenant or have the tenant admin run this script. https://aka.ms/workbenchFAQ " -Exception $_ -Exit | ||
} else { | ||
Log-Error "Creating application failed. Please try again. https://aka.ms/workbenchFAQ" -Exception $_ -Exit | ||
} | ||
} | ||
|
||
################################################################################# | ||
# Assigning the User Application (Optional) | ||
################################################################################# | ||
|
||
Log-Info "Looking for your user '$($currentUser.Account.Id)' in '$TenantName' tenant" | ||
try { | ||
$matchedUsers = Get-AzureADUser -Filter "mail eq '$($currentUser.Account.Id)' or userPrincipalName eq '$($currentUser.Account.Id)' or OtherMails eq '$($currentUser.Account.Id)'" | ||
Log-Debug $matchedUsers | ||
} catch { | ||
Log-Warning "Failed to retrieve your user information. Please refer to the docs to manually add yourself as an admin. https://aka.ms/workbenchAADSteps" -Exception $_ | ||
} | ||
|
||
|
||
if ($matchedUsers -And $matchedUsers.length -gt 0) { | ||
Log-Info "$($matchedUsers.length) user(s) were found with email '$($currentUser.Account.Id)'" | ||
$user = $matchedUsers[0] | ||
Log-Debug $user | ||
|
||
try { | ||
Log-Info "Assign the current logged in user to be the owner of the Application." | ||
$ownerAssignment = Add-AzureADApplicationOwner ` | ||
-ObjectId $application.ObjectId ` | ||
-RefObjectId $user.ObjectId | ||
Log-Debug "Successfully assigned the user as the application owner" | ||
Log-Debug $ownerAssignment | ||
} catch { | ||
Log-Debug "Failed assigned the user as the application owner. The user is probably already an owner" | ||
Log-Debug $_ | ||
} | ||
} | ||
|
||
################################################################################# | ||
# Create Service Principal | ||
################################################################################# | ||
Log-Info 'Creating the Service Principal for Azure Blockchain Workbench ' | ||
try { | ||
$sp = New-AzureADServicePrincipal -AppId $application.AppId | ||
Log-Debug "Successfully created Service Principal" | ||
Log-Debug $sp | ||
} catch { | ||
Log-Error 'Failed to create Service Principal. Please try again.' -Exception $_ -Exit | ||
} | ||
|
||
################################################################################# | ||
# Assign Service Principal to the admin role | ||
################################################################################# | ||
if ($MakeAdmin) { | ||
|
||
$adminAppRole = $null | ||
# Looking for the App role with the Value of "Administrator" | ||
ForEach ($appRole in $workbenchApplication.AppRoles) { | ||
if ($appRole.Value -eq "Administrator") { | ||
$adminAppRole= $appRole | ||
break; | ||
} | ||
} | ||
|
||
if (-Not $adminAppRole) { | ||
Log-Error "Could not find the Admin app role for Application with AppId $WorkbenchAppId" -Exit | ||
} | ||
|
||
Log-Debug $adminAppRole | ||
|
||
try { | ||
$roleAssignment = New-AzureADServiceAppRoleAssignment ` | ||
-Id $adminAppRole.Id ` | ||
-ObjectId $sp.ObjectId ` | ||
-PrincipalId $sp.ObjectId ` | ||
-ResourceId $workbenchSP.ObjectId | ||
|
||
Log-Info "Successfully created role assignment" | ||
Log-Debug $roleAssignment | ||
} catch { | ||
Log-Error "Could not add service principal as an admin." -Exception $_ -Exit | ||
} | ||
} | ||
|
||
|
||
Log-Debug $application | ||
|
||
Write-Host | ||
Write-Host | ||
|
||
Log-Success "Successfully created Service Principal" | ||
Log-Info "AppId: $($application.AppId)" | ||
Log-Info "AppKey: $($password.Value)" | ||
Write-Host "==============================================================================================" |
Binary file added
BIN
+274 KB
blockchain-workbench/scripts/workbench-serviceprincipal/media/cloudshell-open.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+376 KB
blockchain-workbench/scripts/workbench-serviceprincipal/media/download-script.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+427 KB
blockchain-workbench/scripts/workbench-serviceprincipal/media/final.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions
67
blockchain-workbench/scripts/workbench-serviceprincipal/readme.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Creating a Service Principal to Access Workbench API | ||
|
||
|
||
Overview | ||
================= | ||
Workbench uses OAuth 2.0 to secure its resources. The Auth provider for Workbench is [Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-scenarios). | ||
|
||
In order to use Workbench's API you need to set the `Authorization: Bearer <access_token>` in your HTTP header. This access token can be obtained in a number of different ways depending on the [authentication scenarios](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-types). | ||
|
||
If you are trying to consume Workbench's [API programmatically](https://docs.microsoft.com/en-us/azure/active-directory/develop/service-to-service), you need to use the [client credentials flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow) using a [service principal](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals). This document will provide you a script that will create a service principal for you in order to access Workbench programatically. | ||
|
||
|
||
Access Control | ||
================= | ||
By default any service principal in Workbench's active directory has access to Workbench resources just like any user in that directory. However, just like any user, all service principals by default only have User level access and not Admin level access. | ||
|
||
Admin level access is needed if you are trying to create Applications, read all applications, create users, and create role assignments. | ||
|
||
> Note: Since service principals act like users in a directory they can be assigned to different Workbench "application roles". For example if you are trying to use a service principal to create contracts, you need to assign that service principal to the "creator" role of that application. Today this operation has to be done using the Workbench API as the UI does not allow for service principal role assignment. | ||
|
||
It can be tricky to create a service principal and assign it to Workbench as an Admin, so we've provided an automated a script to create a service principal and you have the option to make that service principal an Admin. | ||
|
||
Execution Instructions | ||
================= | ||
To run this script you need to have the [AzureAD](https://docs.microsoft.com/en-us/powershell/module/azuread/?view=azureadps-2.0) module installed. Since the AzureAD PowerShell module only works on Windows, we recommend using [Azure CloudShell](https://shell.azure.com/powershell) since it comes with with all dependencies installed. | ||
|
||
|
||
1. Open [Azure CloudShell](https://shell.azure.com/powershell) and select the tenant tied to your Azure Subscription. | ||
|
||
![CloudShell open](./media/cloudshell-open.png) | ||
|
||
2. Download the script. You can download the upgrade script automatically by using the command bellow, or you can download it from this repository manually | ||
|
||
```powershell | ||
cd; Invoke-WebRequest -Uri https://aka.ms/createWorkbenchServicePrincipalScript -OutFile createWorkbenchServicePrincipal.ps1 | ||
``` | ||
|
||
![CloudShell download](./media/download-script.png) | ||
|
||
3. Locate your Workbench AAD AppId and Tenant and run the following commands. The `-MakeAdmin` parameter is optional and is only needed if want your service principal to have Admin level access. | ||
|
||
|
||
```powershell | ||
./createWorkbenchServicePrincipal.ps1 -TenantName <workbench tenant> -WorkbenchAppId <Workbench AAD AppId> -MakeAdmin (optional) | ||
``` | ||
|
||
![CloudShell final](./media/final.png) | ||
|
||
4. You can now use this `AppId` and `Key` with any [ADAL](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-libraries) library to obtain an access token. | ||
|
||
> Note: The target resource (audience) for accessing Workbench is the Workbench AppId, and the authority is https://login.microsoftonline.com/[tenantName] | ||
Here is an [example](https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-request) of a raw http call.: | ||
|
||
``` | ||
Method: POST | ||
URL: https://login.microsoftonline.com/<tenant>/oauth2/token | ||
Content-Type: application/x-www-form-urlencoded | ||
Body: | ||
grant_type=client_credentials | ||
&client_id=<service_principal_appId> | ||
&client_secret=<service_principal_key> | ||
&resource=<workbench_appId> | ||
``` |