signature verification failing in iloveapis2015-jwt-jwe-jws under JWT-Parse-RS256 policy

I an able to generate a JWT using ../jwt_signed/create-rs256 endpoing from the sample github iloveapis2015-jwt-jwe-jws project. Certificated being used are the default included in JAR file.

A sample JWT is :

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJwcmltYXJ5bGFuZ3VhZ2UiOiJFbmdsaXNoIiwic3ViIjoiSmF2YVRlc3RTZWN1cml0eSIsImF1ZCI6Ik9wdGlvbmFsLVN0cmluZy1vci1VUkkiLCJzaG9lc2l6ZSI6IjguNSIsImlzcyI6Imh0dHA6XC9cL2Rpbm9jaGllc2EubmV0IiwibW90dG8iOiJJbG92ZWFwaXMiLCJleHAiOjE0ODE3NjM4NTYsImlhdCI6MTQ4MTc2MDI1Nn0.E-5gq53MNvoh32vgSy_xi_R0aO0G7Pkal5y6M_8IqRc_FxVpeYwvLZGaDZ33sY0SKsGPx3_on1Od2HUxp77ZGXZuzRkvDHtvVKSVI_CBLS_1yjsZihxGRPirAYjacKofR0Uip2iEUksqSMHSfkNEUe_LPkzL8RmtzWyfK0wL8DVWWviYLoUhqFJEyJJvEHFttWvNtdMzfYm3M6iCSAC6wEBgm32L8i8z2WdImIKuKZWyuChSDoBE3mwYdfG169E6PhasVPquLvLzemeact_S0_sbNNUKePuIvLxOoWejuh6xgRnx4cLOhM1JhmTHHBZeHkwcDELer007SRj1iK392w

you can visit https://jwt.io/ and verify this token using below public key (default key that came with the sample git hub project)

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxlohiBDbI/jejs5WLKe
Vpb4SCNM9puY+poGkgMkurPRAUROvjCUYm2g9vXiFQl+ZKfZ2BolfnEYIXXVJjUm
zzaX9lBnYK/v9GQz1i2zrxOnSRfhhYEb7F8tvvKWMChK3tArrOXUDdOp2YUZBY2b
sl1iBDkc5ul/UgtjhHntA0r2FcUE4kEj2lwU1di9EzJv7sdE/YKPrPtFoNoxmthI
OvvEC45QxfNJ6OwpqgSOyKFwE230x8UPKmgGDQmED3PNrio3PlcM0XONDtgBewL0
3+OgERo/6JcZbs4CtORrpPxpJd6kvBiDgG07pUxMNKC2EbQGxkXer4bvlyqLiVzt
bwIDAQAB
-----END PUBLIC KEY-----

However, when a cal is made to ..jwt_signed/validate-rs256 endpoint, I get an exception:

com.google.common.util.concurrent.UncheckedExecutionException: java.lang.NullPointerException at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2203) at com.google.common.cache.LocalCache.get(LocalCache.java:3937) at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3941) at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4824) at com.apigee.callout.jwtsigned.JwtParserCallout.getRsaVerifier(JwtParserCallout.java:280) at com.apigee.callout.jwtsigned.JwtParserCallout.getVerifier(JwtParserCallout.java:289) at com.apigee.callout.jwtsigned.JwtParserCallout.execute(JwtParserCallout.java:358) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$ClassLoadWrappedExecution.execute(JavaCalloutStepDefinition.java:166) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:231) at java.security.AccessController.doPrivileged(Native Method) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution.execute(JavaCalloutStepDefinition.java:228) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.execute(JavaCalloutStepDefinition.java:101) at com.apigee.messaging.runtime.steps.StepExecution.execute(StepExecution.java:146) at com.apigee.flow.execution.AbstractAsyncExecutionStrategy$AsyncExecutionTask.call(AbstractAsyncExecutionStrategy.java:74) at com.apigee.flow.execution.AbstractAsyncExecutionStrategy$AsyncExecutionTask.call(AbstractAsyncExecutionStrategy.java:45) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.NullPointerException at com.apigee.callout.jwtsigned.PublicKeySource.publicKeyStringToPublicKey(PublicKeySource.java:121) at com.apigee.callout.jwtsigned.PublicKeySource.pemFileStringToPublicKey(PublicKeySource.java:90) at com.apigee.callout.jwtsigned.PublicKeySource.getPublicKey(PublicKeySource.java:72) at com.apigee.callout.jwtsigned.JwtParserCallout$2.load(JwtParserCallout.java:98) at com.apigee.callout.jwtsigned.JwtParserCallout$2.load(JwtParserCallout.java:94) at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3527) at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2319) at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2282) at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2197) ... 20 more

Can some please help with this?

other variables are included below:

request.formparam.jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJwcmltYXJ5bGFuZ3VhZ2UiOiJFbmdsaXNoIiwic3ViIjoiSmF2YVRlc3RTZWN1cml0eSIsImF1ZCI6Ik9wdGlvbmFsLVN0cmluZy1vci1VUkkiLCJzaG9lc2l6ZSI6IjguNSIsImlzcyI6Imh0dHA6XC9cL2Rpbm9jaGllc2EubmV0IiwibW90dG8iOiJJbG92ZWFwaXMiLCJleHAiOjE0ODE3NjM4NTYsImlhdCI6MTQ4MTc2MDI1Nn0.E-5gq53MNvoh32vgSy_xi_R0aO0G7Pkal5y6M_8IqRc_FxVpeYwvLZGaDZ33sY0SKsGPx3_on1Od2HUxp77ZGXZuzRkvDHtvVKSVI_CBLS_1yjsZihxGRPirAYjacKofR0Uip2iEUksqSMHSfkNEUe_LPkzL8RmtzWyfK0wL8DVWWviYLoUhqFJEyJJvEHFttWvNtdMzfYm3M6iCSAC6wEBgm32L8i8z2WdImIKuKZWyuChSDoBE3mwYdfG169E6PhasVPquLvLzemeact_S0_sbNNUKePuIvLxOoWejuh6xgRnx4cLOhM1JhmTHHBZeHkwcDELer007SRj1iK392wjwt_isSigned truejwt_jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJwcmltYXJ5bGFuZ3VhZ2UiOiJFbmdsaXNoIiwic3ViIjoiSmF2YVRlc3RTZWN1cml0eSIsImF1ZCI6Ik9wdGlvbmFsLVN0cmluZy1vci1VUkkiLCJzaG9lc2l6ZSI6IjguNSIsImlzcyI6Imh0dHA6XC9cL2Rpbm9jaGllc2EubmV0IiwibW90dG8iOiJJbG92ZWFwaXMiLCJleHAiOjE0ODE3NjM4NTYsImlhdCI6MTQ4MTc2MDI1Nn0.E-5gq53MNvoh32vgSy_xi_R0aO0G7Pkal5y6M_8IqRc_FxVpeYwvLZGaDZ33sY0SKsGPx3_on1Od2HUxp77ZGXZuzRkvDHtvVKSVI_CBLS_1yjsZihxGRPirAYjacKofR0Uip2iEUksqSMHSfkNEUe_LPkzL8RmtzWyfK0wL8DVWWviYLoUhqFJEyJJvEHFttWvNtdMzfYm3M6iCSAC6wEBgm32L8i8z2WdImIKuKZWyuChSDoBE3mwYdfG169E6PhasVPquLvLzemeact_S0_sbNNUKePuIvLxOoWejuh6xgRnx4cLOhM1JhmTHHBZeHkwcDELer007SRj1iK392wjwt_jwtheader {"typ":"JWT","alg":"RS256"}jwt_error com.google.common.util.concurrent.UncheckedExecutionException: java.lang.NullPointerExceptionjwt_reason java.lang.NullPointerExceptionjwt_isValid falsejwt_stacktrace com.google.common.util.concurrent.UncheckedExecutionException: java.lang.NullPointerException at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2203) at com.google.common.cache.LocalCache.get(LocalCache.java:3937) at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3941) at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4824) at com.apigee.callout.jwtsigned.JwtParserCallout.getRsaVerifier(JwtParserCallout.java:280) at com.apigee.callout.jwtsigned.JwtParserCallout.getVerifier(JwtParserCallout.java:289) at com.apigee.callout.jwtsigned.JwtParserCallout.execute(JwtParserCallout.java:358) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$ClassLoadWrappedExecution.execute(JavaCalloutStepDefinition.java:166) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:231) at java.security.AccessController.doPrivileged(Native Method) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution.execute(JavaCalloutStepDefinition.java:228) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.execute(JavaCalloutStepDefinition.java:101) at com.apigee.messaging.runtime.steps.StepExecution.execute(StepExecution.java:146) at com.apigee.flow.execution.AbstractAsyncExecutionStrategy$AsyncExecutionTask.call(AbstractAsyncExecutionStrategy.java:74) at com.apigee.flow.execution.AbstractAsyncExecutionStrategy$AsyncExecutionTask.call(AbstractAsyncExecutionStrategy.java:45) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.NullPointerException at com.apigee.callout.jwtsigned.PublicKeySource.publicKeyStringToPublicKey(PublicKeySource.java:121) at com.apigee.callout.jwtsigned.PublicKeySource.pemFileStringToPublicKey(PublicKeySource.java:90) at com.apigee.callout.jwtsigned.PublicKeySource.getPublicKey(PublicKeySource.java:72) at com.apigee.callout.jwtsigned.JwtParserCallout$2.load(JwtParserCallout.java:98) at com.apigee.callout.jwtsigned.JwtParserCallout$2.load(JwtParserCallout.java:94) at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3527) at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2319) at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2282) at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2197) ... 20 more
Solved Solved
0 11 536
1 ACCEPTED SOLUTION

Sorry! This question slipped under the radar and has now been sitting for 7 months!

I just tried this JWT with the latest JWT JAR from the github repo, and it worked fine for me.

This is the policy configuration I used:

<JavaCallout name='JWT-Parse-RS256-1'>
  <DisplayName>JWT-Parse-RS256-1</DisplayName>
  <Properties>
    <Property name="algorithm">RS256</Property>
    <Property name="jwt">{request.formparam.jwt}</Property>
    <Property name="public-key">
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxlohiBDbI/jejs5WLKe
Vpb4SCNM9puY+poGkgMkurPRAUROvjCUYm2g9vXiFQl+ZKfZ2BolfnEYIXXVJjUm
zzaX9lBnYK/v9GQz1i2zrxOnSRfhhYEb7F8tvvKWMChK3tArrOXUDdOp2YUZBY2b
sl1iBDkc5ul/UgtjhHntA0r2FcUE4kEj2lwU1di9EzJv7sdE/YKPrPtFoNoxmthI
OvvEC45QxfNJ6OwpqgSOyKFwE230x8UPKmgGDQmED3PNrio3PlcM0XONDtgBewL0
3+OgERo/6JcZbs4CtORrpPxpJd6kvBiDgG07pUxMNKC2EbQGxkXer4bvlyqLiVzt
bwIDAQAB
-----END PUBLIC KEY-----
    </Property>

    <!-- claims to verify -->
    <Property name="claim_iss">http://dinochiesa.net</Property>
    <Property name="claim_shoesize">8.5</Property>
  </Properties>

  <ClassName>com.apigee.callout.jwtsigned.JwtParserCallout</ClassName>
  <ResourceURL>java://apigee-edge-callout-jwt-signed-1.0.9.jar</ResourceURL>
</JavaCallout>

When I import the attached proxy and then invoke the proxy with

curl -i https://ORG-ENV.apigee.net/ofs-jwt/t2 -d 'jwt=eyJ0eXAiOiJKV1QiLCJh...'

...it works as expected.

Actually the JWT is now expired. So the JAR throws an error, which is expected when the JWT is expired. If I include the wantVerify=false, like so:

  <Properties>
    <Property name="wantVerify">false</Property>
    ... 

...then the JWT is successfully parsed, but the sig is not verified, and no exception is thrown. This is all as expected.

ofs-jwt.zip

View solution in original post

11 REPLIES 11

yes, can you show the policy configuration for the Parse/Validate step?

The policy is generating a NullPointerException, which is not helpful. I will correct that so that it returns a better error message.

The root cause is that there is no public key. Something is wrong with the configuration of the policy. I'm extending the test cases to duplicate what you're doing, and will modify the policy source code to issue a better (clearer) error message.

Thanks Dino.

Here's the policy config:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="JWT-Parse-RS256">
    <Properties>
        <Property name="algorithm">RS256</Property>
        <Property name="jwt">{request.formparam.jwt}</Property>
        <!-- pemfile stored the public key used for algorithm = RS256 -->
        <Property name="pemfile">public-key.pem</Property>
        <!-- claims to verify -->
        <Property name="claim_motto">Iloveapis</Property>
    </Properties>
    <ClassName>com.apigee.callout.jwtsigned.JwtParserCallout</ClassName>
    <ResourceURL>java://jwt-signed-edge-callout.jar</ResourceURL>
</JavaCallout>

And that "public-key.pem" still exists within the JAR? and the public-key.pem is a non-empty file?

Public key is mentioned below. I have taken this from the resources folder from github sample. It should be included in the JAR.

-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxlohiBDbI/jejs5WLKe
Vpb4SCNM9puY+poGkgMkurPRAUROvjCUYm2g9vXiFQl+ZKfZ2BolfnEYIXXVJjUm
zzaX9lBnYK/v9GQz1i2zrxOnSRfhhYEb7F8tvvKWMChK3tArrOXUDdOp2YUZBY2b
sl1iBDkc5ul/UgtjhHntA0r2FcUE4kEj2lwU1di9EzJv7sdE/YKPrPtFoNoxmthIOvvEC45QxfNJ6OwpqgSOyKFwE230x8UPKmgGDQmED3PNrio3PlcM0XONDtgBewL03+OgERo/6JcZbs4CtORrpPxpJd6kvBiDgG07pUxMNKC2EbQGxkXer4bvlyqLiVzt
bwIDAQAB
-----END PUBLIC KEY-----

I know that it "should be" included in the JAR. Can you verify that it IS actually included in the JAR? Have you rebuilt the jar?

to check it, you can do

jar tf path-to/jwt-signed-edge-callout.jar

and look for the output that specifies the public-key.pem

Tell you what - I pushed a change to the JAR file to the github repo. if you are using the existing jar file (have not rebuilt it), can you just replace the one you have, with the current version from github?

$ shasum target/jwt-signed-edge-callout.jar 
1bd571f8298685c7bc99622d86cac28320d59008  target/jwt-signed-edge-callout.jar


$ ls -lrt target/jwt-signed-edge-callout.jar
-rw-r--r--  1 dino  staff  32952 Dec 14 17:33 target/jwt-signed-edge-callout.jar

This will issue a better error message, I think. It may help in diagnosing what's going on.

If you have rebuilt the jar to embed your own resources (your own custom pem files), then you will need to "git pull" to get all the sources from that repo, and rebuild.

Thanks.

Now I get below error message:

{
  "error": {
    "code": 500,
    "jwt_error": "jwt_error",
    "message": "com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: there was no public key specified.",
    "reason": "there was no public key specified."
  }
}

How can I specify the public key?

I think it is already specified:

<Property name="pemfile">public-key.pem</Property>

yes it appears to be. This can happen if the public-key.pem is not readable, is empty, or is otherwise not accessible.

But if you are using the original JAR unmodified, then I don't understand how that is happening.

I need to take a break; will look again in a bit.

I'm sorry, I just re-tried this example, starting from scratch, and experienced the same problem you reported. There's a bug in the logic. Working on it now.

Update - 2016 dec 15 2035 PST
I've updated the repo and corrected the problem. The resources in the JAR were not being correctly recognized. I've now added tests to verify that behavior.

You can run "git pull" to get the latest, corrected version. Please try again.

Sorry about the trouble.

Sorry! This question slipped under the radar and has now been sitting for 7 months!

I just tried this JWT with the latest JWT JAR from the github repo, and it worked fine for me.

This is the policy configuration I used:

<JavaCallout name='JWT-Parse-RS256-1'>
  <DisplayName>JWT-Parse-RS256-1</DisplayName>
  <Properties>
    <Property name="algorithm">RS256</Property>
    <Property name="jwt">{request.formparam.jwt}</Property>
    <Property name="public-key">
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxlohiBDbI/jejs5WLKe
Vpb4SCNM9puY+poGkgMkurPRAUROvjCUYm2g9vXiFQl+ZKfZ2BolfnEYIXXVJjUm
zzaX9lBnYK/v9GQz1i2zrxOnSRfhhYEb7F8tvvKWMChK3tArrOXUDdOp2YUZBY2b
sl1iBDkc5ul/UgtjhHntA0r2FcUE4kEj2lwU1di9EzJv7sdE/YKPrPtFoNoxmthI
OvvEC45QxfNJ6OwpqgSOyKFwE230x8UPKmgGDQmED3PNrio3PlcM0XONDtgBewL0
3+OgERo/6JcZbs4CtORrpPxpJd6kvBiDgG07pUxMNKC2EbQGxkXer4bvlyqLiVzt
bwIDAQAB
-----END PUBLIC KEY-----
    </Property>

    <!-- claims to verify -->
    <Property name="claim_iss">http://dinochiesa.net</Property>
    <Property name="claim_shoesize">8.5</Property>
  </Properties>

  <ClassName>com.apigee.callout.jwtsigned.JwtParserCallout</ClassName>
  <ResourceURL>java://apigee-edge-callout-jwt-signed-1.0.9.jar</ResourceURL>
</JavaCallout>

When I import the attached proxy and then invoke the proxy with

curl -i https://ORG-ENV.apigee.net/ofs-jwt/t2 -d 'jwt=eyJ0eXAiOiJKV1QiLCJh...'

...it works as expected.

Actually the JWT is now expired. So the JAR throws an error, which is expected when the JWT is expired. If I include the wantVerify=false, like so:

  <Properties>
    <Property name="wantVerify">false</Property>
    ... 

...then the JWT is successfully parsed, but the sig is not verified, and no exception is thrown. This is all as expected.

ofs-jwt.zip