Chef API Java Integration [With Authentication Solution]

Chef_API-Authentication

Chef is used to streamline the task of configuring and maintaining a company’s servers, and can integrate with cloud-based platforms such as Internap, Amazon EC2, Google Cloud Platform, OpenStack, SoftLayer, Microsoft Azure and Rackspace to automatically provision and configure new machines.” – From Wikipedia

This article is about the REST APIs by Chef which provide access to Chef server, nodes, users, organizations, permissions, keys etc. Refer – Chef Server API

When a node is configured with chef-client, a Public and Private Key pair is generated. Public Key is stored on the Chef server while the Private Key is returned to the user/client. This key pair is used for creating a trust between the server and the client for authenticating the requests.

All the Chef API requests should have a set of HTTP Headers signed using the Private Key associated with the server. The Chef server can verify the signature using the Public Key stored on the server. (Refer – Chef Auth)


For beginners like me, its not easy to integrate these APIs with java code due to the complex HTTP Headers that need to be generated and sent with every request. After trying few solutions from Github, finally was able to successfully get through the Authentication and make API calls.

Download the working Java code – Download Zip

This code takes username, private key path (.pem file) and Chef Server host as input.

Main Class – APIMain

Referred Github project – Link

Understanding Authentication

Requirement for Chef Authentication-
All the below headers are required as part of each Chef API call-
  Accept
  X-Ops-Sign
  X-Ops-Userid
  X-Ops-Timestamp
  X-Ops-Content-Hash
  X-Ops-Authorization-1 (N) –  One (or more) 60 character segments that comprise the canonical header. A canonical header is signed with the private key used by the client machine from which the request is sent, and is also encoded using Base64.
  X-Chef-Version
Canonical Header is comprised of below values. This is then signed with the pem key and split into substrings of 60 each and set in the X-Ops-Authorization-1,2,3,4.. header.
Method
Hashed Path
X-Ops-Content-Hash
X-Ops-Timestamp
X-Ops-UserId
From code perspective-
      // The canonical header is framed below 
      StringBuilder sb = new StringBuilder();
      sb.append("Method:").append(methodName).append("\n");
      sb.append("Hashed Path:").append(hashedPath).append("\n");
      sb.append("X-Ops-Content-Hash:").append(hashedBody).append("\n");
      sb.append("X-Ops-Timestamp:").append(timeStamp).append("\n");
      sb.append("X-Ops-UserId:").append(userId);
      //It is then signed with the private key
      String auth_String = Utils.signWithRSA(sb.toString(), pemPath);
      // Split in 60 length substrings and set in an array
      String[] auth_headers = Utils.splitAs60(auth_String);
      //The main header values are set     
      method.addRequestHeader("Content-type", "application/json");
      method.addRequestHeader("X-Ops-Timestamp", timeStamp);
      method.addRequestHeader("X-Ops-Userid", userId);
      method.addRequestHeader("X-Chef-Version", "0.10.4");
      method.addRequestHeader("Accept", "application/json");
      method.addRequestHeader("X-Ops-Content-Hash", hashedBody);
      method.addRequestHeader("X-Ops-Sign", "version=1.0");


      // The Substrings of 60 each are set in the X-Ops0Authorization-1,2.. header
      for (int i = 0; i < auth_headers.length; i++) {
         method.addRequestHeader("X-Ops-Authorization-" + (i + 1), auth_headers[i]);
         
      }
       //Method call is made
     code = client.executeMethod(method);

Possible Errors

  • If the Chef Server instance is running on HTTPS without a valid SSL certificate then the HTTP Client will throw below Error-
(PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException)

This error is due to SSL Handshake failure between the HTTP Client and the Chef Server.

The solution is to install a valid SSL certificate. (by configuring a Load Balancer and SSL cert with it or importing the certificate in the java keystore file)

  • If the Chef Server instance is running on HTTPS with a self signed certificate, then the same CA certificate needs to be imported to the java keystore of machine from where request is being made. (HTTP Client)

Follow this article to see how to import SSL cert to keystore- Link

Thanks for checking out. Let us know through comments or contact us section in case of any issues.

Categories
Comments
All comments.
Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.