Java GSSException创建凭据
主要编辑:2015-05-27:在取得一定程度的成功后,我更新了我目前的困境,而不是留下一篇杂乱无章的文章……这篇文章真的需要一些提示——有点陷入困境 我正在Linux应用服务器(WebSphere)上运行一些代码,需要对配置为“集成身份验证”的IIS web服务进行身份验证,但在形成授权时遇到一些问题:协商令牌。 我还应该说,我需要将这个令牌放入随后构建的JAX-WSSOAP请求的HTTP头中。我知道我的SOAP请求本身是有效的,因为我们以前使用的是WS-Security用户名令牌配置文件,它工作得很好-尝试交换到kerberos被证明是困难的 我想我的问题是initSecContext。似乎在第一次调用时,上下文是以“某种”方式配置的,并且有一些返回的令牌数据,但是.isEstablished为false。我遇到的问题是将initSecContext调用放入一个循环中-当我这样做时,IIS似乎只是关闭了连接。有人能给我一些建议吗?我似乎采用了其他海报和Oracle示例使用的方法(尽管IBM/WebSphere示例只进行了一次initSecContext调用,并且没有检查。isEstablished,这在Oracle文档中对我来说很奇怪) 无论如何,我得到的错误如下(注意Ready:property似乎明确表示initSecContext需要循环——至少对我来说是这样) 我的代码如下Java GSSException创建凭据,java,kerberos,gssapi,Java,Kerberos,Gssapi,主要编辑:2015-05-27:在取得一定程度的成功后,我更新了我目前的困境,而不是留下一篇杂乱无章的文章……这篇文章真的需要一些提示——有点陷入困境 我正在Linux应用服务器(WebSphere)上运行一些代码,需要对配置为“集成身份验证”的IIS web服务进行身份验证,但在形成授权时遇到一些问题:协商令牌。 我还应该说,我需要将这个令牌放入随后构建的JAX-WSSOAP请求的HTTP头中。我知道我的SOAP请求本身是有效的,因为我们以前使用的是WS-Security用户名令牌配置文件,它
LoginContext lc = getLoginContext(contextName);
final Subject subject = lc.getSubject();
String b64Token = (String) Subject.doAs(subject, new PrivilegedExceptionAction() {
@Override
public Object run() throws PrivilegedActionException, GSSException {
// Create socket to server
Socket socket;
DataInputStream inStream = null;
DataOutputStream outStream = null;
try {
socket = new Socket("iishost.mycorp.com", 443);
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
System.out.println("Exception setting up server sockets: " + ex.getMessage());
}
GSSName gssName = manager.createName(userName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
GSSCredential.DEFAULT_LIFETIME,
KRB5_MECH_OID,
GSSCredential.INITIATE_ONLY);
gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
SPNEGO_MECH_OID,
GSSCredential.INITIATE_ONLY);
GSSName gssServerName = manager.createName(servicePrincipal, KERBEROS_V5_PRINCIPAL_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
SPNEGO_MECH_OID,
gssCred,
GSSContext.DEFAULT_LIFETIME);
clientContext.requestCredDeleg(true);
clientContext.requestMutualAuth(true);
byte[] token = new byte[0];
while (!clientContext.isEstablished()) {
try {
token = clientContext.initSecContext(token, 0, token.length);
// IF I LOOK AT token HERE THERE IS CERTAINLY TOKEN DATA THERE - .isEstablished IS STILL FALSE
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
// Check if we're done
if (!clientContext.isEstablished()) {
token = new byte[inStream.readInt()];
inStream.readFully(token);
}
} catch (IOException ex) {
// THIS EXCEPTION IS THROWN ON SECOND ITERATION - LOOKS LIKE IIS CLOSES THE CONNECTION
System.out.println("IOException during context establishment: " + ex.getMessage());
}
}
String b64Token = Base64.encode(token);
clientContext.dispose(); // I'm assuming this won't invalidate the token in some way as I need to use it later
return b64Token;
}
});
此文档告诉我不需要在initSecContext上循环,但是.isEstablished为我返回false:
Oracle文档告诉我应该:
我唯一犹豫不决的是,从Oracle文档来看,我似乎在启动应用程序对话,但我试图做的是只获取令牌&稍后在我的代码中,我将使用JAX-WS发布我的实际web服务调用(包括http头中的spnego/kerberos令牌)-这是我的问题的原因吗?只是一个更新。我现在已经开始工作了——我以前的代码基本上还可以——这只是我对如何将Kerberos令牌添加到JAX-WS请求的理解。事实证明,这只是将处理程序附加到bindingProvider的问题。然后,处理程序获取Kerberos令牌并将其添加到请求的头中-nice和easy 下面是我的工作处理程序,它被添加到通过调用
bindingProvider.getBinding().getHandlerChain()获得的处理程序链中。
公共类HTTPKerberosHandler实现SOAPHandler{
私有最终字符串contextName;
私有最终字符串服务主体;
专用静态Oid KRB5_MECH_Oid=null;
专用静态Oid SPNEGO_MECH_Oid=null;
私有静态Oid KERBEROS_V5_主体_NAME=null;
最后一个字符串className=this.getClass().getName();
静止的{
试一试{
KERBEROS_V5_PRINCIPAL_NAME=新Oid(“1.2.840.113554.1.2.2.1”);
KRB5_MECH_OID=新OID(“1.2.840.113554.1.2.2”);
SPNEGO_MECH_OID=新OID(“1.3.6.1.5.5.2”);
}捕获(最终GSEX){
System.out.println(“创建mechOid的异常:+ex.getMessage());
例如printStackTrace();
}
}
公共HTTPKerberosHandler(最终字符串contextName,最终字符串servicePrincipal){
this.contextName=contextName;
this.servicePrincipal=servicePrincipal;
}
@凌驾
公共集getHeaders(){
返回null;
}
@凌驾
公共布尔handleFault(SOAPMessageContext上下文){
返回false;
}
@凌驾
公共无效关闭(MessageContext上下文){
//不采取行动
}
@凌驾
公共布尔handleMessage(SOAPMessageContext上下文){
if(((布尔)context.get(SOAPMessageContext.MESSAGE\u出站\u属性))){
返回HandlerRequest(上下文);
}否则{
返回HandlerResponse(上下文);
}
}
私有布尔HandlerRequest(SOAPMessageContext上下文){
byte[]标记=getKerberosToken(contextName,servicePrincipal);
HashMap sendTransportHeaders=新HashMap();
sendTransportHeaders.put(“授权”、“协商”+Base64.encode(令牌));
put(com.ibm.websphere.webservices.Constants.REQUEST\u TRANSPORT\u属性,sendTransportHeader);
返回true;
}
私有布尔HandlerResponse(SOAPMessageContext上下文){
logger.logInformation(类名,“HandlerResponse”,“检测到入站响应”);
返回true;
}
公共字节[]getKerberosToken(最终字符串contextName,最终字符串servicePrincipal){
试一试{
LoginContext lc=getLoginContext(contextName);
最终主题=lc.getSubject();
byte[]标记=(byte[])Subject.doAs(Subject,新PrivilegedExceptionAction(){
@凌驾
public Object run()引发PrivilegedActionException,gssexException{
最终字符串methodName=“getKerberosToken/run”;
最终的GSSManager管理器=GSSManager.getInstance();
Set principals=subject.getPrincipals();
迭代器it=principals.Iterator();
字符串principalName=((Principal)it.next()).getName();
logger.logInformation(className,methodName,“使用主体:[“+principalName+”]”);
GSSName GSSName=manager.createName(principalName、GSSName.NT\u用户名、KRB5\u机械OID);
GSSCredential gssCred=manager.createCredential(gssName.canonicalize(KRB5_MECH_OID)),
GSSCredential.DEFAULT_生命周期,
KRB5_机械类,
GSSCredential.仅启动_);
gssCred.add(gssName,GSSCredential.unlimited_寿命,
GSSCrede
LoginContext lc = getLoginContext(contextName);
final Subject subject = lc.getSubject();
String b64Token = (String) Subject.doAs(subject, new PrivilegedExceptionAction() {
@Override
public Object run() throws PrivilegedActionException, GSSException {
// Create socket to server
Socket socket;
DataInputStream inStream = null;
DataOutputStream outStream = null;
try {
socket = new Socket("iishost.mycorp.com", 443);
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
System.out.println("Exception setting up server sockets: " + ex.getMessage());
}
GSSName gssName = manager.createName(userName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
GSSCredential.DEFAULT_LIFETIME,
KRB5_MECH_OID,
GSSCredential.INITIATE_ONLY);
gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
SPNEGO_MECH_OID,
GSSCredential.INITIATE_ONLY);
GSSName gssServerName = manager.createName(servicePrincipal, KERBEROS_V5_PRINCIPAL_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
SPNEGO_MECH_OID,
gssCred,
GSSContext.DEFAULT_LIFETIME);
clientContext.requestCredDeleg(true);
clientContext.requestMutualAuth(true);
byte[] token = new byte[0];
while (!clientContext.isEstablished()) {
try {
token = clientContext.initSecContext(token, 0, token.length);
// IF I LOOK AT token HERE THERE IS CERTAINLY TOKEN DATA THERE - .isEstablished IS STILL FALSE
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
// Check if we're done
if (!clientContext.isEstablished()) {
token = new byte[inStream.readInt()];
inStream.readFully(token);
}
} catch (IOException ex) {
// THIS EXCEPTION IS THROWN ON SECOND ITERATION - LOOKS LIKE IIS CLOSES THE CONNECTION
System.out.println("IOException during context establishment: " + ex.getMessage());
}
}
String b64Token = Base64.encode(token);
clientContext.dispose(); // I'm assuming this won't invalidate the token in some way as I need to use it later
return b64Token;
}
});
public class HTTPKerberosHandler implements SOAPHandler<SOAPMessageContext> {
private final String contextName;
private final String servicePrincipal;
private static Oid KRB5_MECH_OID = null;
private static Oid SPNEGO_MECH_OID = null;
private static Oid KERBEROS_V5_PRINCIPAL_NAME = null;
final String className = this.getClass().getName();
static {
try {
KERBEROS_V5_PRINCIPAL_NAME = new Oid("1.2.840.113554.1.2.2.1");
KRB5_MECH_OID = new Oid("1.2.840.113554.1.2.2");
SPNEGO_MECH_OID = new Oid("1.3.6.1.5.5.2");
} catch (final GSSException ex) {
System.out.println("Exception creating mechOid's: " + ex.getMessage());
ex.printStackTrace();
}
}
public HTTPKerberosHandler(final String contextName, final String servicePrincipal) {
this.contextName = contextName;
this.servicePrincipal = servicePrincipal;
}
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public void close(MessageContext context) {
// No action
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
if (((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY))) {
return handleRequest(context);
} else {
return handleResponse(context);
}
}
private boolean handleRequest(SOAPMessageContext context) {
byte[] token = getKerberosToken(contextName, servicePrincipal);
HashMap<String, String> sendTransportHeaders = new HashMap<String, String>();
sendTransportHeaders.put("Authorization", "Negotiate " + Base64.encode(token));
context.put(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES, sendTransportHeaders);
return true;
}
private boolean handleResponse(SOAPMessageContext context) {
logger.logInformation(className, "handleResponse", "Inbound response detected");
return true;
}
public byte[] getKerberosToken(final String contextName, final String servicePrincipal) {
try {
LoginContext lc = getLoginContext(contextName);
final Subject subject = lc.getSubject();
byte[] token = (byte[]) Subject.doAs(subject, new PrivilegedExceptionAction() {
@Override
public Object run() throws PrivilegedActionException, GSSException {
final String methodName = "getKerberosToken/run";
final GSSManager manager = GSSManager.getInstance();
Set<Principal> principals = subject.getPrincipals();
Iterator it = principals.iterator();
String principalName = ((Principal) it.next()).getName();
logger.logInformation(className, methodName, "Using principal: [" + principalName + "]");
GSSName gssName = manager.createName(principalName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
GSSCredential.DEFAULT_LIFETIME,
KRB5_MECH_OID,
GSSCredential.INITIATE_ONLY);
gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
SPNEGO_MECH_OID,
GSSCredential.INITIATE_ONLY);
logger.logInformation(className, methodName, "Client TGT obtained: " + gssCred.toString());
GSSName gssServerName = manager.createName(servicePrincipal, GSSName.NT_USER_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
SPNEGO_MECH_OID,
gssCred,
GSSContext.DEFAULT_LIFETIME);
logger.logInformation(className, methodName, "Service ticket obtained: " + clientContext.toString());
byte[] token = new byte[0];
token = clientContext.initSecContext(token, 0, token.length);
clientContext.dispose();
return token;
}
});
return token;
} catch (PrivilegedActionException ex) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "PrivilegedActionException: " + ex.getMessage());
} catch (Exception ex) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Exception: " + ex.getMessage());
}
return null;
}
private LoginContext getLoginContext(String contextName) {
LoginContext lc = null;
try {
lc = new LoginContext(contextName);
lc.login();
} catch (LoginException le) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Login exception: [" + le.getMessage() + "]");
le.printStackTrace();
}
return lc;
}
}