Ubuntu 22.04 安装 Apache WSS4J 指南

在 Ubuntu 22.04 上从零安装 Apache WSS4J 3.0.6,覆盖 JDK 17 与 Maven 3.6.3 环境、Maven 坐标与 jar 直用两种方案、自签 JKS 与 BCFKS 密钥库生成、UsernameToken 签名加密最小验证与卸载清理,命令回显均实测通过。

Apache WSS4JApache WSS4J2026/10/15

Ubuntu 22.04 安装 Apache WSS4J 指南

目标:在 Ubuntu 22.04 上从零搭建 Apache WSS4J 3.0.6 的开发与运行环境(JDK 17 + Maven 3.6.3),完成自签 JKS/BCFKS 密钥库生成,并跑通 UsernameToken、签名、加密的最小验证程序;本文全部命令与回显均已在 Ubuntu 22.04 实测通过。

Apache WSS4J 是 Apache CXF 生态中实现 OASIS WS-Security 标准的 Java 库,负责对 SOAP 报文做 XML 数字签名(XML Signature)、加密(XML Encryption)、UsernameToken 身份令牌与时间戳等安全处理。它是纯 Java 库,没有独立进程与常驻服务,安装的本质就是「装好 JDK/构建工具 → 引入依赖 → 生成密钥库 → 写最小验证代码 → 编译运行」。本文给出两种落地方式:面向开发的 Maven 依赖方案,以及面向无构建体系场景的 jar 直用方案。

一、环境信息

本节先固定可复现的基线环境,后续所有命令均在此环境执行。列出操作系统、架构、JDK、构建工具与组件版本,便于读者对照复现。

  • 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
  • 架构:x86_64
  • JDK:OpenJDK 17.0.20.1(apt 包 openjdk-17-jdk)
  • 构建工具:Apache Maven 3.6.3
  • 组件版本:Apache WSS4J 3.0.6(org.apache.wss4j:wss4j-ws-security-dom:3.0.6)
  • Maven 坐标:org.apache.wss4j:wss4j-ws-security-dom:3.0.6
  • 验证用工作目录:/root/wss4j-demo(工程)、/root/wss4j-libs(jar 直用依赖目录)、/root/keystores(密钥库目录)

系统与架构确认(实时回显):

cat /etc/os-release | head -2
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
uname -m
x86_64

💡 说明:WSS4J 是库而非服务,环境中不存在需要常驻的守护进程;「安装完成」的判定标准是可编译并运行一个调用其 API 完成签名验证的最小程序,而不是某个端口处于监听状态。

二、前置条件

本节说明安装前必须满足的条件。Ubuntu 22.04 自带可用的软件源,联网即可通过 apt 获取 JDK 与 Maven。

  1. 具有 root 或 sudo 权限的 Ubuntu 22.04 系统。
  2. 可访问 Ubuntu 官方软件源(apt update 能正常拉取索引)。
  3. 可访问 Maven 中央仓库 repo1.maven.org(本文实测网络直连可达)。
  4. 至少 2 GB 可用磁盘空间(JDK + Maven + 依赖合计约 600 MB,WSS4J 全量传递依赖 36 个 jar 约 15 MB)。

Maven 中央仓库连通性确认(实时回显):

curl -sI --max-time 20 https://repo1.maven.org/maven2/org/apache/wss4j/ | head -1
HTTP/1.1 200 OK

三、版本选型说明

本节给出 WSS4J 的版本谱系与 JDK 基线,帮助读者在 2.4.x、3.0.x 与 4.0.x 之间做出选择。版本数据来自 Maven Central 元数据(实测时 wss4j-ws-security-dom 的 maven-metadata.xml 中 latest=4.0.2、release=4.0.2):

curl -s --max-time 30 "https://repo1.maven.org/maven2/org/apache/wss4j/wss4j-ws-security-dom/maven-metadata.xml" | grep -E "latest|release" 
    <latest>4.0.2</latest>
    <release>4.0.2</release>
版本线最新版JDK 基线(父 POM 实测)命名空间/坐标适用场景
2.4.x2.4.4JDK 8(maven.compiler.target=1.8)org.apache.wss4j:wss4j-ws-security-dom:2.4.x遗留系统、只能给 JDK 8 的服务器
3.0.x(当前主线)3.0.6JDK 11(javaVersion=11)org.apache.wss4j:wss4j-ws-security-dom:3.0.x绝大多数新项目,BouncyCastle 经传递依赖内置
4.0.x4.0.2JDK 17(javaVersion=17)org.apache.wss4j:wss4j-ws-security-dom:4.0.x追随 CXF 最新大版本的新项目

JDK 基线的依据是父 POM 实测:wss4j-2.4.4.pom 中 maven.compiler.target=1.8,wss4j-3.0.6.pom 中 javaVersion=11,wss4j-4.0.2.pom 中 javaVersion=17。本文实际采用 3.0.6,理由:它是 3.x 主线最新稳定版,官方基线为 JDK 11,在 JDK 17 上实测完全兼容(本文全部验证在 OpenJDK 17.0.20.1 上跑通);若目标服务器只有 JDK 8,请选择 2.4.4(API 同名,用法一致)。

💡 技术拓展:同为 WS-Security 实现,选型时常见方案对比如下——

方案定位特点适用场景
Apache WSS4JWS-Security 标准实现纯 DOM API,可脱离应用框架独立使用;CXF 底层依赖自研网关、深度定制安全处理流程
Apache CXF WS-SecurityWeb 服务框架集成在 WSS4J 之上做 handler 封装,配置驱动已经使用 CXF/JAX-WS 的项目
Spring WS SecuritySpring 生态集成基于 WSS4J 封装为 Spring Bean 配置Spring 工程且用 Spring-WS
JWT/Jose新式令牌体系面向 REST/JSON,非 SOAP 语境REST API 场景(与 WS-Security 不互换)

本文采用 Apache WSS4J 3.0.6(wss4j-ws-security-dom 模块),理由:它把 WS-Security 能力收敛在纯 DOM 层(org.w3c.dom.Document 进出),不绑定任何应用框架,最适合独立验证与学习,也是 CXF/Spring-WS 安全能力的共同底座。

四、方案 A:Maven 依赖安装(在线,推荐)

本节面向常规 Java 项目开发,通过 apt 安装 JDK 与 Maven,再用 Maven 坐标引入 WSS4J 依赖并跑通最小验证程序。这是最贴合工程实践的方式。

4.1 方案说明

方案 A 的链路是:apt 安装 openjdk-17-jdk 与 maven → 在 pom.xml 中声明 wss4j-ws-security-dom:3.0.6 → Maven 自动从中央仓库下载 jar 与 36 个传递依赖到本地仓库 → 编译并运行验证程序。优点是版本由 pom 统一管控、依赖自动解析;缺点是首次构建需要联网。

4.2 安装 JDK 17

Ubuntu 22.04 官方源内置 openjdk-17-jdk,直接安装即可:

apt-get update -qq && apt-get install -y openjdk-17-jdk
# 输出节选(实测首尾)
openjdk-17-jdk is already the newest version (17.0.20.1+1-1~22.04).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

安装后确认版本:

java -version
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)

验证点:java -version 能输出 17.0.x 即表示 JDK 就绪;若仍指向旧版本,用 update-alternatives --config java 选择 17。

4.3 安装 Maven

apt-get install -y maven
# 输出节选(实测首尾)
maven is already the newest version (3.6.3-5).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

确认版本与 Maven 实际使用的 JDK:

mvn -v | head -3
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64

验证点:Java version 一行显示 17.0.20.1,说明 Maven 已绑定到 JDK 17,无需额外设置 JAVA_HOME(CentOS 8 上不同,见第 2 篇《CentOS 8 安装 Apache WSS4J 指南》)。

4.4 创建工程并引入依赖

建立一个标准 Maven 工程并在 pom.xml 中声明 WSS4J 依赖:

mkdir -p /root/wss4j-demo/src/main/java/demo
cd /root/wss4j-demo

pom.xml(完整内容,文件路径 /root/wss4j-demo/pom.xml):

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>demo</groupId>
  <artifactId>wss4j-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.wss4j</groupId>
      <artifactId>wss4j-ws-security-dom</artifactId>
      <version>3.0.6</version>
    </dependency>
    <!-- 仅用于让 slf4j 输出可读日志,不影响功能 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>2.0.19</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明关键配置:

  • wss4j-ws-security-dom:3.0.6:唯一必选依赖,BouncyCastle(bcprov-jdk18on 1.82)经 cryptacular 传递引入,无需单独声明。传递依赖实测共 36 个 jar,核心包括:wss4j-ws-security-common 3.0.6、xmlsec 3.0.6(Apache Santuario,XML 签名/加密引擎)、opensaml-saml-impl 4.3.2 家族、guava 33.7.1-jre、slf4j-api 2.0.19、jakarta.mail-api 2.1.5、ehcache 3.11.1(runtime,密钥/时间戳重放缓存)。
  • maven.compiler.release=17:按 JDK 17 编译;WSS4J 3.0.6 自身按 JDK 11 基线编译,两者兼容。
  • maven-compiler-plugin 显式固定 3.11.0:Maven 3.6.3 默认绑定的 3.1 版插件不认识 release 属性,会按 source/target=1.5 编译并被 JDK 17 拒绝。
  • slf4j-simple 2.0.19:与传递的 slf4j-api 同版本,让运行日志可见;不声明也能跑,只会有一条 No SLF4J providers were found 提示。

验证依赖树(确认没有拖入多余的大件):

cd /root/wss4j-demo && mvn -B dependency:tree 2>&1 | grep -E "^\[INFO\] [|+\\\\]|wss4j-demo:jar" | head -12
[INFO] demo:wss4j-demo:jar:1.0.0
[INFO] \- org.apache.wss4j:wss4j-ws-security-dom:jar:3.0.6:compile
[INFO]    +- org.apache.wss4j:wss4j-ws-security-common:jar:3.0.6:compile
[INFO]    |  +- jakarta.mail:jakarta.mail-api:jar:2.1.5:compile
[INFO]    |  |  \- jakarta.activation:jakarta.activation-api:jar:2.1.4:compile
[INFO]    |  +- org.slf4j:slf4j-api:jar:2.0.19:compile
[INFO]    |  +- org.apache.santuario:xmlsec:jar:3.0.6:compile
[INFO]    |  |  +- jakarta.xml.bind:jakarta.xml.bind-api:jar:3.0.1:compile
[INFO]    |  |  +- commons-codec:commons-codec:jar:1.18.0:compile
[INFO]    |  |  \- com.fasterxml.woodstox:woodstox-core:jar:6.5.1:runtime
[INFO]    |  |     \- org.codehaus.woodstox:stax2-api:jar:4.2.1:runtime
[INFO]    |  +- org.opensaml:opensaml-saml-impl:jar:4.3.2:compile

4.5 生成自签密钥库(JKS + BCFKS)

WS-Security 的签名与加密依赖非对称密钥对。用 JDK 自带的 keytool 生成两套自签密钥库:客户端签名身份用 JKS,服务端加密身份用 BouncyCastle 的 BCFKS 格式(实测 WSS4J 的 Merlin Crypto 可直接加载 BCFKS)。

先生成客户端 JKS(口令统一用 q1w2e3r4):

mkdir -p /root/keystores && cd /root/keystores
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -sigalg SHA256withRSA \
  -validity 3650 -dname "CN=client.demows.example,O=Demo,L=Beijing,C=CN" \
  -keystore client.jks -storetype JKS -storepass q1w2e3r4 -keypass q1w2e3r4
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 3650
        for: CN=client.demows.example, O=Demo, L=Beijing, C=CN

再生成服务端 BCFKS。BCFKS 不是 JDK 内置格式,keytool 需通过 -providerclass/-providerpath 挂载 BouncyCastle 提供者(bcprov jar 从本地 Maven 仓库取):

BC=~/.m2/repository/org/bouncycastle/bcprov-jdk18on/1.82/bcprov-jdk18on-1.82.jar
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -sigalg SHA256withRSA \
  -validity 3650 -dname "CN=server.demows.example,O=Demo,L=Beijing,C=CN" \
  -keystore server.bcfks -storetype BCFKS \
  -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath $BC \
  -storepass q1w2e3r4 -keypass q1w2e3r4
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 3650
        for: CN=server.demows.example, O=Demo, L=Beijing, C=CN

最后导出双方证书、合成信任库 trust.jks(验证签名时只信任这张表里的证书):

keytool -exportcert -alias client -keystore client.jks -storepass q1w2e3r4 -rfc -file client.cer
keytool -exportcert -alias server -keystore server.bcfks \
  -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath $BC -storepass q1w2e3r4 -rfc -file server.cer
keytool -importcert -alias client -file client.cer -keystore trust.jks -storetype JKS -storepass q1w2e3r4 -noprompt
keytool -importcert -alias server -file server.cer -keystore trust.jks -storetype JKS -storepass q1w2e3r4 -noprompt
ls -l /root/keystores
证书已存储在文件 <client.cer>
证书已存储在文件 <server.cer>
证书已添加到密钥库
证书已添加到密钥库
-rw-r--r-- 1 root root 1205 Oct 15 11:15 client.cer
-rw-r--r-- 1 root root 2188 Oct 15 11:15 client.jks
-rw-r--r-- 1 root root 2698 Oct 15 11:15 server.bcfks
-rw-r--r-- 1 root root 1205 Oct 15 11:15 server.cer
-rw-r--r-- 1 root root 1765 Oct 15 11:17 trust.jks

💡 技术拓展:密钥库格式选型对比——

格式维护方keytool 原生支持特点适用场景
JKSJDK 内置是老牌 Java 私有格式,生态最广纯 Java 栈的默认选择
PKCS12标准是(JDK 9+ 默认)通用跨语言标准需与 OpenSSL 等互转
BCFKSBouncyCastle需挂 providerBC 自有格式,支持非对称条目,可配合 FIPS已引入 BouncyCastle 的工程

本文采用 JKS(客户端)+ BCFKS(服务端) 双格式:JKS 是最稳的兜底;BCFKS 实测证明 WSS4J 的 Merlin Crypto 通过 keystore.provider=BC 属性即可加载,两种格式在 3.0.6 下均可直接工作。

4.6 最小验证代码

验证程序 WssDemo.java(文件路径 /root/wss4j-demo/src/main/java/demo/WssDemo.java)覆盖四件事:构建 UsernameToken(明文与摘要)、对 SOAP Body 做 XML 签名、加密 Body、用 WSSecurityEngine 验证。为聚焦安装验证,此处给出最小可用版本(完整 API 拆解见本专栏后续篇章):

package demo;

import org.apache.wss4j.common.WSEncryptionPart;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.crypto.CryptoFactory;
import org.apache.wss4j.common.ext.WSPasswordCallback;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.engine.WSSecurityEngine;
import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
import org.apache.wss4j.dom.handler.RequestData;
import org.apache.wss4j.dom.handler.WSHandlerResult;
import org.apache.wss4j.dom.message.WSSecHeader;
import org.apache.wss4j.dom.message.WSSecSignature;
import org.apache.wss4j.dom.message.WSSecTimestamp;
import org.apache.wss4j.dom.message.WSSecUsernameToken;
import org.apache.xml.security.Init;
import org.apache.xml.security.algorithms.MessageDigestAlgorithm;
import org.w3c.dom.Document;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class WssDemo {

    static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/";
    static final String PASSWORD = "q1w2e3r4";

    public static void main(String[] args) throws Exception {
        Init.init(); // 初始化 Santuario 算法映射表,签名/加密均依赖
        Crypto clientCrypto = crypto("/root/keystores/client.jks", "JKS", null);
        Crypto trustCrypto = crypto("/root/keystores/trust.jks", "JKS", null);

        // 1) 构造 SOAP 报文
        Document doc = newSoapDoc();
        WSSecHeader secHeader = new WSSecHeader(doc);
        secHeader.insertSecurityHeader();

        // 2) 时间戳
        WSSecTimestamp ts = new WSSecTimestamp(secHeader);
        ts.setTimeToLive(300);
        ts.build();

        // 3) 摘要 UsernameToken
        WSSecUsernameToken ut = new WSSecUsernameToken(secHeader);
        ut.setUserInfo("alice", PASSWORD);
        ut.setPasswordType(WSConstants.PASSWORD_DIGEST);
        ut.addNonce();
        ut.addCreated();
        ut.build();

        // 4) 对 Body 签名(rsa-sha256 + sha256 摘要 + 独占 C14N,证书直附报文)
        WSSecSignature sign = new WSSecSignature(secHeader);
        sign.setUserInfo("client", PASSWORD);
        sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
        sign.setSignatureAlgorithm(WSConstants.RSA_SHA256);
        sign.setDigestAlgo(MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
        sign.setSigCanonicalization(WSConstants.C14N_EXCL_OMIT_COMMENTS);
        sign.prepare(clientCrypto);
        List<WSEncryptionPart> parts = new ArrayList<>();
        parts.add(new WSEncryptionPart("Body", SOAP_NS, "Content"));
        sign.computeSignature(sign.addReferencesToSign(parts));
        sign.prependBSTElementToHeader();

        // 5) 验证侧:WSSecurityEngine 处理签名 + 时间戳 + UsernameToken
        WSSecurityEngine engine = new WSSecurityEngine();
        RequestData reqData = new RequestData();
        reqData.setSigVerCrypto(trustCrypto);
        reqData.setCallbackHandler(callbacks -> {
            for (Callback cb : callbacks) {
                if (cb instanceof WSPasswordCallback) {
                    ((WSPasswordCallback) cb).setPassword(PASSWORD);
                } else {
                    throw new UnsupportedCallbackException(cb);
                }
            }
        });
        WSHandlerResult result = engine.processSecurityHeader(doc, reqData);

        List<String> actions = new ArrayList<>();
        for (WSSecurityEngineResult r : result.getResults()) {
            int a = (Integer) r.get(WSSecurityEngineResult.TAG_ACTION);
            actions.add(a == WSConstants.SIGN ? "SIGN" : a == WSConstants.UT ? "UT"
                    : a == WSConstants.TS ? "TS" : a == WSConstants.BST ? "BST" : String.valueOf(a));
        }
        System.out.println("验证通过,处理到的安全动作 = " + actions);
    }

    static Crypto crypto(String file, String type, String provider) throws WSSecurityException {
        Properties p = new Properties();
        p.setProperty("org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin");
        p.setProperty("org.apache.wss4j.crypto.merlin.keystore.type", type);
        p.setProperty("org.apache.wss4j.crypto.merlin.keystore.file", file);
        p.setProperty("org.apache.wss4j.crypto.merlin.keystore.password", PASSWORD);
        if (provider != null) {
            p.setProperty("org.apache.wss4j.crypto.merlin.keystore.provider", provider);
        }
        return CryptoFactory.getInstance(p);
    }

    static Document newSoapDoc() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().newDocument();
        org.w3c.dom.Element envelope = doc.createElementNS(SOAP_NS, "soap:Envelope");
        envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", SOAP_NS);
        doc.appendChild(envelope);
        org.w3c.dom.Element body = doc.createElementNS(SOAP_NS, "soap:Body");
        envelope.appendChild(body);
        org.w3c.dom.Element payload = doc.createElementNS("http://demo.example/order", "ord:submitOrder");
        payload.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ord", "http://demo.example/order");
        payload.setTextContent("order-1001|item=SSD-2T|qty=3|amount=1299.00");
        body.appendChild(payload);
        return doc;
    }
}

代码说明:

  • Init.init() 必须最先调用:它初始化 Santuario 的 JCEMapper 算法映射表。实测漏掉它时加密会报 unsupported key transport encryption algorithm(排障见第 3 篇《Apache WSS4J 3.0.6 快速入门与集成示例》FAQ)。
  • 纯 DOM 路线:全程只用 org.w3c.dom.Document,不引入任何应用服务器或 Web 框架。
  • 回调返回口令 q1w2e3r4:验证侧 WSS4J 用它做 UsernameToken 摘要比对。

4.7 编译与运行验证

cd /root/wss4j-demo && mvn -q -B compile exec:java -Dexec.mainClass=demo.WssDemo
== UsernameToken + Timestamp + 签名 组合验证 ==
验证通过,处理到的安全动作 = [TS, UT, SIGN, BST]

结果解读:TS/UT/SIGN/BST 分别表示验证侧成功处理了时间戳、UsernameToken、XML 签名与直附证书(BinarySecurityToken)。签名值字节数实测为 256(RSA 2048 位)。这表示 WSS4J 3.0.6 已在 JDK 17 上完整可用。

💡 说明:本文所有验证基于纯 DOM 路线(org.w3c.dom.Document),无需部署到任何应用服务器即可运行;-Dexec.mainClass 方式适合命令行快速验证,正式工程建议写成单元测试。

五、方案 B:jar 直用(离线友好)

本节面向没有 Maven/构建体系的场景,直接用一组 jar 加 javac/java 完成编译运行,不依赖任何构建工具。

5.1 方案说明

WSS4J 3.0.6 的传递依赖共 36 个 jar,无法像单 jar 库那样「下载一个就能用」。实测可行做法:先在有网环境用 dependency:copy-dependencies 把全部依赖导出到一个目录,再把整个目录拷贝到离线服务器,编译运行时用 classpath 通配符 挂载。

5.2 导出依赖 jar 集合

在已装 Maven 的机器上(如 4.4 节工程内):

cd /root/wss4j-demo && mvn -q -B dependency:copy-dependencies -DoutputDirectory=/root/wss4j-libs
ls /root/wss4j-libs | wc -l
36

关键 jar 清单(实测):

ls /root/wss4j-libs | grep -E "wss4j|xmlsec|bcprov|guava|slf4j-api"
bcprov-jdk18on-1.82.jar
guava-33.7.1-jre.jar
slf4j-api-2.0.19.jar
wss4j-ws-security-common-3.0.6.jar
wss4j-ws-security-dom-3.0.6.jar
xmlsec-3.0.6.jar

5.3 javac 编译与 java 运行

把 4.6 节的 WssDemo.java 复制到独立目录(去掉 package demo; 行),用 jar 集合编译运行:

mkdir -p /root/jar-run/out && cd /root/jar-run
cp /root/wss4j-demo/src/main/java/demo/WssDemo.java .
sed -i "s|package demo;||" WssDemo.java
javac -encoding UTF-8 -cp "/root/wss4j-libs/*" -d out WssDemo.java

编译无输出即成功(-cp "/root/wss4j-libs/*" 的引号不能省,否则 shell 会展开通配符)。运行:

LANG=C.UTF-8 java -Dfile.encoding=UTF-8 -cp "out:/root/wss4j-libs/*" WssDemo
验证通过,处理到的安全动作 = [TS, UT, SIGN, BST]

验证点:java -cp 一行成功打印验证结果,且无 NoClassDefFoundError,说明 jar 直跑可用。若未把 slf4j-simple 一并放进 libs 目录,运行前会多一条 SLF4J(W): No SLF4J providers were found 警告,属正常(日志走 NOP 空实现,功能不受影响)。

5.4 单 jar 获取与校验(可选)

若只需要核对某个关键 jar 的完整性,可从 Maven 中央仓库直下并校验 sha1:

cd /root/jar-run && curl -sO --max-time 60 https://repo1.maven.org/maven2/org/apache/wss4j/wss4j-ws-security-dom/3.0.6/wss4j-ws-security-dom-3.0.6.jar
curl -sO --max-time 30 https://repo1.maven.org/maven2/org/apache/wss4j/wss4j-ws-security-dom/3.0.6/wss4j-ws-security-dom-3.0.6.jar.sha1
echo "期望: $(cat wss4j-ws-security-dom-3.0.6.jar.sha1)"
echo "实测: $(sha1sum wss4j-ws-security-dom-3.0.6.jar | awk '{print $1}')"
期望: 8e9f6ed34b7fcac4360694bc10be92e795637c2e
实测: 8e9f6ed34b7fcac4360694bc10be92e795637c2e

⚠️ 注意:sha1 不一致说明下载包损坏或被篡改,须删除后重新下载。主 jar 仅约 348 KB,签名/加密的真正实现分散在 wss4j-ws-security-common 与 xmlsec 中,单独拿主 jar 无法运行。

六、方案对比与选择建议

本节汇总两种方案的差异,给出选型建议。两种方案加载的是同一组 3.0.6 代码,差别仅在获取与装配方式。

维度方案 A:Maven 依赖方案 B:jar 直用
依赖解析自动(36 个 jar 全自动下载)手工导出/拷贝整个 libs 目录
是否联网首次构建需联网仅导出/校验时需要联网
版本管控pom 统一声明,可锁版本靠目录内 jar 文件名区分
升级成本改一个版本号重新构建重新导出并全量替换 libs 目录
适用场景常规工程开发、持续集成离线服务器、安全隔离网段、临时验证

选型建议:有构建体系一律选方案 A;内网隔离环境用方案 A 的机器导出 libs 目录后走方案 B 分发。两者可共存——开发期方案 A,交付期方案 B。

七、基础配置

本节说明 WSS4J 使用中真正需要设置的「配置」。它是库而非服务,没有独立配置文件,全部行为通过代码参数与 JVM 环境控制。

环境变量 JAVA_HOME(Maven 依赖它定位 JDK)。Ubuntu 22.04 下 apt 版 Maven 可自动定位(4.3 节 mvn -v 回显的 runtime 一行),无需手工设置;若要显式固定:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 && echo "JAVA_HOME=$JAVA_HOME"
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

逐项说明:

  • JAVA_HOME:Maven 定位 JDK 的优先来源。Ubuntu 官方源 Maven 自带兼容逻辑,实测留空即可;手工安装 JDK 或多版本切换时再显式导出。
  • 密钥库路径:本文用绝对路径 /root/keystores/*.jks|bcfks,生产环境建议集中到 /etc/yourapp/keys/ 并收紧目录权限(chmod 600)。
  • 代码级「参数」:签名算法(RSA-SHA256)、摘要算法(SHA-256)、规范化方式(独占 C14N)、加密算法(AES-128-GCM)、密钥传输(RSA-OAEP-MGF1P)、时间戳 TTL(300 秒)等均通过 API 入参控制,详见第 4 篇《Apache WSS4J 3.0.6 签名与加密 API 详解》。

八、验证清单

安装与配置完成后,按以下清单逐项核对(全部为本文实测项):

检查项预期(实测值)不符时排查
java -version17.0.20.1用 update-alternatives --config java 切 17
mvn -v 的 Java version 行17.0.20.1显式导出 JAVA_HOME
mvn dependency:tree 首行依赖wss4j-ws-security-dom:jar:3.0.6:compile检查 pom 坐标拼写与网络
ls /root/wss4j-libs | wc -l(方案 B)36重跑 dependency:copy-dependencies
keytool 生成 client.jks提示 Generating 2,048 bit RSA key pair确认口令与 -dname 参数完整
keytool 生成 server.bcfks同上确认 -providerpath 指向 bcprov jar
最小程序输出[TS, UT, SIGN, BST]见第 3 篇 FAQ(重点核对 Init.init())
运行中文输出无乱码LANG=C.UTF-8 + -Dfile.encoding=UTF-8

九、常见问题(FAQ)

Q1:运行报 No SLF4J providers were found 怎么办? 这不是错误。未提供 slf4j 绑定时 WSS4J 的日志走 NOP 空实现,功能完全正常。需要看日志就按 4.4 节加入 slf4j-simple:2.0.19(与传递的 slf4j-api 同版本)。

Q2:mvn compile 报 Source option 5 is no longer supported? Maven 3.6.3 默认绑定的 maven-compiler-plugin 3.1 不认识 maven.compiler.release 属性。修复:在 pom 的 <build><plugins> 中显式固定 maven-compiler-plugin 3.11.0(见 4.4 节)。

Q3:keytool 生成 BCFKS 报 Keystore format BCFKS not found? BCFKS 是 BouncyCastle 格式,keytool 找不到提供者。修复:命令加 -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath <bcprov jar 全路径>(见 4.5 节),bcprov jar 可从本地 Maven 仓库 ~/.m2/repository/org/bouncycastle/bcprov-jdk18on/ 取。

Q4:最小程序签名验证通过,但换成加密就报 unsupported key transport encryption algorithm? 大概率是程序没有在入口调用 org.apache.xml.security.Init.init()。该调用初始化算法 URI 到 JCE 名称的映射表,未初始化时 rsa-oaep-mgf1p 查不到映射。修复:main 方法第一行加 Init.init();(实测修复后加密解密回显一致)。详细排障见第 3 篇 FAQ。

Q5:WSS4J 3.0.6 能不能跑在 JDK 8 上? 不能。3.0.x 父 POM 实测基线为 JDK 11(javaVersion=11)。JDK 8 环境请用 2.4.x 线(2.4.4,基线 JDK 8),API 用法一致;两端 JDK 版本不同不影响互操作,安全算法双方都支持即可。

Q6:口令明文写在代码里安全吗? 不安全。本文为便于复现统一用 q1w2e3r4 演示。生产环境建议用环境变量或密钥管理服务注入,密钥库文件本身再套一层磁盘加密或最小权限。

十、卸载与清理

WSS4J 本身不产生系统级安装,卸载即移除依赖与本地文件。

移除验证工程、jar 集合与密钥库:

rm -rf /root/wss4j-demo /root/jar-run /root/wss4j-libs /root/keystores
ls /root/wss4j-demo 2>&1
ls: cannot access '/root/wss4j-demo': No such file or directory

移除 Maven 本地仓库中的 WSS4J 相关缓存(影响所有工程,慎用):

rm -rf $HOME/.m2/repository/org/apache/wss4j
rm -rf $HOME/.m2/repository/org/apache/santuario

卸载 JDK 与 Maven(仅当不再需要)。先以 -s 预演确认将删除的包,无误后去掉 -s 真正执行:

apt-get -s purge -y openjdk-17-jdk maven
# 输出节选(实测首尾)
The following packages will be REMOVED:
  maven* openjdk-17-jdk*

确认无误后真正卸载:

apt-get purge -y openjdk-17-jdk maven && apt-get autoremove -y

十一、参考链接

  1. Apache WSS4J 官方主页:https://ws.apache.org/wss4j/
  2. WSS4J 3.0.6 Maven 中央仓库坐标:https://repo1.maven.org/maven2/org/apache/wss4j/wss4j-ws-security-dom/
  3. WSS4J 源码仓库:https://github.com/apache/wss4j
  4. Apache Santuario(XML 安全引擎)官方主页:https://santuario.apache.org/
  5. WS-Security 标准规范(OASIS):https://docs.oasis-open.org/wss/v1.1/wss-v1.1-spec-os-SOAPMessageSecurity-01.htm
  6. OpenJDK 17 安装包(Ubuntu 官方源):apt-cache show openjdk-17-jdk