3
votes

I've been trying for a week to authenticate on Azure Active Directory with a Java application which presents client credential grant, in order to retrieve an access token to target the Outlook Office365 REST API, but could not succeed. The server always returns an error :

com.microsoft.aad.adal4j.AuthenticationException: {"error":"unauthorized_client","error_description":"AADSTS70002: Error validating credentials. AADSTS50064: Credential validation failed

I have followed the MSDN blog post http://blogs.msdn.com/b/exchangedev/archive/2015/01/21/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx and uploaded my public cert in the application manifest on Azure.

I'm using the Java Library ADAL4J in version 0.0.4 with the following code :

        service = Executors.newFixedThreadPool(1);

        final KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
        keystore.load(new FileInputStream(MyApp.class.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);
        final AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(TestConfiguration.AAD_CLIENT_ID, key, cert);
        ctx = new AuthenticationContext(TestConfiguration.AAD_TENANT_ENDPOINT, false, service);
        final Future<AuthenticationResult> result = ctx.acquireToken(TestConfiguration.AAD_RESOURCE_ID, asymmetricKeyCredential,null);
        ar = result.get();

Here is my TestConfiguration object :

public final class TestConfiguration {

public final static String AAD_HOST_NAME = "login.windows.net";
public final static String AAD_TENANT_NAME = "MYTENANT.onmicrosoft.com"; 
public final static String AAD_TENANT_ENDPOINT = "https://" + AAD_HOST_NAME + "/" + AAD_TENANT_NAME + "/";
public final static String AAD_CLIENT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
public final static String AAD_CLIENT_SECRET = "xxxxxxxxxx";
public final static String AAD_RESOURCE_ID = "https://outlook.office365.com/"; 
public final static String AAD_CERTIFICATE_PATH = "/MyCert.pfx";
public final static String AAD_CERTIFICATE_PASSWORD = "xxxxxxx";
}

Here is the com.microsoft.aad.adal4j.AdalOAuthRequest request object properties produced :

authorization : null
contentType : application/x-www-form-urlencoded; charset=UTF-8
extraHeaderParams : {client-request-id=d942e921-71d7-47ef-9f97-29e8bb4122aa, x-client-OS=Windows 7, x-client-SKU=java, return-client-request-id=true, x-client-CPU=amd64, x-client-VER=1.0}
method : POST
query : client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&grant_type=client_credentials&client_assertion=eyJhbGciOiJSUzI1NiIsIn ... cut ... G0U4MeBV69EGauQ&resource=https%3A%2F%2Foutlook.office365.com%2F
url : https://login.windows.net/mytenant.onmicrosoft.com/oauth2/token

Where may have I missed some thing ?

Thanks for your help.

P.S. : when I download my application manifest back from Azure, I find my "keyCredentials" JSON object but it's "value" property is null (whereas I did previously put my public cert in it) ... Does it mean it is really null or just an empty property for security reasons ??

1
Do you have a correlation id and timestamp? - Rich Randall
Yes : here is the complete error : Exception in thread "main" com.microsoft.aad.adal4j.AuthenticationException: {"error":"unauthorized_client","error_description":"AADSTS70002: Error validating credentials. AADSTS50064: Credential validation failed.\r\nTrace ID: 823ec9e0-7872-4564-a6c0-316dd077eafb\r\nCorrelation ID: 2ab2a724-be32-446b-b343-21fa2c58e7cb\r\nTimestamp: 2015-02-23 19:47:32Z"} - Eric
It appears that the server is having trouble parsing part of the JWT token being sent. We are investigating the cause. Stay tuned... - Rich Randall
Hey eric, can you please share a fiddler trace or your client assertion at <my-first-name>.<my-last-name>(AT)<company-name>.com... where my-first-name=kanishk, my-last-name=panwar and company-name=microsoft :) - Kanishk Panwar
Can you also please share how you generated the pfx and uploaded the cer to azure ad? - Kanishk Panwar

1 Answers

0
votes

commons-codec version needed to be updated from 1.4 to 1.5 to make the encoding work correctly. http://commons.apache.org/proper/commons-codec/changes-report.html#a1.5

EDIT FROM ERIC

I finally managed to retrieve an access token by upgrading my common-codecs artifact from 1.4 (with which it was not working) to 1.5 .

We got thinking of the common-codecs artifact because the JWT token presented had a public certificate value with "\r\n" inserted when generated by my app, whereas it hadn't when it was generated from a dedicated sample test app.

Those "\r\n" characters were inserted into the "x5c" JWT header property by a call to org.apache.commons.codec.binary.Base64.encodeBase64String(byte[]) from com.microsoft.aad.adal4j.AsymmetricKeyCredential.getPublicCertificate().

It appeared that my app had already a depency to common-codecs v1.4 which didn't suit to adal4j.