WS-security で保護された SOAP サービス (Java) を 1 つ 1 つ終了します。もう一方の端は、SOAP サーバーのクライアントとして機能する HTTP サーバー (Java) です。
次の委任チェーンを持つユーザーにシングル サインオン (Negotiate/Kerberos を使用) を実装したいと考えています: ブラウザ >> HTTP サーバー >> SOAP サーバー
ブラウザ >> HTTP サーバーは問題なく動作しています (HTTP でネゴシエート)。
HTTP サーバーでユーザーになりすます、2 番目のホップ HTTP サーバー >> SOAP サーバーは、JNA を使用したいのでより困難であり、1 つのトークンを使用して認証を実行したい (ハンドシェークを回避する)。一方向認証しか必要ないため、可能であると思われます。
エンベロープで 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 の現在の設計は完全にステートレスであり、この方法で維持することが望まれます)。