当Coldfusion从'jar'文件中调用方法时,未编译的Java程序可以正常工作,但会产生错误?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当Coldfusion从'jar'文件中调用方法时,未编译的Java程序可以正常工作,但会产生错误?相关的知识,希望对你有一定的参考价值。

项目:

将JWT转换为已签名的加密JWE

环境:

  1. Windows 10
  2. Jdk1.d
  3. Apache Maven 3.5.4
  4. VSCode 1.25.1包含所有必需的Java扩展
  5. 带有JRE1.8的Adobe Coldfusion 11 Application Server

依赖关系:

  1. 灵气何塞 - 智威汤逊 - 6.0
  2. JSON-智能2.3
  3. ASM-1.0.2

问题:

首先,请理解我是Java的新手,但我对Coldfusion [CFML,如php]有很好的理解。

当我从VSCode中运行我的程序时,我得到序列化JWT字符串的预期结果。

当我尝试从'jar'文件中访问该方法时,使用我的服务器端语言Coldfusion [类似于PHP],我得到一个错误,来自最后一行。

构造函数已成功初始化,并且大多数方法调用都会执行。

我仔细测试了每一行,绝大多数代码在外部调用'JwtSignEncrypt'类的'Encrypt()'方法时都有效,但是最后一行失败并出现以下错误。

The JWE object must be in an encrypted or decrypted state

堆栈跟踪的重要部分:

java.lang.IllegalStateException: The JWE object must be in an encrypted or decrypted state
at com.nimbusds.jose.JWEObject.ensureEncryptedOrDecryptedState(JWEObject.java:320)
at com.nimbusds.jose.JWEObject.serialize(JWEObject.java:456)
at com.chamika.jwt.JwtSignEncrypt.Encrypt(JwtSignEncrypt.java:153)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at coldfusion.runtime.StructBean.invoke(StructBean.java:508)
at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2553)
at cftest412ecfm1275900201.runPage(C:ColdFusion11cfusionwwwrootestablishmindfulnessunit-test	est41.cfm:129)
at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:246)
at coldfusion.tagext.lang.IncludeTag.handlePageInvoke(IncludeTag.java:736)
at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:572)
at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65)
at coldfusion.filter.IpFilter.invoke(IpFilter.java:45)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:466)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:42)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:142)
at coldfusion.filter.LicenseFilter.invoke(LicenseFilter.java:30)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:94)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:58)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
at coldfusion.CfmServlet.service(CfmServlet.java:219)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at coldfusion.inspect.weinre.MobileDeviceDomInspectionFilter.doFilter(MobileDeviceDomInspectionFilter.java:121)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:422)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

JW TSI缸内encrypt.Java

package com.chamika.jwt;

import java.util.*;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;


public class JwtSignEncrypt 
{

    String issuer;
    String subject;
    List<String> audience;
    Date expirationTime;
    Date notBeforeTime;
    Date issueTime;
    String jwtID;
    Map<String, Object> claim;

    public JwtSignEncrypt(final String iss, 
            final String sub,
            final String aud,
            final Date exp,
            final Date nbf,
            final Date iat,
            final String jti,
            Map<String, Object> cla) {
        if(iss != null) {        
            this.issuer = iss;
        }
        if(sub != null) {
            this.subject = sub;
        }
        if(aud != null) {
            List<String> items = Arrays.asList(aud.split("\s*,\s*")); 
            this.audience = items;
        }
        if(exp != null) {
            this.expirationTime = exp;
        }
        if(nbf != null) {
            this.notBeforeTime = nbf;
        }
        if(iat != null) {
            this.issueTime = iat;
        }
        if(jti != null) {
            this.jwtID = jti;
        }
        if(cla != null) {
            this.claim = cla;
        }
    }


    public String Encrypt(byte[] secretKeyEncoded) {

        String key = null;
        Object value = null;

        for (Map.Entry<String, Object> entry : claim.entrySet()) {
            key = entry.getKey();
            value = entry.getValue();
        }

        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().issuer(this.issuer).subject(this.subject).audience(this.audience).expirationTime(this.expirationTime).notBeforeTime(this.notBeforeTime).issueTime(this.issueTime).jwtID(this.jwtID).claim(key,value).build();

        String jweobject = "";
        JWSSigner signer;

        try {

            signer = new MACSigner(secretKeyEncoded);
            SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
            try {
                signedJWT.sign(signer);
            } catch (JOSEException e) {
                e.printStackTrace();
            }

            JWEObject jweObject = new JWEObject(
                new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                    .contentType("JWT") 
                    .build(),
                new Payload(signedJWT));

            try {
                jweObject.encrypt(new DirectEncrypter(secretKeyEncoded));

            } catch (KeyLengthException e) {
                e.printStackTrace();
            } catch (JOSEException e) {
                e.printStackTrace();
            }

            jweobject = jweObject.serialize();

        } catch (KeyLengthException e) {
            e.printStackTrace();
        }

        return jweobject;
    }

}

在java文件中的以下行发生错误:

jweObject.encrypt(new DirectEncrypter(secretKeyEncoded));

Coldfusion onRequestStart方法中的Java Loader:

  <cfset request.lckchamikajwtlibinit = true />

  <cfif NOT StructKeyExists(APPLICATION,"chamikajwtlib") OR request.appreload>
    <cftry>
      <cflock name="chamikajwtlib" type="exclusive" timeout="#request.writelocktimeout#">
        <cfset local.jbClasschamikajwt = "#request.filepathasset#libchamika-jwt-sign-encryptchamika-jwt-sign-encrypt-1.0.2.jar" />
        <cfset local.javaloader = createObject('component','com.javaloader.JavaLoader') />
        <cfset application.chamikajwtlib = local.javaloader.init([local.jbClasschamikajwt]) />
      </cflock>
      <cfcatch>
        <cfset request.lckchamikajwtlibinit = false />
      </cfcatch>
    </cftry>
  </cfif>

  <cfif request.lckchamikajwtlibinit>
    <cflock NAME="chamikajwtliblck" TIMEOUT="#request.readlocktimeout#" TYPE="READONLY">
      <cfset request.chamikaJwtSignEncryptJar= application.chamikajwtlib />
    </cflock>
  <cfelse>
    <cfset request.chamikaJwtSignEncryptJar= "" />
  </cfif>

test.cfm

<cfscript>

  local = {};
  local.loader = request.chamikaJwtSignEncryptJar;
  local.issuer = JavaCast("string","https://openid.net");
  local.subject = JavaCast("string","Charles Robertson");
  local.audience = "https://app-one.com,https://app-two.com";
  local.expirationTime = createObject("java","java.util.Date").init().getTime() + 60 * 1000;
  local.expirationTime = createObject("java","java.util.Date").init(local.expirationTime);
  local.currentDateTime = createObject("java","java.util.Date").init();
  local.notBeforeTime = local.currentDateTime;
  local.issueTime = local.currentDateTime;
  local.jwtID = JavaCast("string",CreateUUID());
  local.claim = createObject("java", "java.util.LinkedHashMap").init();
  local.json = {forename="Charles",surname='Robertson'};
  local.claim['json'] = SerializeJson(local.json);
  local.JwtSignEncrypt = local.loader.create("com.chamika.jwt.JwtSignEncrypt").init(local.issuer,local.subject,local.audience,local.expirationTime,local.notBeforeTime,local.issueTime,local.jwtID,local.claim);

  local.keyGen = local.loader.create("javax.crypto.KeyGenerator").getInstance("AES");
  local.keyGen.init(256);
  local.secretKeyEncoded = local.keyGen.generateKey().getEncoded();

  local.jweString = local.JwtSignEncrypt.Encrypt(local.secretKeyEncoded);

  writeDump(var=local.jweString);

</cfscript>

pom.hml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.chamika.jwt</groupId>
  <artifactId>chamika-jwt-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>chamika-jwt-app</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.nimbusds</groupId>
      <artifactId>nimbus-jose-jwt</artifactId>
      <version>6.0</version>
    </dependency>
    <dependency>
        <groupId>net.minidev</groupId>
        <artifactId>json-smart</artifactId>
        <version>2.3</version>
    </dependency>
    <dependency>
    <groupId>net.minidev</groupId>
        <artifactId>asm</artifactId>
        <version>1.0.2</version>
    </dependency>
  </dependencies>
</project>

我已经正确地将所有必需的库包含在我的'jar'中。当我打包'jar'时,我还需要采取其他措施。我正在使用'pom.xml'文件,有3个依赖项。出于某种原因,当我跑:

nvm package

不包含依赖项。所以,我已经使用'jarsplice'来捆绑依赖项。可以在外部独立地正确访问所有依赖项。

问题:

  1. 当我尝试生成签名加密的JWT时,为什么我在使用Coldfusion调用'.jar'文件中的方法时会收到错误?
  2. 为什么我的依赖项不包含在打包的“.jar”文件中?

更新:

这是我的git回购:

https://bitbucket.org/charlesrobertson/chamika-jwt-app/src/master/

我的java类基于官方文档片段:

https://connect2id.com/products/nimbus-jose-jwt/examples/signed-and-encrypted-jwt

答案
  1. 当我尝试生成签名加密的JWT时,为什么我在使用Coldfusion调用'.jar'文件中的方法时会收到错误?

我和CF11有同样的错误。问题是try/catch代码基本上吞下了错误,因为CF没有在屏幕上显示e.printStackTrace()的输出。它被发送到默认日志文件。因此,您甚至不会知道发生异常 - 除非您检查CF日志。

错误处理全部取决于应用程序,但我的想法是,如果方法不能对错误做任何有用的事情,也可以让它冒泡并让调用者决定如何处理它。无论如何,一旦我摆脱了所有的try/catch并为所有方法添加了throws XYZException,如下所示:

public String Encrypt(byte[] secretKeyEncoded) throws KeyLengthException, JOSEException {
    // ...
    jweObject.encrypt(new DirectEncrypter(secretKeyEncoded));
    // ...
}

...我可以在屏幕上看到错误消息。无法创建AES / GCM / NoPadding密码:密钥大小非法。这意味着除非安装了Unlimited JCE files,否则无法创建256位密钥(或更高)。解决方案是下载并安装Unlimited JCE文件并重新启动CF.之后,jar工作正常(具有3个依赖项)。

  • 下载java版本的文件。例如,对于java 8 - jce_policy-8.zip
  • 备份local_policy.jar中现有的US_export_policy.jar<java-home>libsecurity文件
  • 解压缩文件并将新的local_policy.jarUS_export_policy.jar复制到<java-home>libsecurity
  • 重启CF服务器(必填)
  1. 为什么我的依赖项不包含在打包的“.jar”文件中?

Maven不包含依赖项,除非它是specified in the pom.xml,它不适用于此项目。就个人而言,我避免这样做。将所有内容打包到一个大的超级jar中很方便,但是更难以处理依赖项中的版本更改。我只是分别加载相关的罐子。

以上是关于当Coldfusion从'jar'文件中调用方法时,未编译的Java程序可以正常工作,但会产生错误?的主要内容,如果未能解决你的问题,请参考以下文章

从 ColdFusion 引用 java 资源文件

ColdFusion:获取变量类型

Coldfusion 和非作用域变量

如何从中构建JAR文件

Coldfusion 10,IIS 7.5 - 即使文件存在也得到 404

如何正确使用 Coldfusion File Exist() 方法?