Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Christopher
Participant
Digest Access Authentication? You've never heard of it? Well, I have been there one week ago as well! I have never heard of it and yet it exists and there are systems that require this authentication. Let's start with an introduction of Digest Access Authentication:

https://en.wikipedia.org/wiki/Digest_access_authentication

Even though it is not the safest way of authentication, it is safer than Basic Auth and has therefore advantages. That makes me wondering why I haven't seen it earlier, especially as an alternative for Basic Auth.

Unfortunately, the Cloud Integration does not support this method out of the box (unlike Postman for example), therefore we have to implement it manually. I used the Postman echo service (great service that I haven't known before as well) to implement an example of the authentication. There's quite a bit of variety in the way the target server can be configured, therefore your implementation might be a little different. But the general aspect will be the same and the adaptions won't be a problem once the concept is understood.

So, the basic principle is to have a first GET call to your endpoint which will always fail. Despite the failing part, an important header parameter will be returned that you have to fetch and process.

To focus on the solution and to not overcomplicate it, I chose to handle it in one integration flow. I think my productive solution would have a separate iFlow that is called via the ProcessDirect Adapter. This iFlow will fail, but the exception is called and the calling iFlow can continues it's process. But for this example I will work with local Integration Processes.

Let's start with the initial call to receive the important header parameter:



You see a local Integration Process with an HTTP Get call to the Postman Echo Service URL: https://postman-echo.com/digest-auth


As said earlier, this call will fail. Let's have a quick call into the log to see what the failed call returned in the header. We see the Response Code 401, BUT more importing, we see the header parameter "WWW-Authenticate" which holds the information we will need to authenticate:



 

Because the call fails, we have an Exception Subprocess that catches the exception. Since this exception is expected we will ignore it and continue with a call of the second Integration Subprocess (LPC_Get).


 

Here, the important part is the Groovy Script "GS_setAuth" which will process the header parameter  "WWW-Authenticate" that was returned by the first GET call.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import org.apache.commons.codec.digest.DigestUtils;
def Message setAuth(Message message) {

def map = message.getHeaders();

def www_auth = map.get("WWW-Authenticate");
// Pattern of the www_auth for the Postman Echo call. Additional parts might
// be delivered by other services
// Digest realm="Users", nonce="OAnRUlVfhouPq526GFnoBvHCvsEHzNR4", qop="auth"

def realm = www_auth.split("realm=")[1].split("\"")[1];
def nonce = www_auth.split("nonce=")[1].split("\"")[1];
def qop = www_auth.split("qop=")[1].split("\"")[1];

user = "postman";
password = "password";
def uri = "/digest-auth";

// username:realm:password
def HA1 = user + ":" + realm + ":" + password;

HA1 = DigestUtils.md5Hex( HA1 );

def HA2 = DigestUtils.md5Hex( "GET:" + uri );

def response = HA1 + ":" + nonce + ":" + HA2;
response = DigestUtils.md5Hex( response );

//Digest username="postman", realm="Users", nonce="ni1LiL0O37PRRhofWdCLmwFsnEtH1lew", uri="/digest-auth", response="254679099562cf07df9b6f5d8d15db44", opaque=""
def auth = "Digest username=\"" + user + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\"," + " response=\"" + response + "\"" + ", opaque=\"\"";

message.setHeader( "Authorization", auth);
return message;
}


Please notice that I use the class DigestUtils to create the MD5 (https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils....), you'll have to import the .jar file into your iFlow to use it.

Let's go through this coding step by step:

  • We're fetching the header parameter WWW-Authenticate

  • Afterwards we have to extract the values of the parameters. The Postman echo service sends the parameter "realm", "nonce" and "qop", other services might have additional parameters like cnonce

  • No we have to calculate the MD5 for differents parts, let's start with HA1 and HA2

    • HA1 has the pattern of username:realm:password

      • You see that user/password are stored in the coding, of course we would use secure parameters in a productive scenario



    • HA2 has the pattern HTTPMethod:uri

      • In our case it's a GET method and the URI /digest-auth





  • Once we have calculated HA1 and HA2, we can create the final MD5, in our case "response"

    • response has the pattern of HA1:nonce:HA2



  • Now we have to create a string that is set into the header parameter "Authorization". This is the tricky part if you don't have the information how exactly it needs to be constructed. After some trial and error I found the combination that works for Postman


Once all that is done, we have a second GET call that looks exactly the same as the first one, but this time it is successful:


 


 

Conclusion

If you have to integrate a System via HTTP Digest Authentication, you learned the basics with a working example. As said, there are some minor varieties in data that we be coming back from the first call, but the principles and the existing coding will help you establishing the connection to your target system

 

 
3 Comments
Labels in this area