Connecting to SharePoint using Azure app authentication and Python

Question:

I created a self signed certificate and uploaded it to an Azure app registration, similar to what I’ve done with a dozen or so other apps. I’m attempting to connect to my SharePoint site with Python’s office365 library, which is not something I have a lot of experience with and it shows.

from office365.runtime.auth.client_credential import ClientCredential
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.files.file_system_object_type import FileSystemObjectType
import os 

def create_client_with_private_key():

    cert_credentials = {
        'tenant': tenant,
        'client_id': appid,
        'thumbprint': thumb,
        'cert_path': path
    }
    return ClientContext(siteurl).with_client_certificate(**cert_credentials)


siteurl = 'https://mytenant.sharepoint.com/sites/mysite'
appid = '<AppID guid>'
tenant = '<TenantID>'
thumb = '<certificate thumbprint>'
path = "d:\azure cert\mycertificate.pem"

ctx = create_client_with_private_key()
current_web = ctx.web.get().execute_query()
print("{0}".format(current_web.url))

The script that dies at the second to last line (current_web = ctx.web.get().execute_query()) with this error

Exception has occurred: ValueError
(‘Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).’, [_OpenSSLErrorWithText(code=75497580, lib=9, reason=108, reason_text=b’error:0480006C:PEM routines::no start line’)])
ValueError: Could not deserialize key data. The data may be in an incorrect format or it may be encrypted with an unsupported algorithm.

During handling of the above exception, another exception occurred:

File "C:scriptssp-test.py", line 50, in
current_web = ctx.web.get().execute_query()
ValueError: (‘Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).’, [_OpenSSLErrorWithText(code=75497580, lib=9, reason=108, reason_text=b’error:0480006C:PEM routines::no start line’)])

I’ve read up that I need to make sure I have the python cryptography package installed, which I do. I’m guessing the format of the certificate is wrong, but I’m not sure what format I should hve it in.

I used the following PowerShell script to create the certificate

$validMonths =12;
$notAfter = (Get-Date).AddMonths($validMonths) # Valid for 4 months
$thumb = (New-SelfSignedCertificate -DnsName "mycertificate" -CertStoreLocation "cert:LocalMachineMy"  -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $notAfter).Thumbprint
$pwd = ConvertTo-SecureString -String $certPassword -Force -AsPlainText
Export-PfxCertificate -cert "cert:localmachinemy$thumb" -FilePath $certPath -Password $pwd
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate($certPath, $pwd)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
New-AzureADApplicationKeyCredential -ObjectId $objectID -Type AsymmetricX509Cert -Usage Verify -Value $keyValue -EndDate ($notAfter.AddHours(-2))

Which creates a pfx file. I had tried that first and that didn’t work. So then I exported the certificate as a pem

Export-Certificate -Type CERT -Cert "cert:localmachinemy$thumb" -FilePath "$baseCertPath$($certName).der"; 
certutil -encode "$baseCertPath$($certName).der" "$baseCertPath$($certName).pem";

What am I doing wrong?

Asked By: Robbert

||

Answers:

The certificate format may be wrong. The key data could not be deserialized, possibly owing to an unsupported technique or format.

Your PowerShell script creates and exports a self-signed certificate in PFX and PEM formats. The certificate’s PEM export may be the problem.

OpenSSL may immediately export the certificate as PEM from the PFX file instead of DER and PEM. Command:

openssl pkcs12 -in mycertificate.pfx -out mycertificate.pem -nodes

This command should PEM-export the private key and certificate. Use this PEM file in Python.

Check that the certificate is properly installed in the certificate store on the system running your Python script. Windows’ Certificate Manager shows the certificate in the "Personal" store.

If the certificate is properly installed and the PEM file is in the correct format, consider using an alternative library or technique to connect to SharePoint, or contact the office365 library maintainers for help.

Answered By: PforPython

I ended up solving the problem by not using PowerShell to generate the certificate. For whatever reason, no matter what I did, I could not get Python to use any certificate I generated with PowerShell. I created the certificate using my Azure Key Vault and was able to download the file as a PEM that my Python script accepted.

Answered By: Robbert