LDAP: experimental SASL DIGEST-MD5 implementation for OSX Lion Directory Utility support

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1790 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2011-09-15 08:47:16 +00:00
parent fe540492e7
commit 47f8ec7708
2 changed files with 111 additions and 15 deletions

View File

@ -99,7 +99,7 @@ public final class ExchangeSessionFactory {
/**
* Create authenticated Exchange session
*
* @param baseUrl OWA base URL
* @param baseUrl OWA base URL
* @param userName user login
* @param password user password
* @return authenticated session
@ -256,6 +256,21 @@ public final class ExchangeSessionFactory {
}
}
/**
* Get user password from session pool for SASL authentication
*
* @param userName Exchange user name
* @return user password
*/
public static String getUserPassword(String userName) {
for (PoolKey poolKey : POOL_MAP.keySet()) {
if (poolKey.userName.equals(userName)) {
return poolKey.password;
}
}
return null;
}
/**
* Check if at least one network interface is up and active (i.e. has an address)
*

View File

@ -30,6 +30,10 @@ import davmail.exchange.ExchangeSessionFactory;
import davmail.ui.tray.DavGatewayTray;
import org.apache.log4j.Logger;
import javax.security.auth.callback.*;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslServer;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -299,6 +303,8 @@ public class LdapConnection extends AbstractConnection {
static final int LDAP_REP_SEARCH = 0x64;
static final int LDAP_REP_RESULT = 0x65;
static final int LDAP_SASL_BIND_IN_PROGRESS = 0x0E;
// LDAP return codes
static final int LDAP_OTHER = 80;
static final int LDAP_SUCCESS = 0;
@ -348,6 +354,11 @@ public class LdapConnection extends AbstractConnection {
}
}
/**
* Sasl server for DIGEST-MD5 authentication
*/
protected SaslServer saslServer;
/**
* raw connection inputStream
*/
@ -496,7 +507,10 @@ public class LdapConnection extends AbstractConnection {
DavGatewayTray.resetIcon();
}
protected static final byte[] EMPTY_BYTE_ARRAY= new byte[0];
protected void handleRequest(byte[] inbuf, int offset) throws IOException {
dumpBer(inbuf, offset);
BerDecoder reqBer = new BerDecoder(inbuf, 0, offset);
int currentMessageId = 0;
try {
@ -509,27 +523,94 @@ public class LdapConnection extends AbstractConnection {
ldapVersion = reqBer.parseInt();
userName = reqBer.parseString(isLdapV3());
if (reqBer.peekByte() == (Ber.ASN_CONTEXT | Ber.ASN_CONSTRUCTOR | 3)) {
// SASL authentication
reqBer.parseSeq(null);
// Get mechanism, usually DIGEST-MD5
String mechanism = reqBer.parseString(isLdapV3());
throw new IOException("Unsupported authentication mechanism: "+mechanism);
byte[] serverResponse;
CallbackHandler callbackHandler = new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
// look for username in callbacks
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
userName = ((NameCallback) callback).getDefaultName();
// get password from session pool
password = ExchangeSessionFactory.getUserPassword(userName);
}
}
// handle other callbacks
for (Callback callback:callbacks) {
if (callback instanceof AuthorizeCallback) {
((AuthorizeCallback)callback).setAuthorized(true);
} else if (callback instanceof PasswordCallback) {
if (password != null) {
((PasswordCallback)callback).setPassword(password.toCharArray());
}
}
}
}
};
int status;
if (reqBer.bytesLeft() > 0) {
if (saslServer != null) {
byte[] clientResponse = reqBer.parseOctetString(Ber.ASN_OCTET_STR, null);
serverResponse = saslServer.evaluateResponse(clientResponse);
status = LDAP_SUCCESS;
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_USER", currentMessageId, userName));
try {
session = ExchangeSessionFactory.getInstance(userName, password);
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_SUCCESS"));
} catch (IOException e) {
serverResponse = EMPTY_BYTE_ARRAY;
status = LDAP_INVALID_CREDENTIALS;
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_INVALID_CREDENTIALS"));
}
} else {
throw new IOException("Invalid authentication sequence");
}
} else {
Map<String, String> properties = new HashMap<String, String>();
properties.put("javax.security.sasl.qop", "auth,auth-int");
saslServer = Sasl.createSaslServer(mechanism, "ldap", InetAddress.getLocalHost().getHostName(), properties, callbackHandler);
serverResponse = saslServer.evaluateResponse(EMPTY_BYTE_ARRAY);
status = LDAP_SASL_BIND_IN_PROGRESS;
}
responseBer.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
responseBer.encodeInt(currentMessageId);
responseBer.beginSeq(LDAP_REP_BIND);
responseBer.encodeInt(status, LBER_ENUMERATED);
// server credentials
responseBer.encodeString("", isLdapV3());
responseBer.encodeString("", isLdapV3());
// challenge or response
responseBer.encodeOctetString(serverResponse, 0x87);
responseBer.endSeq();
responseBer.endSeq();
sendResponse();
} else {
password = reqBer.parseStringWithTag(Ber.ASN_CONTEXT, isLdapV3(), null);
}
if (userName.length() > 0 && password.length() > 0) {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_USER", currentMessageId, userName));
try {
session = ExchangeSessionFactory.getInstance(userName, password);
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_SUCCESS"));
if (userName.length() > 0 && password.length() > 0) {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_USER", currentMessageId, userName));
try {
session = ExchangeSessionFactory.getInstance(userName, password);
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_SUCCESS"));
sendClient(currentMessageId, LDAP_REP_BIND, LDAP_SUCCESS, "");
} catch (IOException e) {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_INVALID_CREDENTIALS"));
sendClient(currentMessageId, LDAP_REP_BIND, LDAP_INVALID_CREDENTIALS, "");
}
} else {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_ANONYMOUS", currentMessageId));
// anonymous bind
sendClient(currentMessageId, LDAP_REP_BIND, LDAP_SUCCESS, "");
} catch (IOException e) {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_INVALID_CREDENTIALS"));
sendClient(currentMessageId, LDAP_REP_BIND, LDAP_INVALID_CREDENTIALS, "");
}
} else {
DavGatewayTray.debug(new BundleMessage("LOG_LDAP_REQ_BIND_ANONYMOUS", currentMessageId));
// anonymous bind
sendClient(currentMessageId, LDAP_REP_BIND, LDAP_SUCCESS, "");
}
} else if (requestOperation == LDAP_REQ_UNBIND) {