0
votes

I am trying to use an Azure AD service principal in my AAD tenant to obtain an access token for the Azure AD Application proxy service, to be used to register a new connector. The service principal has the required permissions in my tenant to do this. Basically I am trying to adopt the following code to support authenticating with a principal instead of doing an interactive authentication flow. This would allow the service principal information and secret/cert to be obtained from a secure store and used in an automation pipeline. However, I have run out of skill! Does anyone know how to do this?

# Locate AzureAD PowerShell Module
 # Change Name of Module to AzureAD after what you have installed
 $AADPoshPath = (Get-InstalledModule -Name AzureAD).InstalledLocation
 # Set Location for ADAL Helper Library
 $ADALPath = $(Get-ChildItem -Path $($AADPoshPath) -Filter Microsoft.IdentityModel.Clients.ActiveDirectory.dll -Recurse ).FullName | Select-Object -Last 1

 # Add ADAL Helper Library
 Add-Type -Path $ADALPath

 #region constants

 # The AAD authentication endpoint uri
 [uri]$AadAuthenticationEndpoint = "https://login.microsoftonline.com/common/oauth2/token?api-version=1.0/" 

 # The application ID of the connector in AAD
 [string]$ConnectorAppId = "55747057-9b5d-4bd4-b387-abf52a8bd489"

 # The reply address of the connector application in AAD
 [uri]$ConnectorRedirectAddress = "urn:ietf:wg:oauth:2.0:oob" 

 # The AppIdUri of the registration service in AAD
 [uri]$RegistrationServiceAppIdUri = "https://proxy.cloudwebappproxy.net/registerapp"

 #endregion

 #region GetAuthenticationToken

 # Set AuthN context
 $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $AadAuthenticationEndpoint

 # Build platform parameters
 $promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
 $platformParam = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList $promptBehavior

 # Do AuthN and get token
 $authResult = $authContext.AcquireTokenAsync($RegistrationServiceAppIdUri.AbsoluteUri, $ConnectorAppId, $ConnectorRedirectAddress, $platformParam).Result

 # Check AuthN result
 If (($authResult) -and ($authResult.AccessToken) -and ($authResult.TenantId) ) {
 $token = $authResult.AccessToken
 $tenantId = $authResult.TenantId
 }
 Else {
 Write-Output "Authentication result, token or tenant id returned are null"
 }

 #endregion

My attempts always fail at the AcquireTokenAsync step.

Thanks!

1
I think you need to use a different overload of AcquireTokenAsync. One that takes a resource + client credential object.juunas

1 Answers

0
votes

You should consider using this overload of AuthenticationContext when you want to authenticate SP using secret (See documentation here):

public System.Threading.Tasks.Task<Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult> AcquireTokenAsync (string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential clientCredential);

// Sample code
var authContext = new AuthenticationContext("<authority uri>");
var clientCreds = new ClientCredential("<app id associated to sp>", "<app secret>");
authContext.AcquireTokenAsync("<resource>", clientCreds);

On the other hand, if you want to authenticate SP using a certificate, you should consider using this overload of AuthenticationContext (See documentation here):

public System.Threading.Tasks.Task<Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult> AcquireTokenAsync (string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.IClientAssertionCertificate clientCertificate);

// Sample code
// fetch certificate first
var storeName = StoreName.My;
var storeLocation = StoreLocation.LocalMachine; // if cert lives in local machine store, code needs to run as administrator
string certName = "<my cert subject name>"; // e.g. "CN = myspcertficate"
X509Store store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
X509Certificate2 cert = signingCert.OfType<X509Certificate2>().OrderByDescending(c => c.NotBefore).FirstOrDefault();
store.Close();
if (cert != null)
{
    var authContext = new AuthenticationContext("<authority uri>");
    authContext.AcquireTokenAsync("<resource>", "<app id associated to sp>", cert);
}