mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-04 14:52:24 -05:00
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:
parent
fe540492e7
commit
47f8ec7708
@ -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)
|
||||
*
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user