Ubuntu 22.04 安装 Apache WSS4J 指南
在 Ubuntu 22.04 上从零安装 Apache WSS4J 3.0.6,覆盖 JDK 17 与 Maven 3.6.3 环境、Maven 坐标与 jar 直用两种方案、自签 JKS 与 BCFKS 密钥库生成、UsernameToken 签名加密最小验证与卸载清理,命令回显均实测通过。
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。
- 具有 root 或 sudo 权限的 Ubuntu 22.04 系统。
- 可访问 Ubuntu 官方软件源(
apt update能正常拉取索引)。 - 可访问 Maven 中央仓库
repo1.maven.org(本文实测网络直连可达)。 - 至少 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.x | 2.4.4 | JDK 8(maven.compiler.target=1.8) | org.apache.wss4j:wss4j-ws-security-dom:2.4.x | 遗留系统、只能给 JDK 8 的服务器 |
| 3.0.x(当前主线) | 3.0.6 | JDK 11(javaVersion=11) | org.apache.wss4j:wss4j-ws-security-dom:3.0.x | 绝大多数新项目,BouncyCastle 经传递依赖内置 |
| 4.0.x | 4.0.2 | JDK 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 WSS4J WS-Security 标准实现 纯 DOM API,可脱离应用框架独立使用;CXF 底层依赖 自研网关、深度定制安全处理流程 Apache CXF WS-Security Web 服务框架集成 在 WSS4J 之上做 handler 封装,配置驱动 已经使用 CXF/JAX-WS 的项目 Spring WS Security Spring 生态集成 基于 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 原生支持 特点 适用场景 JKS JDK 内置 是 老牌 Java 私有格式,生态最广 纯 Java 栈的默认选择 PKCS12 标准 是(JDK 9+ 默认) 通用跨语言标准 需与 OpenSSL 等互转 BCFKS BouncyCastle 需挂 provider BC 自有格式,支持非对称条目,可配合 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 -version | 17.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
十一、参考链接
- Apache WSS4J 官方主页:https://ws.apache.org/wss4j/
- WSS4J 3.0.6 Maven 中央仓库坐标:https://repo1.maven.org/maven2/org/apache/wss4j/wss4j-ws-security-dom/
- WSS4J 源码仓库:https://github.com/apache/wss4j
- Apache Santuario(XML 安全引擎)官方主页:https://santuario.apache.org/
- WS-Security 标准规范(OASIS):https://docs.oasis-open.org/wss/v1.1/wss-v1.1-spec-os-SOAPMessageSecurity-01.htm
- OpenJDK 17 安装包(Ubuntu 官方源):
apt-cache show openjdk-17-jdk