Authenticating against Exchange Web Services using certificate based OAuth2 tokens 5/5 (1)

Overview

This post contains step by step information on configuring your environment and authenticating against Exchange Web Services using certificate based OAuth2 tokens. The information in this blog post is only valid for connecting to Exchange Online mailboxes.

Requirements

In order to set up certificate based OAuth2 authentication you will require access to the Azure Active Directory portal. In addition, you will need an Office 365 Exchange Online mailbox to test access.

How it works

The workflow is the following:

1. Generate a new self-signed certificate

2. Export the certificate to disk both with and without a private key

3. Create an app registration in Azure Active Directory and link it to the certificate generated at step 1

4. Use the ADAL libraries to acquire an access token either in .Net or Java

5. Use the access token to connect to Exchange Online mailboxes using the .Net or Java EWS APIs or as part of an EWS SOAP operation

Detailed steps

I. Generate a Base-64 encoded x.509 certificate export

1. Create a new certificate using the following syntax: makecert -r -pe -n “CN=SUBJECT” -b VALIDITY_START -e VALIDITY_EXPIRATION -ss my -len 2048. For example, makecert -r -pe -n “CN=Developer Support for Messaging” -b 09/01/2018 -e 09/01/2020 -ss my -len 2048

2. Open the Certificates mmc by running certmgr.msc in Run or cmd.exe

clip_image002

3. Select the certificate created at step #1, right click it, click All tasks, followed by Export

4. In the Certificate Export Wizard welcome page, click on Next

clip_image004

5. Select the No, do not export the private key radio button and click Next

clip_image006

6. Select Base-64 encoded x.509 (.CER) and click Next

clip_image008

7. Select your export path and give your certificate a name, then click Save

clip_image010

8. Click Next to continue to the last page

clip_image012

9. Click Finish to export your certificate

clip_image014

10. Click OK to dismiss the confirmation message

clip_image016

II. Generate the keyCredentials value using PowerShell

1. Run the following PowerShell script to generate the keyCredential value based on your Base-64 encoded certificate file. Be sure to replace the text in red with the path to your cert file.

$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2

$cer.Import(“C:\Temp\certname.cer”)

$bin = $cer.GetRawCertData()

$base64Value = [System.Convert]::ToBase64String($bin)

$bin = $cer.GetCertHash()

$base64Thumbprint = [System.Convert]::ToBase64String($bin)

$keyid = [System.Guid]::NewGuid().ToString()

$keyCredentials = “`”keyCredentials`”: [ `r`n”

$keyCredentials += ” {`r`n”

$keyCredentials += [String]::Format(” `”customKeyIdentifier`”: `”{0}`”,`r`n”, $base64Thumbprint)

$keyCredentials += [String]::Format(” `”keyId`”: `”{0}`”,`r`n”, $keyid)

$keyCredentials += ” `”type`”: `”AsymmetricX509Cert`”,`r`n”

$keyCredentials += ” `”usage`”: `”Verify`”,`r`n”

$keyCredentials += [String]::Format(” `”value`”: `”{0}`”`r`n”, $base64Value)

$keyCredentials += ” }`r`n”

$keyCredentials += ” ],”

write-host -foregroundcolor green “Copy the following block in the app manifest”; write-host “===========================”;

$keyCredentials; write-host “===========================”

2. Copy the PowerShell output and store it for later use. Your output should be similar to:

“keyCredentials”: [

{

“customKeyIdentifier”: “eoYFreyYeaw4ZlzLKuuQteScS4A=”,

“keyId”: “ca16f9c9-179a-4b1b-a67f-87007398fb82”,

“type”: “AsymmetricX509Cert”,

“usage”: “Verify”,

“value”: “MIIDNTCCAiGgAwIBAgIQmD032SGR45JCYLU6PgiSDjAJBgUrDgMCHQUAMCoxKDAmBgNVBAMTH0RldmVsb3BlciBTdXBwb3J0IGZvciBNZXNzYWdpbmcwHhcNMTgwODMxMjMwMDAwWhcNMjAwODMxMjMwMDAwWjAqMSgwJgYDVQQDEx9EZXZlbG9wZXIgU3VwcG9ydCBmb3IgTWVzc2FnaW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuN/f0B6vnERsmc1sk0QmMyOg5NoJEgfTcBQbF8aUaqNgsQuv0/lbx7xiBtB65j4QbI5zh5nm0NdhXuABzT6GwxpzxR6dEfzthP4m30F++LMcufLCkbbIURea/4btBS/qlp37zfOc/i8rmb5hR1+oZm/r8s7T0VjHfJXJqjqeksihV/xHS/NaVJUNbuoyaMnV+i3kRjFCJKSUT2i9dl+wvlc7lH+jIxnI8QvTRSRp6AwgfHZXLVejGu2kOgk4Dma3uXyeOGJhUO6tmUGVdNqakNXyEfbRnWcs7xlPCCFh2TTzwJaOV4PNadUtwHZ93Mu+ZWQndMEKgfsx75OQjiSfEQIDAQABo18wXTBbBgNVHQEEVDBSgBBiDvviZnl02uCJdBFYyLxDoSwwKjEoMCYGA1UEAxMfRGV2ZWxvcGVyIFN1cHBvcnQgZm9yIE1lc3NhZ2luZ4IQmD032SGR45JCYLU6PgiSDjAJBgUrDgMCHQUAA4IBAQCYHqJTmutuA+Uy6QnGkZAO5VPSSArpaRZ5Jc2EgGu7Q48GbM0VTi0z89FJ1yK0w6Bk0d9GHFEiX7nlbMCkyHEJnJhOGGknwX3Eqp+vjky2MzxWQAV4uz3hs5RIAO8wpgbp5im3GVrB/L8f5I6jl080SVouCPVS16aFtooE43AYdeCKR8VoCHFGf0ec0pKZYGoKgaiFc24Nf86rAB7FQz87lNii1kyWtxQhf9YAKUaxSBMMb0WKukDJhe8cnI3OSOV+7WgEj6d3UjqHuibCwIu872ERYgxDKVFh6wjMC0Pvv6R0SXYI2+NGy16Q7I0zLC4agONuGf7JeAf112W8Zkro”

}

],

III. Generate a PKCS #12 (.PFX)

1. Select the certificate created previously, right click it, click All tasks, followed by Export

2. In the Certificate Export Wizard welcome page, click on Next

3. Select Yes, export the private key and click Next

clip_image018

4. Click Next in the Export File Format page

clip_image020

5. Check the Password checkbox, type in and confirm a password and click Next

clip_image022

6. Select your export path and give your certificate a name, then click Save

clip_image024

7. Click Next to continue to the last page

clip_image026

8. Click Finish to export your certificate

clip_image028

11. Click OK to dismiss the confirmation message

clip_image029

IV. Create your app registration in Azure Active Directory

1. Access https://portal.azure.com, click on Azure Active Directory, click on App registrations, then click on New app registration

clip_image031

2. Fill in the Name and Sign-on URL fields and click Create

clip_image033

3. On the app registration page, click on Settings

clip_image035

4. Under Settings, click on Required Permissions

clip_image037

5. Click on Add to add new permissions

clip_image039

6. Click on Select an API

clip_image041

7. Select Office 365 Exchange Online and click Select

clip_image043

8. Select Use Exchange Web Services with full access to all mailboxes and click Select

clip_image045

9. Click on Done

clip_image047

10. Click on Grant permissions

clip_image049

11. Click on Manifest

clip_image051

12. Replace the existing “keyCredentials”: [], block with the one you’ve obtained as part of the II. Generate the keyCredentials value using PowerShell procedure

clip_image053

13. Lastly, make a note of the Application ID value

clip_image055

V. Obtaining an access token using in .Net

You can use the Microsoft.IdentityModel.Clients.ActiveDirectory library to acquire a certificate based access token. The following example demonstrates how to acquire a certificate based application token, courtesy of Matthias Leibmann:

// need to address the tenant specific authority/token issuing endpoint

// https://login.windows.net/<tenant-id>/oauth2/authorize

// retrieved tenantID from ID token for the app during consent flow (authorize flow)

string authority = appConfig.AuthorizationUri.Replace(“common”, tenantId);

AuthenticationContext authenticationContext = new AuthenticationContext(

authority,

false);

string certfile = Server.MapPath(appConfig.ClientCertificatePfx);

X509Certificate2 cert = new X509Certificate2(

certfile,

appConfig.ClientCertificatePfxPassword, // password for the cert file containing private key

X509KeyStorageFlags.MachineKeySet);

ClientAssertionCertificate cac = new ClientAssertionCertificate(

appConfig.ClientId, cert);

var authenticationResult = await authenticationContext.AcquireTokenAsync(

resource, // always https://outlook.office365.com for Mail, Calendar, Contacts API

cac);

return authenticationResult.AccessToken;

Note: The complete sample of a web app using client credential flow is available in GitHub on https://github.com/mattleib/o365api-as-apponly-webapp

Other examples are available as part of the https://github.com/Microsoft/Office365APIEditor and https://github.com/developermessaging/OauthTokenSamples samples.

VI. Obtaining an access token using Java

You can use the Microsoft Azure Active Directory Authentication Library (ADAL) for Java to acquire a certificate based access token. The following example indicates how to acquire a token:

try {

final KeyStore keystore = KeyStore.getInstance(“PKCS12”, “SunJSSE”);

keystore.load(

new FileInputStream(this.getClass()

.getResource(TestConfiguration.AAD_CERTIFICATE_PATH)

.getFile()),

TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());

final String alias = keystore.aliases().nextElement();

final PrivateKey key = (PrivateKey) keystore.getKey(alias,

TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());

final X509Certificate cert = (X509Certificate) keystore

.getCertificate(alias);

AsymmetricKeyCredential certCredential = AsymmetricKeyCredential.create(CLIENT_ID, key, cert);

// Using UserAssertion as Authorization Grants

Future<AuthenticationResult> future = context.acquireToken(RESOURCE, new UserAssertion(jwt),

certCredential, null);

future.get();

}

catch (ExecutionException ex){

Assert.assertTrue(ex.getCause() instanceof AuthenticationException);

}

The full sample is available in OAuthRequestValidationTest.java.

VII. Using OAuth2 with the EWS Managed API (.Net)

The following code snippet indicates how to use an OAuth2 token with the EWS Managed API:

ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);

exchangeService.Url = new Uri(“https://outlook.office365.com/ews/exchange.asmx”);

exchangeService.TraceEnabled = true;

exchangeService.TraceFlags = TraceFlags.All;

exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken));

For more information please visit Authenticate an EWS application by using OAuth.

VIII. Using OAuth2 with the Exchange Web Services Java API

The Java API doesn’t offer an OAuthCredentials class. You will need to add a HTTP header to the request instead. The following code snippet indicates how to use an OAuth2 token with the EWS Java API:

service.getHttpHeaders().put(“Authorization”, “Bearer ” + accessToken);

IX . Using OAuth2 with the Exchange Web Services SOAP operations

Simply add a HTTP header with the header name Authorization and a header value containing Bearer and the accessToken value obtained using the ADAL libraries. For example:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSJ9.eyJhdWQiOiJodHR

Conclusion

The steps above will allow you to acquire a certificate based OAuth2 token that you can use to authenticate against and access Exchange Online mailboxes. This procedure cannot be used for on-premises deployments of Exchange.

Notes

ADAL libraries are available for .Net and Java projects.

Code samples are also available on GitHub.

References

Microsoft Azure Active Directory Authentication Library (ADAL) for Java

Azure AD token reference

Active Directory Authentication Library (ADAL) for .NET

Authenticate an EWS application by using OAuth

Building Daemon or Service Apps with Office 365 Mail, Calendar, and Contacts APIs (OAuth2 client credential flow)

Office365APIEditor

Revisions

Revision type

Date

Author

Comments

Original

2018-09-11

Andrei Ghita

 

Please rate this

1+

Leave a Reply

Your email address will not be published. Required fields are marked *