1

I'm working on a Groovy script in the SAP CPI environment which means the script runs in a somewhat canned JVM.

I uploaded the jjwt-api-0.11.2, jjwt-impl-0.11.2 and jjwt-jackson-0.11.2 jars, in order to build a JWT.

The first run just after deployment the script runs just fine, but every run afterwards I get the following error:

com.sap.it.rt.adapter.http.api.exception.HttpResponseException: An internal server error occured: java.lang.ClassCastException: io.jsonwebtoken.impl.DefaultJwtBuilder (loaded by com.sap.gateway.ip.core.customdev.classloader.MergeClassLoaders@1625616) cannot be cast to io.jsonwebtoken.JwtBuilder (loaded by com.sap.gateway.ip.core.customdev.classloader.MergeClassLoaders@1624982) (found matching interface io.jsonwebtoken.JwtBuilder loaded by com.sap.gateway.ip.core.customdev.classloader.MergeClassLoaders@1625616, but needed loader com.sap.gateway.ip.core.customdev.classloader.MergeClassLoaders@1624982)@ line 70 in script1.groovy.

Line 70 reads:

JwtBuilder jwtBuilder = Jwts.builder().setClaims(claims).setIssuedAt(nowDate).setExpiration(expDate).setHeader((Map<String, Object>) header);

The error persists even if I change it to:

DefaultJwtBuilder jwtBuilder = Jwts.builder().setClaims(claims).setIssuedAt(nowDate).setExpiration(expDate).setHeader((Map<String, Object>) header);

When I re-deploy, it works again the first time and then goes back to the error every subsequent call.

As a debugging aid I dumped System.getenv() but the data it returns is the same in both succesful and erroneous runs:

{HC_GLOBAL_HOST=br1.hana.ondemand.com, HC_COMPONENT=web, HC_REGION=BR_1, HC_APPLICATION=someid, HC_HOST_INT=int.br1.hana.ondemand.com, replicate_ebs_volumes=false, replicate_ebs_with_delete=false, HC_PROCESS_ID=f6576be76bd88828e305602dbbca9d13890c, ENABLE_CAM=false, HC_LANDSCAPE=production, DISABLE_ANTIVIRUS=true, HC_APPLICATION_URL=https://someid-n9e08ec00.int.br1.hana.ondemand.com, HC_LOCAL_HTTP_PORT=9001, HC_HOST_SCP=sapcp.br1.hana.ondemand.com, HC_HOST_SVC=svc.br1.hana.ondemand.com, HC_HOST_CERT=cert.br1.hana.ondemand.com, HC_LANDSCAPE_TYPE=single_AZ, HC_ACCOUNT=someotherid, HC_OP_HTTP_PROXY_HOST=localhost, LDAP_SEARCH_BASE=dc=spa3,dc=od,dc=sap,dc=biz, HC_HOST=br1.hana.ondemand.com, HC_OP_HTTP_PROXY_PORT=20003, HOME=/usr/sap/ljs/home, HC_AVAILABILITY_ZONE=NLB1FSA02}

The rest of the relevant code is:

import com.sap.gateway.ip.core.customdev.util.Message;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.keystore.KeystoreService;

import java.security.cert.Certificate;
import java.security.Key;
import java.util.HashMap;
import java.io.File;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.Scanner;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.impl.DefaultJwtBuilder;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultHeader;


def Message processData(Message message) {
     
    def messageLog = messageLogFactory.getMessageLog(message);

    messageLog.addAttachmentAsString("dump_env", System.getenv().toString(), "text/plain");
    
    Map<String, Object> header = new HashMap<String, Object>();
    header.put("typ", "JWT");
    header.put("alg", "RS256");
    
//  Claims claims = Jwts.claims();
    Map<String, Object> claims = new HashMap<String, Object>();
    claims.put("scope", "https://www.googleapis.com/auth/devstorage.full_control");
    claims.put("aud", tokenUrl);
    claims.put("iss", "mysecret@thing.iam.gserviceaccount.com");
    
    /* Create JWT json with JwtBuilder */
    DefaultJwtBuilder jwtBuilder = Jwts.builder().setClaims(claims).setIssuedAt(nowDate).setExpiration(expDate)
            .setHeader((Map<String, Object>) header);
    // ^^^^^^^^----> Crashing line
    
    // ...jwt signing and whatnot

    /* Set body and URL encode the grant_type string. */ 
    body = "grant_type=" + URLEncoder.encode("urn:ietf:params:oauth:grant-type:jwt-bearer") + "&assertion=" + assertion             
    message.setHeader("Content-Type", "application/x-www-form-urlencoded")    
    message.setBody(body);

   return message;

Formerly I was using the Headers and Claims classes but those were exhibiting this same issue (they worked fine the first time but afterwards threw a classcasting error which didn't go away by changing the variable class)

What are other tools, system variables or resources I could use to debug this strange behaviour?

I suspect it's a classloading error, but I'm learning java as I work on this and I still haven't got to grips with the JVM and the Java world idiosyncrasy.

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
Vladimir
  • 393
  • 3
  • 16

0 Answers0