Help! JWT Verification not working

I'll raise this issue here in case I'm missing something obvious.

We have implemented App based authentication by attaching an RSA public key to the application using a KVM. Which has been working great for a couple of years.

(We use the public key to verify the JWT sent by the client which has been signed by the corresponding private key).

However. The new interface is not a text box and so the text formatting of the key removes newlines.

(See attached screen shots).

This then kills the policy which verifies the JWT. We get the following error for public keys saved using the new interface:

{"fault":{"faultstring":"Failed to parse key: policy(VerifyJWT-ClientCredentials)","detail":{"errorcode":"steps.jwt.KeyParsingFailed"}}}

Any ideas?  Will this be fixed or should I raise a ticket? Obviously will become quite a problem for us once the old interface disappears completely.

This is the code of the policy which is failing:

<VerifyJWT async="false" continueOnError="false" enabled="true" name="VerifyJWT-ClientCredentials">
  <snip.JPGAlgorithm>RS512</Algorithm>
  <Source>request.formparam.client_assertion</Source>
  <Audience ref="proxy.url" />
  <Subject ref="jwt.DecodeJWT-FromClientAssertionFormParam.decoded.claim.iss"/>
  <PublicKey>
    <Value ref="verifyapikey.VerifyAPIKey-JwtIssuer.rsa-public-key" />
  </PublicKey>
  <MaxLifespan>5m</MaxLifespan>
</VerifyJWT>
Solved Solved
4 3 160
1 ACCEPTED SOLUTION

May I clarify?

However. The new interface is not a text box and so the text formatting of the key removes newlines.

I understand that you are pasting the public key into the textbox in the UI.... and that is when the newline-to-space conversion happens, and that's causing the problem you reported where the same public key no longer works to verify the JWT. And this works of you use the "old UI" to paste in the public key.

is that right?

And specifically you are using custom attributes on the app.

Does the KVM even enter into the picture? I don't see the need for KVM in any of this.

I think the problem is that at runtime the VerifyJWT policy expects the public key to look like this:

 

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5iLGOwNkhepd+pAcW83
...
bUMrRhfFzbLWkhxO23VIRUYSE3PMBFvLPfH99wSJVUkVRbhJv/rFdwRQKJlUuIWV
kQIDAQAB
-----END PUBLIC KEY-----

 

But, because of the "helpful" magic conversion of newlines to spaces done by the UI, you are getting this at runtime:

 

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5iLGOwNkhepd+pAcW83 ... kQIDAQAB -----END PUBLIC KEY-----

 

This seems like a bug to me. I created a ticket to track - internal reference b/340359934 .

If that is the case, you can do the requisite surgery on the PEM string using AssignMessage, to reform the public key into something the policy can use. Like this:

 

<AssignMessage name='AM-Reform-Key'>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>

  <AssignVariable>
    <Name>whitespace_pattern</Name>
    <Value>\s+</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>pem_header</Name>
    <Value>-----BEGIN PUBLIC KEY-----</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>pem_footer</Name>
    <Value>-----END PUBLIC KEY-----</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>empty_string</Name>
    <Value></Value>
  </AssignVariable>
  <AssignVariable>
    <Name>newline</Name>
    <Value>
</Value>
  </AssignVariable>

  <!-- get the mangled PEM key with spaces in place of newlines -->
  <AssignVariable>
    <Name>tmp</Name>
    <Ref>verifyapikey.VerifyAPIKey-1.rsa-public-key</Ref>
  </AssignVariable>

  <!-- remove PEM header and footer -->
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,pem_header,empty_string)}</Template>
  </AssignVariable>
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,pem_footer,empty_string)}</Template>
  </AssignVariable>

  <!-- replace all remaining whitespace with newline -->
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,whitespace_pattern,newline)}</Template>
  </AssignVariable>

  <!-- re-apply header and footer -->
  <AssignVariable>
    <Name>reformed-publickey</Name>
    <Template>{pem_header}
{tmp}
{pem_footer}
</Template>
  </AssignVariable>

</AssignMessage>

 

The result in reformed-publickey is of the desired form.

View solution in original post

3 REPLIES 3

May I clarify?

However. The new interface is not a text box and so the text formatting of the key removes newlines.

I understand that you are pasting the public key into the textbox in the UI.... and that is when the newline-to-space conversion happens, and that's causing the problem you reported where the same public key no longer works to verify the JWT. And this works of you use the "old UI" to paste in the public key.

is that right?

And specifically you are using custom attributes on the app.

Does the KVM even enter into the picture? I don't see the need for KVM in any of this.

I think the problem is that at runtime the VerifyJWT policy expects the public key to look like this:

 

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5iLGOwNkhepd+pAcW83
...
bUMrRhfFzbLWkhxO23VIRUYSE3PMBFvLPfH99wSJVUkVRbhJv/rFdwRQKJlUuIWV
kQIDAQAB
-----END PUBLIC KEY-----

 

But, because of the "helpful" magic conversion of newlines to spaces done by the UI, you are getting this at runtime:

 

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5iLGOwNkhepd+pAcW83 ... kQIDAQAB -----END PUBLIC KEY-----

 

This seems like a bug to me. I created a ticket to track - internal reference b/340359934 .

If that is the case, you can do the requisite surgery on the PEM string using AssignMessage, to reform the public key into something the policy can use. Like this:

 

<AssignMessage name='AM-Reform-Key'>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>

  <AssignVariable>
    <Name>whitespace_pattern</Name>
    <Value>\s+</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>pem_header</Name>
    <Value>-----BEGIN PUBLIC KEY-----</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>pem_footer</Name>
    <Value>-----END PUBLIC KEY-----</Value>
  </AssignVariable>

  <AssignVariable>
    <Name>empty_string</Name>
    <Value></Value>
  </AssignVariable>
  <AssignVariable>
    <Name>newline</Name>
    <Value>
</Value>
  </AssignVariable>

  <!-- get the mangled PEM key with spaces in place of newlines -->
  <AssignVariable>
    <Name>tmp</Name>
    <Ref>verifyapikey.VerifyAPIKey-1.rsa-public-key</Ref>
  </AssignVariable>

  <!-- remove PEM header and footer -->
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,pem_header,empty_string)}</Template>
  </AssignVariable>
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,pem_footer,empty_string)}</Template>
  </AssignVariable>

  <!-- replace all remaining whitespace with newline -->
  <AssignVariable>
    <Name>tmp</Name>
    <Template>{replaceAll(tmp,whitespace_pattern,newline)}</Template>
  </AssignVariable>

  <!-- re-apply header and footer -->
  <AssignVariable>
    <Name>reformed-publickey</Name>
    <Template>{pem_header}
{tmp}
{pem_footer}
</Template>
  </AssignVariable>

</AssignMessage>

 

The result in reformed-publickey is of the desired form.

Thanks for raising the bug and providing us some lovely ninja style Assign Message policies as a work around. I would have gone straight to my Javascript kit bag to fix this one so it's good to know that there's some quite complex text manipulation that can be done with AssignMessage. It probably executes faster too and I think shouldn't damage any previously stored KVMs that haven't been mashed up. We may need to use this so thank you.

Meanwhile we have found that fixes to the rsa-public-key variable (which I had termed an app KVM) are possible using the Apigee management API where replacing the newlines with \n characters seems to work. We had also found, like you did, that it's possible to have a single string with no breaks representing the PEM which also gets parsed correctly.

Thanks again for your help.


@MasonJohnDavis wrote:

Meanwhile we have found that fixes to the rsa-public-key variable (which I had termed an app KVM) are possible using the Apigee management API where replacing the newlines with \n characters seems to work.


YES! If you provision these KVMs via the management API, then you avoid the magic newline-to-space conversion that happens in the UI. 


@MasonJohnDavis wrote:

We had also found, like you did, that it's possible to have a single string with no breaks representing the PEM which also gets parsed correctly.


YES. This is nice to know. The PEM encoding says that there should be a linebreak every 64 characters, but that's not always required. Many parsers (including apigee) will tolerate longer lines. (But not lines with spaces)

 


@MasonJohnDavis wrote:

Thanks again for your help.


 

Glad to help. Thanks for circling back with your findings.