Gerenios / AADInternals

AADInternals PowerShell module for administering Azure AD and Office 365
http://aadinternals.com/aadinternals
MIT License
1.24k stars 214 forks source link

Use BPRT for AzureAD Join #2

Closed dkattan closed 3 years ago

dkattan commented 3 years ago

Hey @NestoriSyynimaa

I'm looking for a programmatic way to join real devices to AzureAD. Playing with your module, it appears that Join-AADIntDeviceToAzureAD creates a "fake" device and doesn't actual join your device.

Outside of Autopilot, the only supported way to programmatically join AzureAD is by creating and applying a provisioning profile using Windows Configuration Designer.

Windows Configuration Designer creates and accepts a "BPRT"

During creation you do this: image

image

Then you get a BPRT value that starts with 0. image

However when I run Get-AADIntAccessTokenForAADJoin I get a token that starts with eyJ image

I believe the one it wants is encrypted as I'm not able to decode it using jwt.io

Is there a way your library can produce the BPRT in the format necessary for Windows Configuration Designer?

If it helps, it appears that Windows Configuration Designer spawns Microsoft.AAD.BrokerPlugin.exe to generate this token. C:\Windows\SystemApps\Microsoft.AAD.BrokerPlugin_cw5n1h2txyewy\Microsoft.AAD.BrokerPlugin.exe -ServerName:App.AppXgvz9wxd0frjs1prgz5kvtcz083996jyv.mca

NestoriSyynimaa commented 3 years ago

You can do a "normal" PRT with AADInternals, but I don't think it works in your case. But I'll take a look at this later this week.

NestoriSyynimaa commented 3 years ago

@dkattan, I was able to create a BPRT but I haven't been able to test it. Could you kindly test the following code? To test, first open the AccessToken_utils.ps1 file from the AADInternals installation location with PowerShell ISE. The location can be found:

Get-Module AADInternals | select path

When the file is opened, run it by pressing F5.

After that, create a new file with the following content and run it.

$AccessToken = Get-AccessToken -ClientId "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "urn:ms-drs:enterpriseregistration.windows.net" -Credentials $cred

$headers = @{
    "Authorization" = "Bearer $AccessToken"
}

$guid = (New-Guid).ToString()

$body = @{
    "pid" = $guid
    "name" = "package_$guid"
    "exp" =  (Get-Date).AddMonths(1).ToString("MM/dd/yyyy")
}

# Make the first request to get flowToken
$response = Invoke-RestMethod -Method Post -UseBasicParsing -Uri "https://login.microsoftonline.com/webapp/bulkaadjtoken/begin" -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json"

if($response.state -like "*Error*")
{
    $resultData = $response.resultData | ConvertFrom-Json
    throw $resultData.error_description
}

# Get the BPRT
$response = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "https://login.microsoftonline.com/webapp/bulkaadjtoken/poll?flowToken=$($response.flowToken)" -Headers $headers

$response.resultData | ConvertFrom-Json
dkattan commented 3 years ago

This totally worked! I'm wondering if it would be possible to do this without needing to use the PowerShell Module ClientID + Username and Password and instead use my own App Registration with a Client Secret.

NestoriSyynimaa commented 3 years ago

Good to hear!

Sure, you should be able to do this with an App.

Before you begin, you need to register an app with permissions (or scope) "policy_management". See this link for more details. After registering your app, you can get an access token and use it in the script.

dkattan commented 3 years ago

Is that policy_management scope in the Add API Permission UI in Azure?

Closest I could find is Policy.ReadWrite.PermissionGrant image

Googling, I can't seem to find much on this policy_management permission.

I know that there are permissions not listed there, for example when I use Kelvin's script to generate an App Registration, 1cebfa2a-fb4d-419e-b5f9-839b4383e05a correlates to a Partner Center API permission that isn't listed in the UI, but you can add it to the manifest and it shows up:

$partnerCenterAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
    ResourceAppId = "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd";
    ResourceAccess =
        [Microsoft.Open.AzureAD.Model.ResourceAccess]@{
            Id = "1cebfa2a-fb4d-419e-b5f9-839b4383e05a";
            Type = "Scope"}
}

image

Do you perhaps know the Guid for the permission/scope in question?

Out of curiosity, how'd you determine the policy_management permission/scope is what's required?

NestoriSyynimaa commented 3 years ago

I found the scope from the access token used to create the BPRT token:

image

I'll check which API permissions are required from the app.

dkattan commented 3 years ago

Is it possible to retrieve the manifest for well-known appids like 1b730954-1685-4b74-9bfd-dac224a7b894?

NestoriSyynimaa commented 3 years ago

This seems to be un-doable as the service doing the registration requires an access token with a scope (or resource) of "urn:ms-drs:enterpriseregistration.windows.net" and upn claim to be present ☹ So, I'm afraid you need to stick to a user.

What comes to manifests, I haven't find a to retrieve them (besides the apps you've registered your self).

dkattan commented 3 years ago

Hey, that’s all I needed to know. Thank you so much, this is going to be tremendously valuable!