Apigee Edge OPDK: JWT Token Expired Use-case - ExecutionFailureError

sharath034
Participant II

Hi Everyone and Dino,

I thank everyone for answering my previous question and special thanks to @Dino.

We are having a issue while executing a Java callout. We are using Apigee Edge on-premises.

We are using java callout from iloveapis - JWT. We are able to generate the JWT access_tokens and validate the access tokens. We are having a problem when running the proxy for validate or generating a new JWT when Access_token/jwt is expired.

We are getting the following error when the request is sent from POSTMAN.

{
    "fault": {
        "faultstring": "Execution returned an error result",
        "detail": {
            "errorcode": "flow.execution.ExecutionReturnedFailure"
        }
    }
}

The error when running a trace.

6802-11.png

6803-2222.png

Please, let me know if any more information is needed.

Solved Solved
1 7 838
1 ACCEPTED SOLUTION

ok, I understand that you are using the jwt_signed callout, on OPDK. I understand that the Java Parse callout is throwing a fault in the case of expired JWT.

I don't understand what you expect or desire to happen.

Throwing a fault when parsing an expired JWT seems like the correct behavior.

What do you think the callout should do when the JWT is expired?

You should be aware of two documented properties on the callout:

  • continueOnError - true or false, defaults to false. If you want the policy to continue and NOT throw a fault even if the JWT is expired, set this to true.
  • wantVerify - true or false, defaults to true. If you set it to false, the parse callout does not verify the JWT at all; does not verify the algorithm, the expiry, the signature, and so on

Both of these are described in the README.

View solution in original post

7 REPLIES 7

ok, I understand that you are using the jwt_signed callout, on OPDK. I understand that the Java Parse callout is throwing a fault in the case of expired JWT.

I don't understand what you expect or desire to happen.

Throwing a fault when parsing an expired JWT seems like the correct behavior.

What do you think the callout should do when the JWT is expired?

You should be aware of two documented properties on the callout:

  • continueOnError - true or false, defaults to false. If you want the policy to continue and NOT throw a fault even if the JWT is expired, set this to true.
  • wantVerify - true or false, defaults to true. If you set it to false, the parse callout does not verify the JWT at all; does not verify the algorithm, the expiry, the signature, and so on

Both of these are described in the README.

@Dino

ContinueOnError is not working when assigned to True. It is failing before hand and giving an output in POSTMAN as follows:

{
    "fault": {
        "faultstring": "Execution returned an error result",
        "detail": {
            "errorcode": "flow.execution.ExecutionReturnedFailure"
        }
    }
}

The request is not even reaching the other step or next step. Please take a look at the picture.

6821-11.png

6822-22.png

It seems to be a technical issue. I personally request you to look into it and reply.

Thanks,

Sharath

Sharath, as always, please show me the exact configuration you are using.

The screenshots are nice, but I need to see how you've configured the policy. ALL of the configuration. Including the specification of the JAR.

@Dino..

The following is the configuration for the JWTValidate Policy we are using.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="JWT-Parse-HS256" enabled="true" continueOnError="true">
    <Properties>
        <!-- <Property name="wantVerify">true</Property> -->
        <!--  <Property name="debug">true</Property> -->
        <Property name="algorithm">HS256</Property>
        <Property name="jwt">{request.header.jwt}</Property>
        <Property name="secret-key">{verifyapikey.Verify-API-Key.key}</Property>
 
        <!-- verify these claims -->
        <!--<Property name="claim_name">{response.content}</Property>-->
        <!-- <Property name="claim_iss">http://dinochiesa.net</Property> -->
        <!--<Property name="claim_aud">{apiproxy.name}</Property><Property name="claim_shoesize">9</Property>-->
 
 
    </Properties>
 
    <ClassName>com.apigee.callout.jwtsigned.JwtParserCallout</ClassName>
    <ResourceURL>java://apigee-edge-callout-jwt-signed-1.0.16.jar</ResourceURL>
</JavaCallout>

We are using the same Parse-HS256 Configuration that was been available in your GITHUB. (iloveapis).

ok thank you. I see you have the continueOnError attribute set on the element. Like this:

<JavaCallout name="JWT-Parse-HS256" enabled="true" continueOnError="true">

The continueOnError thing needs to be set as a Property. Like this:

  <Property name="continueOnError">true</Property><br>

That's unfortunate, because there's an attribute on the callout element itself, with the same name. But the Java Callout cannot get access to the attribute on the element. In fact the attribute on the element is meaningless.

This is described on the readme.

Can you try that way and see what results you get?

Thanks Dino.

We are getting the same response. It started last night out of nowhere.

This is our policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="GenerateStackdriverJWT" enabled="true" continueOnError="true">
    <DisplayName>GenerateStackdriverJWT</DisplayName>
    <Properties>
        <Property name="algorithm">RS256</Property>
        <Property name="private-key">{private.stackdriver.privKeyPem}</Property>
        <!-- standard claims -->
        <Property name="issuer">{stackdriver.jwt_issuer}</Property>
        <Property name="audience">https://www.googleapis.com/oauth2/v4/token</Property>
        <Property name="expiresIn">90</Property>
        <!-- in seconds; for stackdriver, 300 max -->
        <!-- custom claims -->
        <Property name="claim_scope">https://www.googleapis.com/auth/logging.write</Property>
    </Properties>
    <Property name="continueOnError">true</Property>
    <ClassName>com.apigee.callout.jwtsigned.JwtCreatorCallout</ClassName>
    <ResourceURL>java://apigee-edge-callout-jwt-signed-1.0.5.jar</ResourceURL>
</JavaCallout>

And this is the stacktrace in out trace:

java.util.concurrent.ExecutionException: 
org.apache.commons.ssl.ProbablyNotPKCS8Exception: asn1 parse failure: 
java.io.IOException: DER length more than 4 bytes
	at 
com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:299)
	at 
com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:286)
	at 
com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:116)
	at 
com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly(Uninterruptibles.java:137)
	at 
com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2348)
	at 
com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2320)
	at 
com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2282)
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2197)
	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.JwtCreatorCallout.getRsaSigner(JwtCreatorCallout.java:111)
	at 
com.apigee.callout.jwtsigned.JwtCreatorCallout.execute(JwtCreatorCallout.java:483)
	at 
com.apigee.steps.javacallout.JavaCalloutStepDefinition$ClassLoadWrappedExecution.execute(JavaCalloutStepDefinition.java:204)
	at 
com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:271)
	at 
com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:269)
	at java.security.AccessController.doPrivileged(Native Method)
	at 
com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution.execute(JavaCalloutStepDefinition.java:269)
	at 
com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.execute(JavaCalloutStepDefinition.java:138)
	at 
com.apigee.messaging.runtime.steps.StepExecution.execute(StepExecution.java:156)
	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:1149)
	at 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.commons.ssl.ProbablyNotPKCS8Exception: asn1 parse 
failure: java.io.IOException: DER length more than 4 bytes
	at org.apache.commons.ssl.PKCS8Key.<init>(PKCS8Key.java:190)
	at 
com.apigee.callout.jwtsigned.JwtCreatorCallout.generatePrivateKey(JwtCreatorCallout.java:343)
	at 
com.apigee.callout.jwtsigned.JwtCreatorCallout.access$000(JwtCreatorCallout.java:55)
	at 
com.apigee.callout.jwtsigned.JwtCreatorCallout$2.load(JwtCreatorCallout.java:95)
	at 
com.apigee.callout.jwtsigned.JwtCreatorCallout$2.load(JwtCreatorCallout.java:93)
	at 
com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3527)
	at 
com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2319)
	... 22 more
Can you help in any way? Do you need additional info?