How to use pnp-js at a node.js application to fetch data from sharepoint? - node.js

I got a node.js application and I'm trying to use the AdalFetchClient of PnPjs to fetch some data from sharepoint.
sp.setup({
sp: {
baseUrl: "https://placeholder.sharepoint.com",
fetchClientFactory: () => {
return new AdalFetchClient("tenantId", "azure_clientId", "azure_clientSecret");
},
},
});
await sp.web.getAppCatalog().get();
I get this error: Error making HttpClient request in queryable [401] Unauthorized ::> {"error_description":"Invalid issuer or signature."}
I setup the permissions of my azure active directory app like so:
Azure App permissions
I granted all the permissions to the tenant I'm trying to fetch data from:
Granted permissions to Azure App
The example I used is here: https://pnp.github.io/pnpjs/nodejs/adal-fetch-client/
I also tried to use the AdalFetchClient with graph.. which is working. Only the sharepoint api seems to have a problem.

I found the solution. There is a AdalCertificateFetchClient which requires the following paramters:
Tenant-ID
Azure App Client ID
Thumbprint of your x.509 certificate
The private key of your x.509 certificate
The root url of the sharepoint you want to connect to
So first of all you have to create a x.509 certificate. I used this tutorial for this. (Thanks for that)
After that you have to get your thumbprint by installing the certificate to your local machine and following this steps
Last step is to get your private key of your certificate. For that you have to install openssl for windows and follow this steps
Now you can use your AdalCertificateFetchClient

Related

Replacing secret with certificate in Azure app registration

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

Azure App Service Fails to Find Newly Created Certificate

I have an Azure app service I did not create but now maintain. The app service finds a certificate in a Key Vault by thumbprint and in turn uses that to get a token for doing some SQL work via nightly jobs.
It appears the certificate was set to auto renew after 80% of its valid date (12 months). The day the cert renewed my nightly jobs started to fail. I'm reasonably certain the new certificate is at the root of the problem.
As best I can tell it designed to work like this:
Job fires via Azure Logic App
annomyous POST to a reports processing API (end result should be .PDF report creation for email atachment)
API has Appsetting.json that contains the current certificates thumbprint
Thumbprint is used in the line of code below to find the certificate in the cert store
Cert is used to aquire access token and perform work
When I install both the old certificate and the new certificate on my local machine and run the entire process it works find with the old certificate and fails on this line with the new auto-generated certificate. It also fails with any new certificates I try to make in Azure and export from Azure and import to my dev machine. I've double/triple checked the appsettings to make sure the Thumbprint in question is correct and updated.
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
When this was configured a year ago the process was to go into App Service, TLS/SSL setting blade, select Private Key Certificates (.pfx) and finally + Import Key Vault Certificate.
From there you selected the Key Vault and Certificate, then changed the Appsettings.Json to have the new Thumbprint.
Why will it work with the old (soon to expire) certificate and corresponding Thumbprint entry into appsettings but fails to work with any newly created certificates and corresponding correct Thumbprint entry?
I've looked at the Configuration for the App Service in question and it has the following setting when I understand is supposed to let the app service see all certificates registered to it, right?
WEBSITE_LOAD_CERTIFICATES = *
EDIT:
After some more testing I find that any cert I export form Azure and import on my computer will successfully iterate the cert store and find any Certificate I provide a valid Thumbprint. What it won't do is use that cert to obtain a access token. The complete code is below.
The certificate that is due to expire soon will get a proper access token and run the rest of the process by getting the proper data from the DB.
The exception I get with all the other certificates suggest something about base64 encoding but I can't quite figure that out. Any ideas?
Exception for all but the original certificate:
Client assertion contains an invalid signature
Successful Access token with this code only with original certificate:
private async Task<string> GetDatabaseTokenFromCert()
{
X509Certificate2 cert;
var store = new X509Store(StoreLocation.CurrentUser);
var authContext = new AuthenticationContext(_appSettings.AzureAD.AADInstance + _appSettings.AzureAD.TenantId);
try
{
store.Open(OpenFlags.ReadOnly);
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
if (signingCert == null)
{
throw new FileNotFoundException("Cannot locate certificate for DB access!", _appSettings.AzureAD.CertificateThumbprint);
}
cert = signingCert;
}
finally
{
store.Close();
}
var certCred = new ClientAssertionCertificate(_appSettings.AzureAD.ClientId, cert);
var result = await Retry(() => authContext.AcquireTokenAsync(_appSettings.SqlConfig.ResourceId, certCred));
return result?.AccessToken;
}
Turns out you need to also add the new certificate to the app registration. As a .cer file without the private key, obviously.
So if you get the error message:
AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: 'YourNewCert'
Go to Key Vault, export new cert as .cer file and import it into the App Service that is trying to obtain the Access token from AcquireTokenAsync
In my case the order of operation is:
Logic app fires off anonymous call as a POST to web API
Web API uses Thumbprint of Cert in question via appsetting.json
Finds cert with thumbprint that is in App Registration of the web API
AcquireTokenAsync takes Azure info and Cert and returns Access Token
This will work or fail on this line of original post
var result = await Retry(() => authContext.AcquireTokenAsync(_appSettings.SqlConfig.ResourceId, certCred));

self signed certificate for azure ad registered applications

Hi I have a daemon application which will access Azure AD graph API.
I am trying to have certificate based authentication,Hence first creatinga self signed certificate.
I have followed this article
https://azure.microsoft.com/en-in/resources/samples/active-directory-dotnet-daemon-certificate-credential/
I am using windows 10 machine.
When I try to modify the manifest file of registered application of Azure AD I get below error
Failed to update application graphapi2. Error details: KeyValue cannot be null or empty Request ID: fea0789a-b8fd-4001-83c4-f74d67fb9812, Timestamp: 12/13/2018 11:56:08
Has any one faced this issue?How will I be able to create self signed certificate to azure ad registered applications.
I got it working by following this link :-github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2 . While exporting the key choose the option ->Do not export private key->Base 64 encoded option.Later I uploaded the certificated in the app registrations preview and it works!! :)
This seems to be happening in the Azure Portal when using the "App registrations (preview)" rather than the normal "App registrations". If you try "App registrations" and edit the manifest there and add your KeyCredentials it seems to work fine.

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).

access SSL certificate in Azure Web App

I've uploaded an SSL certificate to my Azure Web App, running on Node, and now I'd like to access my certificate programmatically from my Node scripts to use it for signing JWTs. Is there a way to do this?
I've found similar answers for C#, but I haven't been able to translate this into Node-world.
Update
Here is code that worked successfully, with help from #peter-pan-msft. Before running this code, I had to SFTP upload my SSL certificate to a private folder on the server.
process.env.KEY = fs.readFileSync('path-to-private-folder/mykey.pem');
const jwt = require('jsonwebtoken');
const token = jwt.sign(payload, process.env.KEY, opts);
There are two samples separately from AzureAD on GitHub and azure-mgmt on npmjs.org.
https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/blob/master/sample/certificate-credentials-sample.js
https://www.npmjs.com/package/azure-mgmt
If you want to use the certification for doing Azure Management, you can directly refer to the second sample.

Resources