使用Java验证ADFS域账号凭据的技术实现问询
用Java验证ADFS 4.0(2016)域用户名/密码的轻量级方案
我懂你要的是什么——不用复杂的SAML SSO流程,不用做登录页面,就一个简单的服务来测试域账号密码对不对。刚好ADFS 4.0支持WS-Trust协议的用户名密码验证,这完全贴合你的需求,比折腾SAML简单太多了。下面给你一步步拆解实现:
1. 准备依赖
我们用Apache CXF来处理WS-Trust的底层交互,它封装了SOAP请求的细节,不用自己手写XML。在你的Maven pom.xml 里添加这些依赖:
<dependencies> <!-- CXF WS-Trust核心依赖 --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-security</artifactId> <version>3.6.2</version> <!-- 用最新稳定版即可 --> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-sts-client</artifactId> <version>3.6.2</version> </dependency> <!-- 日志依赖,方便调试问题 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>2.0.7</version> </dependency> </dependencies>
2. 从Federation Metadata提取WS-Trust端点
你手里的federationmetadata.xml URL包含了ADFS所有服务的端点信息,我们需要从中找到WS-Trust 13 Username/Mixed端点(通常路径是/adfs/services/trust/13/usernamemixed)。
可以用CXF的工具类自动加载元数据并提取端点:
import org.apache.cxf.sts.service.ServiceSTS; import org.apache.cxf.sts.service.ServiceSTS.WSTrust13; import org.springframework.core.io.UrlResource; import javax.xml.namespace.QName; import java.io.IOException; public class ADFSValidator { private static final String FED_METADATA_URL = "你的federationmetadata.xml完整URL"; private static final QName STS_SERVICE_QNAME = new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512", "SecurityTokenService"); public static String getWSTrustEndpoint() throws IOException { // 加载元数据资源 UrlResource metadataResource = new UrlResource(FED_METADATA_URL); ServiceSTS stsService = ServiceSTS.create(metadataResource.getInputStream()); // 提取Username/Mixed类型的WS-Trust端点 WSTrust13 trust13 = stsService.getWSTrust13(); return trust13.getEndpointReference().getAddress(); } }
3. 核心验证逻辑
用CXF的STSClient发送用户名密码请求:如果能成功获取到安全令牌,就说明凭据有效;反之则无效。
完整的验证方法示例:
import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.sts.request.SecurityTokenRequest; import org.apache.cxf.sts.request.SecurityTokenRequestType; import org.apache.cxf.ws.security.trust.STSClient; import org.apache.wss4j.common.ext.WSSecurityException; public class ADFSValidator { // ... 上面的getWSTrustEndpoint方法 ... public static boolean validateCredentials(String username, String password) { try { String stsEndpoint = getWSTrustEndpoint(); // 初始化STS客户端 STSClient stsClient = new STSClient(); stsClient.setWsdlLocation(stsEndpoint + "?wsdl"); stsClient.setServiceName(STS_SERVICE_QNAME); stsClient.setEndpointName(new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512", "UsernameMixed")); // 处理TLS证书(如果ADFS用自签证书,测试时可临时禁用CN校验,生产环境必须导入信任证书!) TLSClientParameters tlsParams = new TLSClientParameters(); tlsParams.setDisableCNCheck(true); // 仅测试用,生产环境务必删除此行 stsClient.setTlsClientParameters(tlsParams); // 设置待验证的用户名密码 stsClient.setUsername(username); stsClient.setPassword(password); // 发送令牌请求:只要不抛异常,就代表验证通过 SecurityTokenRequest request = new SecurityTokenRequest(); request.setRequestType(SecurityTokenRequestType.ISSUE); stsClient.requestSecurityToken(request); return true; } catch (WSSecurityException e) { // 凭据错误通常会抛出这个异常,比如InvalidSecurityToken System.err.println("凭据验证失败: " + e.getMessage()); return false; } catch (Exception e) { // 其他错误,比如网络问题、元数据加载失败 System.err.println("验证过程出错: " + e.getMessage()); return false; } } // 测试用主方法 public static void main(String[] args) { String username = "DOMAIN\\testuser"; // 支持DOMAIN\username或user@domain.com格式 String password = "testpassword"; boolean isValid = validateCredentials(username, password); System.out.println("凭据是否有效: " + isValid); } }
4. 关键注意事项
- ADFS配置检查:登录ADFS管理控制台,进入服务 > 端点,找到
WS-Trust 13 Username/Mixed,确认它处于启用状态。 - 证书信任问题:如果ADFS用的是自签SSL证书,需要把证书导入到Java的
cacerts信任库;测试时临时禁用CN校验的方式绝对不能用在生产环境。 - 用户名格式:ADFS支持
DOMAIN\username和username@domain.com两种格式,任选其一即可。
5. 常见错误排查
InvalidSecurityToken:用户名或密码错误,直接检查凭据即可。MessageAuthenticationFailed:ADFS不允许当前客户端的请求,需要检查ADFS的权限设置(比如是否允许外部客户端访问)。SSLHandshakeException:证书未被信任,检查证书是否正确导入到Java信任库。
内容的提问来源于stack exchange,提问作者Sebastião Burnay
相关产品推荐
相关产品推荐

