Search code examples
javaazureazure-active-directoryazure-api-apps

Authenticate to an Azure API App from Java


I have a similar issue to this post:Authenticate to Azure API App using ADAL but in my case I have a customer with a Java client hosted in JBoss who needs access to my API. The service is secured as 'Public (authenticated)' and I don't have any issues accessing it from a browser. I know that I can create an Azure API App Client in .net but I can't find any samples on how to authenticate from Java. Is this currently possible and if so does anyone have any samples or advice that would help?


Solution

  • I reviewed some documents below to make a sample in Java for calling an Azure API app from client authenticated by AAD.

    As references:

    1. https://azure.microsoft.com/en-us/documentation/articles/app-service-api-authentication-client-flow/
    2. https://azure.microsoft.com/en-us/documentation/articles/app-service-api-dotnet-add-authentication/
    3. https://azure.microsoft.com/en-us/documentation/articles/app-service-authentication-overview/

    For the sample, I created a maven project in Eclipse and used libs adal4j, common-io & httpclient. Here is the dependencies configuration below in pom.xml file.

    <dependencies>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>adal4j</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.1</version>
        </dependency>
    </dependencies>
    

    The sample code for service secured as Public (authenticated), please pay attention to comments in code.

        String gateway_url = "https://<GatewayHost>.azurewebsites.net/";
        String app_id_uri = gateway_url + "login/aad";
        String authority = "https://login.microsoftonline.com/<aad-domain>.onmicrosoft.com";
        String clientId = "<clientId>";
        String clientSecret = "<key>";
        String url = "https://<ApiAppHost>.azurewebsites.net/...";
    /*
     *  Get Access Token from Gateway Login URL with authentication provider name
     *  Note: Please refer to the aad sample in Java for Native Headless at https://github.com/Azure-Samples/active-directory-java-native-headless
     */
    HttpsURLConnection conn = (HttpsURLConnection) new URL(app_id_uri).openConnection();
    AuthenticationContext context = null;
        AuthenticationResult result = null;
        ExecutorService service = null;
        try {
            service = Executors.newFixedThreadPool(1);
            context = new AuthenticationContext(authority, false, service);
            ClientCredential credential = new ClientCredential(clientId, clientSecret);
            Future<AuthenticationResult> future = context.acquireToken(app_id_uri, credential, null);
            result = future.get();
        } finally {
            service.shutdown();
        }
        String accessToken = null;
        if (result == null) {
            throw new ServiceUnavailableException(
                    "authentication result was null");
        } else {
            accessToken = result.getAccessToken();
            System.out.println("Access Token: " +accessToken);
        }
        /*
         * Using access token to get authentication token
         */
        String data = "{\"access_token\": \""+accessToken+"\"}";
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        conn.addRequestProperty("Content-Length", data.length()+"");
        new DataOutputStream(conn.getOutputStream()).writeBytes(data);
        String authTokenResp = IOUtils.toString(conn.getInputStream());
        System.out.println("Get Authentication Token Response: " + authTokenResp);
        /*
         * The content of Authentication Token Response is as {"user": {"userId": "sid:xxx...xxx"}, "authenticationToken": "xxxx...xxxxx"}.
         * Need to extract the authenticationToken from Json.
         */
        Gson gson = new Gson();
        Map<String, Object> map = gson.fromJson(authTokenResp, Map.class);
        String authenticationToken = (String) map.get("authenticationToken");
        System.out.println("Authentication Token: "+authenticationToken);
        /*
         * Using authentication token as X-ZUMO-AUTH header to get data from Api App
         * Note: Must using Apache Common HttpClient supported HTTP 30x redirection, Class Http(s)URLConnection not support.
         *          There are three times continuous 302 redirection in accessing Api App with zumo token. 
         */
        HttpGet httpGet = new HttpGet(url);
        httpGet.addHeader("x-zumo-auth", authenticationToken);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpResponse resp = httpclient.execute(httpGet);
        String apiAppData = IOUtils.toString(resp.getEntity().getContent());
        System.out.println(apiAppData);
    

    Any concern, please feel free to let me know.