gecko-dev/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSaslBind.java

292 строки
12 KiB
Java

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.ldap.client.opers.*;
import netscape.ldap.ber.stream.*;
import netscape.ldap.util.*;
import java.io.*;
import java.net.*;
//import javax.security.auth.callback.CallbackHandler;
/**
* Authenticates to a server using SASL
*/
public class LDAPSaslBind implements LDAPBind, java.io.Serializable {
static final long serialVersionUID = -7615315715163655443L;
/**
* Construct an object which can authenticate to an LDAP server
* using the specified name and a specified SASL mechanism.
*
* @param dn if non-null and non-empty, specifies that the connection and
* all operations through it should authenticate with dn as the
* distinguished name
* @param mechanisms array of mechanism names, e.g. { "GSSAPI", "SKEY" }
* @param props optional additional properties of the desired
* authentication mechanism, e.g. minimum security level
* @param cbh a class which may be called by the SASL framework to
* obtain additional required information
*/
public LDAPSaslBind( String dn,
String[] mechanisms,
String packageName,
Hashtable props,
/*CallbackHandler*/ Object cbh ) {
_dn = dn;
_mechanisms = mechanisms;
_packageName = packageName;
_props = props;
_cbh = cbh;
// 12-01-99 Disabled check for instanceof CallbackHandler so that
// there is no dependency on the extenal jaas.jar package. This is
// reqired for Communicator build where the ldap java package does not
// include any sasl classes.
/*if ( (cbh != null) &&
!(cbh instanceof javax.security.auth.callback.CallbackHandler) ) {
throw new IllegalArgumentException(
"Callback argument must implement " +
"javax.security.auth.callback.CallbackHandler" );
}*/
}
/**
* Authenticates to the LDAP server (that the object is currently
* connected to) using the parameter that were provided to the
* constructor. If the requested SASL mechanism is not
* available, an exception is thrown. If the object has been
* disconnected from an LDAP server, this method attempts to reconnect
* to the server. If the object had already authenticated, the old
* authentication is discarded.
*
* @param ldc an active connection to a server, which will have
* the new authentication state on return from the method
* @exception LDAPException Failed to authenticate to the LDAP server.
*/
public void bind( LDAPConnection ldc ) throws LDAPException {
if ( _props == null ) {
_props = new Hashtable();
}
if ( (!_props.containsKey( CLIENTPKGS )) &&
(System.getProperty( CLIENTPKGS ) == null) ) {
_props.put( CLIENTPKGS, ldc.DEFAULT_SASL_PACKAGE );
}
_saslClient = getClient( ldc, _packageName );
if ( _saslClient != null ) {
bind( ldc, true );
return;
} else {
ldc.printDebug( "LDAPSaslBind.bind: getClient " +
"returned null" );
}
}
/**
* Get a SaslClient object from the Sasl framework
*
* @param ldc contains the host name
* @param packageName package containing a ClientFactory
* @return a SaslClient supporting one of the mechanisms
* of the member variable _mechanisms.
* @exception LDAPException on error producing a client
*/
private Object getClient( LDAPConnection ldc, String packageName )
throws LDAPException {
try {
Object[] args = new Object[6];
args[0] = _mechanisms;
args[1] = _dn;
args[2] = "ldap";
args[3] = ldc.getHost();
args[4] = _props;
args[5] = _cbh;
String[] argNames = new String[6];
argNames[0] = "[Ljava.lang.String;";
argNames[1] = "java.lang.String";
argNames[2] = "java.lang.String";
argNames[3] = "java.lang.String";
argNames[4] = "java.util.Hashtable";
argNames[5] = CALLBACK_HANDLER;
// Get a mechanism driver
return DynamicInvoker.invokeMethod(null,
packageName+".Sasl",
"createSaslClient",
args, argNames);
} catch (Exception e) {
ldc.printDebug( "LDAPSaslBind.getClient: " +
packageName+".Sasl.createSaslClient: " +
e );
throw new LDAPException(e.toString(), LDAPException.OTHER);
}
}
void bind(LDAPConnection ldc, boolean rebind)
throws LDAPException {
if ((ldc.isConnected() && rebind) ||
!ldc.isConnected()) {
try {
// Get the initial request to start authentication
String className = _saslClient.getClass().getName();
ldc.printDebug( "LDAPSaslBind.bind: calling " +
className+".createInitialResponse" );
byte[] outVals =
(byte[])DynamicInvoker.invokeMethod(
_saslClient,
className,
"createInitialResponse", null, null);
String mechanismName =
(String)DynamicInvoker.invokeMethod(
_saslClient,
className,
"getMechanismName", null, null);
ldc.printDebug( "LDAPSaslBind.bind: mechanism " +
"name is " +
mechanismName );
boolean isExternal = isExternalMechanism(mechanismName);
int resultCode = LDAPException.SASL_BIND_IN_PROGRESS;
JDAPBindResponse response = null;
while (!checkForSASLBindCompletion(resultCode)) {
ldc.printDebug( "LDAPSaslBind.bind: calling " +
"saslBind" );
response = saslBind(ldc, mechanismName, outVals);
resultCode = response.getResultCode();
ldc.printDebug( "LDAPSaslBind.bind: saslBind " +
"returned " + resultCode );
if (isExternal) {
continue;
}
byte[] b = response.getCredentials();
Object[] args = {b};
String[] argNames = {"[B"}; // class name for byte array
outVals =
(byte[])DynamicInvoker.invokeMethod(
_saslClient,
className, "evaluateChallenge",
args, argNames);
}
// Make sure authentication REALLY is complete
Boolean bool =
(Boolean)DynamicInvoker.invokeMethod(
_saslClient,
className, "isComplete", null, null);
if (!bool.booleanValue()) {
// Authentication session hijacked!
throw new LDAPException("The server indicates that " +
"authentication is successful" +
", but the SASL driver " +
"indicates that authentication" +
" is not yet done.",
LDAPException.OTHER);
}
Object[] args = {ldc.getInputStream()};
String[] argNames = {"java.io.InputStream"};
InputStream is =
(InputStream)DynamicInvoker.invokeMethod(
_saslClient,
className, "getInputStream", args, argNames);
ldc.setInputStream(is);
args[0] = ldc.getOutputStream();
argNames[0] = "java.io.OutputStream";
OutputStream os =
(OutputStream)DynamicInvoker.invokeMethod(
_saslClient,
className, "getOutputStream", args, argNames);
ldc.setOutputStream(os);
ldc.markConnAsBound();
} catch (LDAPException e) {
throw e;
} catch (Exception e) {
throw new LDAPException(e.toString(), LDAPException.OTHER);
}
}
}
boolean isExternalMechanism(String name) {
return name.equalsIgnoreCase( LDAPConnection.EXTERNAL_MECHANISM );
}
private boolean checkForSASLBindCompletion(int resultCode)
throws LDAPException{
if (resultCode == LDAPException.SUCCESS) {
return true;
} else if (resultCode == LDAPException.SASL_BIND_IN_PROGRESS) {
return false;
} else {
throw new LDAPException("Authentication failed", resultCode);
}
}
private JDAPBindResponse saslBind(LDAPConnection ldc,
String mechanismName,
byte[] credentials)
throws LDAPException {
LDAPResponseListener myListener = ldc.getResponseListener ();
try {
ldc.sendRequest(new JDAPBindRequest(3,
_dn,
mechanismName,
credentials),
myListener, ldc.getConstraints());
LDAPMessage response = myListener.getResponse();
JDAPProtocolOp protocolOp = response.getProtocolOp();
if (protocolOp instanceof JDAPBindResponse) {
return (JDAPBindResponse)protocolOp;
} else {
throw new LDAPException("Unknown response from the " +
"server during SASL bind",
LDAPException.OTHER);
}
} finally {
ldc.releaseResponseListener(myListener);
}
}
private static final String CALLBACK_HANDLER =
"javax.security.auth.callback.CallbackHandler";
private static final String CLIENTPKGS =
"javax.security.sasl.client.pkgs";
private String _dn;
private String[] _mechanisms;
private String _packageName;
private Hashtable _props;
private /*CallbackHandler*/ Object _cbh;
private Object _saslClient = null;
}