3

一对一结束受 WS-security 保护的 SOAP 服务 (Java)。另一端是充当 SOAP 服务器客户端的 HTTP 服务器 (Java)。

我想为具有以下委托链的用户实现单点登录(使用 Negotiate/Kerberos):浏览器 >> HTTP 服务器 >> SOAP 服务器

浏览器 >> HTTP 服务器没有问题并且可以正常工作(通过 HTTP 协商)。

在 HTTP 服务器上模拟用户,第二跳 HTTP 服务器 >> SOAP 服务器更具挑战性,因为我想使用 JNA,并且我还希望使用单个令牌执行身份验证(避免握手)。我读到它应该是可能的,因为我只需要一种方式身份验证。

在信封中将令牌从 HTTP 服务器传递到 SOAP 服务器也可以正常工作,在 SOAP 服务器端有一个拦截器。我唯一的问题是在调用 AcceptSecurityContext 时生成一个不会导致SEC_I_CONTINUE_NEEDED状态的有趣令牌。

获取 SOAP 服务令牌的客户端代码(JNA 由 Waffle 项目包装):

import sun.misc.BASE64Encoder;
import waffle.windows.auth.IWindowsSecurityContext;
import waffle.windows.auth.impl.WindowsSecurityContextImpl;

public class WindowsAuthenticator {

public static final String securityPackage = "Negotiate";

public static String getKrbToken(String targetSPN) {
    if (null == targetSPN || targetSPN.trim().isEmpty()) {
        return null;
    }
    IWindowsSecurityContext ctx = WindowsSecurityContextImpl.getCurrent(securityPackage, targetSPN);
    byte[] token = ctx.getToken();
    return new BASE64Encoder().encode(token);
}

private WindowsAuthenticator() {
    super();
}

}

用于验证 Kerberos 令牌的 SOAP 服务器代码

import org.apache.log4j.Logger;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.handler.RequestData;
import org.apache.ws.security.message.token.BinarySecurity;
import org.apache.ws.security.validate.Credential;
import org.apache.ws.security.validate.Validator;
import waffle.windows.auth.IWindowsAuthProvider;
import waffle.windows.auth.IWindowsIdentity;
import waffle.windows.auth.IWindowsSecurityContext;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;

public class KerberosTokenValidator implements Validator {

private static final Logger logger =      Logger.getLogger(KerberosTokenValidator.class);
private final IWindowsAuthProvider windowsAuthProvider;

public KerberosTokenValidator() {
    this.windowsAuthProvider = new WindowsAuthProviderImpl();
}

@Override
public Credential validate(Credential credential, RequestData data) throws     WSSecurityException {
    BinarySecurity token = credential.getBinarySecurityToken();
    byte[] binaryToken = token.getToken();
    String id = token.getID();
    String type = token.getValueType();
    final IWindowsSecurityContext securityContext;
    try {
        securityContext = this.windowsAuthProvider.acceptSecurityToken(id, binaryToken, "Negotiate");


        this.windowsAuthProvider.acceptSecurityToken(id, binaryToken, "Negotiate");

        final IWindowsIdentity windowsIdentity = securityContext.getIdentity();
        securityContext.dispose();

    } catch (Exception exception) {
        logger.warn("error logging in user: " + exception.getMessage());
        throw new WSSecurityException("Could not auth....");
    }

    return null;
}

}

问题是acceptSecurityToken返回一个SEC_I_CONTINUE_NEEDED并且我最终进行了握手(就像第一跳通过 HTTP 完成的那样)。在这里,我真的希望(如果可能的话)服务器对单个令牌感到满意(SOAP API 的当前设计是完全无状态的,希望以这种方式保持)。

4

0 回答 0