Apigee sha256Hex and AWS SigV4 and Newline

Has anyone successfully hit a protected AWS resource using just the AssignMessage policy to correctly sign a request OR resolved the newline encoding?

The issue does not seem to be the actual hmac signing but the building of the things that need to be signed.  The string-to-sign (as AWS calls it) needs sha256Hex but portions require newlines. When comparing the Apigee sha256Hex to another sha256 generator the output differs when newlines are introduced otherwise they are identical.  I see lot's of solutions using Java or JS (and we have been warned to stay away from the AWS extensions) but I expect this can resolved using just the AM policy

Note:

I have successfully hit AWS resources using the snippet below by replacing the \n with a variable containing a newline extracted from an object.  The process I hacked up seems excessive... create an object with a member value containing only a newline {"newline": "\n"} only to extract it right back out.  It appears objects preserve the proper encoding.  There must be something I'm missing as I would expect this to be more straightforward.

This example shows the required newlines necessary but does not work

 

 <AssignVariable>
        <Name>canonical-headers</Name>
        <!--sorting important-->
        <!--no white space allowed-->
        <Template>host:{aws-service-endpoint}\nx-amz-date:{x-amz-date}\n</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>canonical-request</Name>
        <Template>{aws-service-http-verb}\n{canonical-uri}\n{canonical-querystring}\n{canonical-headers}\n{signed-header-names}\n{payload-hash}</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>algorithm</Name>
        <Value>AWS4-HMAC-SHA256</Value>
    </AssignVariable>
    <AssignVariable>
        <Name>credential-scope</Name>
        <Template>{date-value}/{aws-region}/{aws-service-name}/aws4_request</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>string-to-sign</Name>
        <Template>{algorithm}\n{x-amz-date}\n{credential-scope}\n{sha256Hex(canonical-request)}</Template>
    </AssignVariable>

 

This example does work when the variable evnl has the newline extracted from an object

 

    <AssignVariable>
        <Name>canonical-request</Name>
        <Template>{aws-service-http-verb}{evnl}{canonical-uri}{evnl}{canonical-querystring}{evnl}{canonical-headers}{evnl}{signed-header-names}{evnl}{payload-hash}</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>canonical-request-hash</Name>
        <Template>{sha256Hex(canonical-request)}</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>algorithm</Name>
        <Value>AWS4-HMAC-SHA256</Value>
    </AssignVariable>
    <AssignVariable>
        <Name>credential-scope</Name>
        <Template>{date-value}/{aws-region}/{aws-service-name}/aws4_request</Template>
    </AssignVariable>
    <AssignVariable>
        <Name>string-to-sign</Name>
        <Template>{algorithm}{evnl}{x-amz-date}{evnl}{credential-scope}{evnl}{canonical-request-hash}</Template>
    </AssignVariable>

 

Solved Solved
0 5 387
1 ACCEPTED SOLUTION

I tweaked your idea to get it working in the UI.  This is what I was looking for - a easy way to get a proper newline into a variable. My signed requests are working. Thanks for your help!  

    <AssignVariable>
        <Name>wrapnl</Name>
        <Value>aaa
aaa</Value>
    </AssignVariable>
    <AssignVariable>
        <Name>nl</Name>
        <Template>{replaceAll(wrapnl, 'aaa', '')}</Template>
    </AssignVariable>

 

View solution in original post

5 REPLIES 5

 

The AssignMessage template doesn't translate the sequence \n into a single newline character, as happens in C code or JS or Java.  It doesn't have that kind of "escaping". 

But you can do what you want, I suppose, with a little less hackiness, with a replace function.

 

<AssignMessage name='AM-String-to-Sign'>
  ...
  <AssignVariable>
        <Name>string-to-sign</Name>
        <Template>{algorithm}\n{x-amz-date}\n{credential-scope}\n{sha256Hex(canonical-request)}</Template>
  </AssignVariable>
  <AssignVariable>
    <Name>newline</Name>
    <Value>
</Value>
  </AssignVariable>
  <AssignVariable>
    <Name>regex</Name>
    <Value>\\n</Value> <!-- the char sequence: backslash+n -->
  </AssignVariable>
  <AssignVariable>
    <Name>string-to-sign</Name>
    <Template>{replaceAll(string-to-sign,regex,newline)}</Template>
  </AssignVariable>
</AssignMessage>

See also, this callout which rolls up all the AssignVariables into a single Java policy. 

 

When I try this (in the UI), the newline var value upon saving gets converted to <Value/> losing the return

 

mmmmm that's a bummer.  when I do it I don't use the UI, so it doesn't convert.

Here's my bundled proxy zip (attached). This works for me, for the specific request I tested.  It comes from the test suite from AWS, which I downloaded from https://docs.aws.amazon.com/general/latest/gr/samples/aws-sig-v4-test-suite.zip 

You might be able to "import" this bundle via the UI, and get it to behave the way you want. 

It works as far as it goes. It's a little tricky to get right with all the headers and so on.  the Java callout I referenced earlier is an attempt to make something configurable, something a little easier to use. 

I tweaked your idea to get it working in the UI.  This is what I was looking for - a easy way to get a proper newline into a variable. My signed requests are working. Thanks for your help!  

    <AssignVariable>
        <Name>wrapnl</Name>
        <Value>aaa
aaa</Value>
    </AssignVariable>
    <AssignVariable>
        <Name>nl</Name>
        <Template>{replaceAll(wrapnl, 'aaa', '')}</Template>
    </AssignVariable>

 

kinda hacky, but it works ! Glad I could help.