Replacing secret with certificate in Azure app registration - azure

I am currently using a client secret with an Azure app registration to access an Azure Media service from an App Service. I want to replace the client secret with a certificate as the certificate will last longer. I have successfully generated a certificate and uploaded it to the app registration.
Using the client secret seems straight forward. I create environment variables (in the app service configuration or local.settings.json) for the app registration client ID, app registration client secret and tenant ID and then use the following code:
private async Task<ServiceClientCredentials> GetCredentialsAsync(string aadClientId, string aadSecret, string aadTenantId)
{
ClientCredential clientCredential = new ClientCredential(aadClientId, aadSecret);
return await ApplicationTokenProvider.LoginSilentAsync(aadTenantId, clientCredential,
ActiveDirectoryServiceSettings.Azure);
}
How do I change this code to use the certificate?

I tried to reproduce the same in my environment and got the results like below:
I created an Azure AD Application and uploaded a certificate:
To generate the access token using certificate, you can declare the below parameters in your app.settings file:
"AzureAd": {
"Scope":"https://graph.microsoft/.default",
"Instance":"https://login.microsoftonline.com/",
"Domain":"XXX.onmicrosoft.com",
"TenantId":"YourTenantID",
"ClientId":"ClientID",
"ClientCertificates": [
{
"SourceType":"KeyVault",
"KeyVaultUrl":"https://xxx.vault.azure.net",
"KeyVaultCertificateName":"certName"
}
]
},
You can refer this blog by damienbod to know how generate the access token in detail.
I tried to generate the access token in Postman by using parameters like below:
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id:clientId
client_assertion_type:urn:ietf:params:oauth:client-assertion-type:jwt-bearer
scope:https://graph.microsoft.com/.default
grant_type:client_credentials
client_assertion:client_assertion
References:
Azure AD OAuth client credential flow with certificate by Nicola Delfino
App that calls MSGraph with a certificate by christosmatskas

Related

What is the authentication flow when calling Azure Service Bus from console app using Client Certificate with Azure AD App Registration

Using C#, I have created a console application that calls out to Azure Service Bus to send a message, having an app registration setup in Azure AD with a client certificate as the authentication.
I use the azure "ClientCertificateCredential" class for this.
This works.
However, I am unsure of the flow of this and how it works. What is it doing under the hood? How does it add that certificate to the request? Is it different from a TLS certificate? Is it just 1 call? Or is it doing anything with making 1 request, then getting a token returned, to make another? etc.
I have not managed to find a flow diagram of this.
Here is the test code for reference:
string tenantId = "xxx";
string clientId = "xxx";
string clientCertPath = "mykey.pem";
string queueName = "xxx";
string fullyQualifiedNamespace = "xxx.servicebus.windows.net";
TokenCredential credential = new ClientCertificateCredential(tenantId, clientId, clientCertPath);
var client = new ServiceBusClient(fullyQualifiedNamespace, credential);
ServiceBusSender sender = client.CreateSender(queueName);
ServiceBusMessage busMessage = new ServiceBusMessage("test");
sender.SendMessageAsync(busMessage).Wait();
Client Certificate Authentication is a mutual certificate based authentication, where the client provides its Client Certificate to the Server to prove its identity. This happens as a part of the SSL Handshake
ClientCertificateCredential Class enables authentication of a service principal (App Registration) in to Azure Active Directory using the client certificate that is assigned to it's App Registration
TokenCredential Class obtains the access token from the ClientCertificateCredential provided
This access token will be used to access Azure Service Bus
For more information on Client Certificate Authentication, you can refer this blog: Client Certificate Authentication - Microsoft Tech Community

Retrieve Azure KeyVault secret using client secret

I'm experimenting with various Azure features and currently want to retrieve a secret from KeyVault.
Straight to the case:
I'm using this nuget package to interact with my azure resources.
I've developed a simple .NET Core console app and run it locally.
I have a KeyVault resource with one secret defined which is active and not expired.
I've registered an App in AAD so my locally shipped .NET Core console app has an identity within AAD.
Than I've created a "client secret" within this registered app in AAD to use it to authenticate myself as an app.
After that I've added access policy in my KeyVault resource to allow GET operation for secrets for this registered app:
Then I've developed a small piece of code which should retrieve the desired secret:
public class AzureAuthentication
{
public async Task<string> GetAdminPasswordFromKeyVault()
{
const string clientId = "--my-client-id--";
const string tenantId = "--my-tenant-id--";
const string clientSecret = "--my-client-secret--";
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var client = new SecretClient(new Uri("https://mykeyvaultresource.vault.azure.net"), credentials);
var secret = await client.GetSecretAsync("admincreds");
return secret.Value.Value;
}
}
However when I'm trying to do this I'm getting an AccessDenied error:
Am I missing something painfully obvious here? Or there is some latency (>30 min for this moment) for which changes from Access policies screen in KeyVault resource are applied?
I test your code and Get permission, it works fine.
From your screenshot, it looks you didn't add the correct service principal related to the AD App to the Access policies.
If you add the service principal related to the AD App, it will appear as APPLICATION, not COMPOUND IDENTITY.
So when you add it, you could search for the client Id(i.e. application Id) or the name of your App Registration directly, make sure you add the correct one.
Make sure your AD App(service principal) has the correct permission in your keyvault -> Access policies

Azure AD OAuth 2.0 Auth Code Token Exchange using cert

The docs for the OAuth2 auth code to token exchange show making a request using client_id and client_secret. However is there a way to do this using cert based auth for the azure app?
Yes you can acquire tokens using a certificate instead of using client secret as well. It's covered as part of Client Credentials Grant.
Azure AD V1 Endpoint
Here is a detailed code sample - It makes use of a self signed certificate and uses Azure AD V1 endpoint
Authenticating to Azure AD in daemon apps with certificates
certCred = new ClientAssertionCertificate(clientId, cert);
result = await authContext.AcquireTokenAsync(todoListResourceId, certCred);
In case you're looking to make direct REST based calls (not using ADAL Library) here's a sample. You can read more details on each of the parameters here on Microsoft Docs:
Access token request with a certificate
POST /<tenant_id>/oauth2/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
resource=https%3A%2F%contoso.onmicrosoft.com%2Ffc7664b4-cdd6-43e1-9365-c2e1c4e1b3bf&client_id=97e0a5b7-d745-40b6-94fe-5f77d35c6e05&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg&grant_type=client_credentials
Azure AD V2 Endpoint
Using MSAL.NET Library you can do it like this. Both client secret and Certificate Credentials variations are shown here. (Certificate is covered in the else case)
More details available here - Client credential flows in MSAL.NET
// Even if this is a console application here, a daemon application is a confidential client application
IConfidentialClientApplication app;
#if !VariationWithCertificateCredentials
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithClientSecret(config.ClientSecret)
.Build();
#else
// Building the client credentials from a certificate
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithCertificate(certificate)
.Build();
#endif
// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
// a tenant administrator
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
}
catch(MsalServiceException ex)
{
// Case when ex.Message contains:
// AADSTS70011 Invalid scope. The scope has to be of the form "https://resourceUrl/.default"
// Mitigation: change the scope to be as expected
}
Again in case you're interested in making direct REST based calss (not using MSAL Library) here's a sample.You can read more details on each of the parameters here on Microsoft Docs:
Access token request with a certificate
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 // Line breaks for clarity
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_id=97e0a5b7-d745-40b6-94fe-5f77d35c6e05
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg
&grant_type=client_credentials

Support for user certificate authentification in Azure AD

I'am searching for public/private key-based authentication for users with Azure-ActiveDirectory but can't find any hints in Azure AD Authentification Scenarios. Every user should bring his own key pair. Any suggestions how to achieve it?
Azure AD supports OAuth 2.0 to authorize the third-party apps and the OAuth 2.0 support to acquire the token using the app’s client credential.
There are two ways to acquire the token for the client credential flow.
First is that using the keys which generated by the Azure portal like figure below:
And here is a figure about token request using the key(client_secret):
Another way is using the cert. Technical speaking, the cert is a pair of public/private key. We will store the information of public key with the app. When we require to prove we are the owner of the third-party apps, we need to sign the message with the private key and Azure AD with verify the messages with public key.
To store the cert information with apps, we need to change the manifest of app. Here is the detail steps to use a self-signed certificate from here:
1.Generate a self-signed certificate:
makecert -r -pe -n "CN=MyCompanyName MyAppName Cert" -b 03/15/2015 -e 03/15/2017 -ss my -len 2048
2.Open the Certificates MMC snap-in and connect to your user account.
3.Find the new certificate in the Personal folder and export the public key to a base64-encoded file (for example, mycompanyname.cer). Your application will use this certificate to communicate with AAD, so make sure you retain access to the private key as well.
Note You can use Windows PowerShell to extract the thumbprint and base64-encoded public key. Other platforms provide similar tools to retrieve properties of certificates.
4.From the Windows PowerShell prompt, type and run the following:
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("mycer.cer")
$bin = $cer.GetRawCertData()
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cer.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
$keyid = [System.Guid]::NewGuid().ToString()
5.Store the values for $base64Thumbprint, $base64Value and $keyid, to be used when you update your application manifest in the next set of steps.
Using the values extracted from the certificate and the generated key ID, you must now update your application manifest in Azure AD.
6.In the Azure Management Portal, select your application and choose Configure in the top menu.
7.In the command bar, click Manage manifest and select Download Manifest.
8.Open the downloaded manifest for editing and replace the empty KeyCredentials property with the following JSON:
"keyCredentials": [
{
"customKeyIdentifier": "$base64Thumbprint_from_above",
"keyId": "$keyid_from_above",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": "$base64Value_from_above"
}
],
9.Save your changes and upload the updated manifest by clicking Manage manifest in the command bar, selectingUpload manifest, browsing to your updated manifest file, and then selecting it.
And below is the figure about token request using the cert:
In the article above, it generate the client_assertion from scratch. We can also use the ADAL library to help us and authenticate for a daemon apps:
string authority = $"https://login.microsoftonline.com/{tenant}";
var thumbprint="";
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByThumbprint, thumbprint, false);
X509Certificate2 cert = fcollection[0];
var certCred = new ClientAssertionCertificate(clientId, cert);
var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
AuthenticationResult result = null;
try
{
result = await authContext.AcquireTokenAsync(resource, certCred);
}
catch (Exception ex)
{
}
return result.AccessToken;
And if you want to use the cert to authorize for the OAuth2.0 code grant flow, you also can refer the code sample here.
If you're looking for a programmatic method to authenticate users (not apps) in Azure AD using certificates, this is not currently possible.
It is possible to do certificate-based authentication in AD FS (e.g.), and it is possible to federate authentication for users from Azure AD to AD FS. However, this requires the overhead of Windows Server AD, Azure AD Connect and AD FS, and I don't think the federated authentication can be achieved in a programmatic way (i.e. without prompting the user to choose a certificate).

Setting jwt audience in Azure Mobile Apps backend

I am playing with an Azure Mobile Apps backend (nodeJS), as discussed here. I have been using the default web setup configuration to develop my mobile app, but now I want to customise the cloud backend functionality, so I have created a local backend with the Azure-Mobile-Apps SDK.
I logged in with my mobile app (using the authorization aspect of the Azure client SDK) and then captured the AuthToken, using a live managed backend setup.
When I then come to try and authorise a request, I get the following issue:
{ "name": "JsonWebTokenError", "message": "jwt audience invalid. expected: urn:microsoft:windows-azure:zumo" }
Following on from: Locally Testing Azure Mobile Auth - invalid jwt signature
How can I set the jwt audience?
To set the audience and issuer, use the auth:{} object in your azureMobile.js. You can decode the JWT at jwt.io to see what the audience and issuer are, then do:
auth: {
audience: '<your audience>',
issuer: '<your issuer>'
};
Some good references:
My blog post on Custom Auth
The main configuration reference (which azureMobile.js exports)

Resources