harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lvj...@apache.org
Subject svn commit: r594819 - in /harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap: BindOp.java LdapClient.java LdapResult.java asn1/Utils.java sasl/ sasl/SaslBind.java
Date Wed, 14 Nov 2007 10:06:09 GMT
Author: lvjing
Date: Wed Nov 14 02:06:08 2007
New Revision: 594819

URL: http://svn.apache.org/viewvc?rev=594819&view=rev
Log:
add DEGIST-MD5, EXTERNAL and GSSAPI authentication mechanisms for SASL (according to Harmony-5072)

Added:
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/SaslBind.java
Modified:
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java?rev=594819&r1=594818&r2=594819&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java
Wed Nov 14 02:06:08 2007
@@ -25,66 +25,74 @@
 import org.apache.harmony.security.asn1.ASN1Integer;
 
 /**
- * Ldap Bind operation. Refer to
- * {@link http://www.rfc-editor.org/rfc/rfc2251.txt} for detailed information
- * 
+ * Ldap Bind operation
  */
-final public class BindOp implements LdapOperation, ASN1Encodable,
-        ASN1Decodable {
+public class BindOp implements LdapOperation {
 
-    private int version = DEFAULT_VERSION;
+    private String name;
 
-    private static final int DEFAULT_VERSION = 3;
+    private byte[] serverSaslCreds; // server's challenge
 
-    private String name;
+    private LdapResult result; // result from this Bind operation
 
-    private AuthenticationChoice authentication;
+    AuthenticationChoice authChoice;
 
-    final public static class SaslCredentials implements ASN1Encodable {
+    private class SaslCredentials implements ASN1Encodable {
 
         private String mechanism;
 
-        private String credentials;
+        private byte[] credentials;
+
+        public SaslCredentials(String mech, byte[] creds) {
+            this.mechanism = mech;
+            this.credentials = creds;
+        }
 
         public void encodeValues(Object[] values) {
             values[0] = Utils.getBytes(mechanism);
-            values[1] = Utils.getBytes(credentials);
+            values[1] = credentials;
         }
 
         public void setMechanism(String mechanism) {
             this.mechanism = mechanism;
         }
 
-        public void setCredentials(String credentials) {
+        public void setCredentials(byte[] credentials) {
             this.credentials = credentials;
         }
 
+        public byte[] getCredentials() {
+            return credentials;
+        }
+
     }
 
-    final public static class AuthenticationChoice implements ASN1Encodable {
+    private class AuthenticationChoice implements ASN1Encodable {
 
         public AuthenticationChoice(int index, SaslCredentials sasl) {
             this.index = index;
             this.sasl = sasl;
-            this.value = new Object[2];
-            sasl.encodeValues((Object[]) value);
         }
 
         public AuthenticationChoice(int index, String password) {
             this.index = index;
             this.password = password;
-            this.value = Utils.getBytes(this.password);
         }
 
         private int index;
 
-        private Object value;
-
         private SaslCredentials sasl;
 
         private String password;
 
         public void encodeValues(Object[] values) {
+            Object value;
+
+            if (index == 0) {
+                value = Utils.getBytes(password);
+            } else {
+                value = sasl;
+            }
             values[0] = new ChosenValue(index, value);
 
         }
@@ -93,48 +101,51 @@
             return index;
         }
 
-        public SaslCredentials getSasl() {
-            return sasl;
+        public byte[] getSaslCredentials() {
+            return sasl.getCredentials();
         }
 
-    }
-
-    private LdapResult result;
-
-    private byte[] response; // response from previous negotiation
+        public void setSaslCredentials(byte[] credentials) {
+            sasl.setCredentials(credentials);
+        }
 
-    public BindOp(int version, String dn) {
-        this.version = version;
-        this.name = dn;
-    }
-
-    public BindOp(String dn, String pwd) {
-        this.name = dn;
-        this.authentication = new AuthenticationChoice(0, pwd);
-        this.response = null;
     }
 
     public BindOp(String dn, String pwd, String saslMechanism, byte[] res) {
         this.name = dn;
-        SaslCredentials sasl = new SaslCredentials();
-        sasl.setMechanism(saslMechanism);
-        sasl.setCredentials(pwd);
-        this.authentication = new AuthenticationChoice(1, sasl);
-        this.response = res;
-    }
 
-    public LdapResult getResult() {
-        return result;
+        if (saslMechanism == null) {
+            authChoice = new AuthenticationChoice(0, pwd);
+        } else {
+            SaslCredentials saslCreds = new SaslCredentials(saslMechanism, res);
+            authChoice = new AuthenticationChoice(1, saslCreds);
+        }
     }
 
     public ASN1Encodable getRequest() {
-
-        return this;
+        return new ASN1Encodable() {
+            public void encodeValues(Object[] values) {
+                values[0] = ASN1Integer.fromIntValue(3);
+                values[1] = Utils.getBytes(name);
+                values[2] = authChoice;
+            }
+        };
     }
 
     public ASN1Decodable getResponse() {
 
-        return this;
+        return new ASN1Decodable() {
+            public void decodeValues(Object[] values) {
+                result = new LdapResult();
+                result.decodeValues(values);
+                if (values[4] != null) {
+                    serverSaslCreds = (byte[]) values[4];
+
+                }
+
+            }
+
+        };
     }
 
     public int getRequestId() {
@@ -145,21 +156,15 @@
         return LdapASN1Constant.OP_BIND_RESPONSE;
     }
 
-    public void encodeValues(Object[] values) {
-        values[0] = ASN1Integer.fromIntValue(version);
-        values[1] = Utils.getBytes(name);
-        Object[] auth = new Object[1];
-        // TODO: encoding AuthenticationChoice
-        authentication.encodeValues(auth);
-        values[2] = auth[0];
+    public void setSaslCredentials(byte[] credentials) {
+        authChoice.setSaslCredentials(credentials);
     }
 
-    public void decodeValues(Object[] values) {
-        result = new LdapResult();
-        result.decodeValues(values);
-        if (values[4] != null) {
-            authentication.getSasl().setCredentials(
-                    Utils.getString((byte[]) values[4]));
-        }
+    public LdapResult getResult() {
+        return result;
+    }
+
+    public byte[] getServerSaslCreds() {
+        return serverSaslCreds;
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java?rev=594819&r1=594818&r2=594819&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
Wed Nov 14 02:06:08 2007
@@ -58,6 +58,11 @@
      */
     private OutputStream out;
 
+    /*
+     * Address of connection
+     */
+    private String address;
+
     // constructor for test
     public LdapClient() {
         // do nothing
@@ -79,8 +84,12 @@
      */
     public LdapClient(SocketFactory factory, String address, int port)
             throws UnknownHostException, IOException {
+        this.address = address;
         socket = factory.createSocket(address, port);
-        in = socket.getInputStream();
+        // FIXME: Use of InputStreamWrap here is to deal with a potential bug of
+        // RI.
+        in = new InputStreamWrap(socket.getInputStream());
+        // in = socket.getInputStream();
         out = socket.getOutputStream();
     }
 
@@ -122,6 +131,7 @@
         out.flush();
         LdapMessage responseMsg = new LdapMessage(response);
         responseMsg.decode(in);
+
         if (opIndex == LdapASN1Constant.OP_SEARCH_REQUEST
                 && responseMsg.getOperationIndex() != LdapASN1Constant.OP_SEARCH_RESULT_DONE)
{
             responseMsg = new LdapMessage(response);
@@ -222,5 +232,77 @@
         }
 
         return cls;
+    }
+
+    // TODO: This class is used to deal with a potential bug of RI, may be
+    // removed in the future.
+    /**
+     * When use <code>InputStream</code> from SSL Socket, if invoke
+     * <code>InputStream.read(byte[])</code> with byte array of zero length,
+     * the method will be blocked. Seems it's bug of ri.
+     * 
+     * This wrap class delegate all request to wrapped instance, except
+     * returning immediately when the invoke
+     * <code>InputStream.read(byte[])</code> with byte array of zero length.
+     */
+    static class InputStreamWrap extends InputStream {
+        InputStream in;
+
+        public InputStreamWrap(InputStream in) {
+            this.in = in;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return in.read();
+        }
+
+        @Override
+        public int read(byte[] bs, int offset, int len) throws IOException {
+            if (len == 0) {
+                return 0;
+            }
+            return in.read(bs, offset, len);
+        }
+
+        @Override
+        public void reset() throws IOException {
+            in.reset();
+
+        }
+
+        @Override
+        public int available() throws IOException {
+            return in.available();
+        }
+
+        @Override
+        public void close() throws IOException {
+            in.close();
+        }
+
+        @Override
+        public void mark(int readlimit) {
+            in.mark(readlimit);
+        }
+
+        @Override
+        public boolean markSupported() {
+            return in.markSupported();
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return in.read(b);
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            return in.skip(n);
+        }
+    }
+
+    public String getAddress() {
+        return address;
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java?rev=594819&r1=594818&r2=594819&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java
Wed Nov 14 02:06:08 2007
@@ -27,6 +27,83 @@
  * This class represents LDAPResult defined in RFC 2251 page 16.
  */
 public class LdapResult implements ASN1Decodable {
+    public static final int SUCCESS = 0;
+
+    public static final int OPERATIONS_ERROR = 1;
+
+    public static final int PROTOCOL_ERROR = 2;
+
+    public static final int TIME_LIMIT_EXCEEDED = 3;
+
+    public static final int SIZE_LIMIT_EXCEEDED = 4;
+
+    public static final int COMPARE_FALSE = 5;
+
+    public static final int COMPARE_TRUE = 6;
+
+    public static final int AUTH_METHOD_NOT_SUPPORTED = 7;
+
+    public static final int STRONGER_AUTH_REQUIRED = 8;
+
+    public static final int REFERRAL = 10;
+
+    public static final int ADMIN_LIMIT_EXCEEDED = 11;
+
+    public static final int UNAVAILABLE_CRITICAL_EXTENSION = 12;
+
+    public static final int CONFIDENTIALITY_REQUIRED = 13;
+
+    public static final int SASL_BIND_IN_PROGRESS = 14;
+
+    public static final int NO_SUCH_ATTRIBUTE = 16;
+
+    public static final int UNDEFINED_ATTRIBUTE_TYPE = 17;
+
+    public static final int INAPPROPRIATE_MATCHING = 18;
+
+    public static final int CONSTRAINT_VIOLATION = 19;
+
+    public static final int ATTRIBUTE_OR_VALUE_EXISTS = 20;
+
+    public static final int INVALID_ATTRIBUTE_SYNTAX = 21;
+
+    public static final int NO_SUCH_OBJECT = 32;
+
+    public static final int ALIAS_PROBLEM = 33;
+
+    public static final int INVALID_DN_SYNTAX = 34;
+
+    public static final int ALIAS_DEREFERENCING_PROBLEM = 36;
+
+    public static final int INAPPROPRIATE_AUTHENTICATION = 48;
+
+    public static final int INVALID_CREDENTIALS = 49;
+
+    public static final int INSUFFICIENT_ACCESS_RIGHTS = 50;
+
+    public static final int BUSY = 51;
+
+    public static final int UNAVAILABLE = 52;
+
+    public static final int UNWILLING_TO_PERFORM = 53;
+
+    public static final int LOOP_DETECT = 54;
+
+    public static final int NAMING_VIOLATION = 64;
+
+    public static final int OBJECT_CLASS_VIOLATION = 65;
+
+    public static final int NOT_ALLOWED_ON_NON_LEAF = 66;
+
+    public static final int NOT_ALLOWED_ON_RDN = 67;
+
+    public static final int ENTRY_ALREADY_EXISTS = 68;
+
+    public static final int OBJECT_CLASS_MODS_PROHIBITED = 69;
+
+    public static final int AFFECTS_MULTIPLE_DSAS = 71;
+
+    public static final int OTHER = 80;
 
     private int resultCode;
 
@@ -66,10 +143,26 @@
      * Retrieves the referrals.
      * 
      * @return A prossibly null array. <code>null</code> means no referrals
-     *         retrieved from server
+     *         retrieves from server
      */
     public String[] getReferrals() {
         return referrals;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public void setMachedDN(String machedDN) {
+        this.machedDN = machedDN;
+    }
+
+    public void setReferrals(String[] referrals) {
+        this.referrals = referrals;
+    }
+
+    public void setResultCode(int resultCode) {
+        this.resultCode = resultCode;
     }
 
     public int getResultCode() {

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java?rev=594819&r1=594818&r2=594819&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
Wed Nov 14 02:06:08 2007
@@ -24,8 +24,8 @@
 
 public class Utils {
 
-    private static final String CODING_CHARSET = "UTF-8"; //$NON-NLS-1$
-    
+    public static final String CODING_CHARSET = "UTF-8"; //$NON-NLS-1$
+
     /**
      * conjoin two ASN1Sequence type as new one
      * 
@@ -65,36 +65,95 @@
     }
 
     /**
-     * Convert <code>bytes</code> to <code>String</code> using UTF-8
-     * charset. when <code>bytes</code> is <code>null</code>, empty
String
-     * will be returned.
+     * Convert <code>obj</code> to <code>String</code>. If obj is
byte[],
+     * then using UTF-8 charset. when <code>obj</code> is <code>null</code>,
+     * empty String would be returned.
      * 
-     * @param bytes
-     *            bytes to be decoded into a UTF-8 string
-     * @return UTF-8 String composed of bytes, never be empty string
+     * @param obj
+     *            object to be covert
+     * @return UTF-8 String
      */
-    public static String getString(byte[] bytes) {
-        try {
-            return (bytes == null) ? "" : new String(bytes, CODING_CHARSET); //$NON-NLS-1$
-        } catch (UnsupportedEncodingException e) {
-            // never reached, because UTF-8 is supported by all java platform
+    public static String getString(Object obj) {
+        if (obj == null) {
             return ""; //$NON-NLS-1$
         }
+
+        if (obj instanceof byte[]) {
+            try {
+                return new String((byte[]) obj, CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java
+                // platform
+                return ""; //$NON-NLS-1$
+            }
+        } else if (obj instanceof char[]) {
+            return new String((char[]) obj);
+        } else  {
+            return (String) obj;
+        }
+        
     }
 
     /**
-     * Encodes <code>s</code> into a sequence of bytes using UTF-8 charset.
+     * Encodes <code>obj</code> into a sequence of bytes using UTF-8 charset.
      * 
-     * @param s
-     *            String to be encoded
-     * @return UTF-8 String
+     * @param obj
+     *            object to be encoded
+     * @return UTF-8 byte[]
      */
-    public static byte[] getBytes(String s) {
-        try {
-            return (s == null) ? new byte[0] : s.getBytes(CODING_CHARSET);
-        } catch (UnsupportedEncodingException e) {
-            // never reached, because UTF-8 is supported by all java platform
+    public static byte[] getBytes(Object obj) {
+        if (obj == null) {
             return new byte[0];
+        }
+
+        if (obj instanceof String) {
+            try {
+                return ((String) obj).getBytes(CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java platform
+                return new byte[0];
+            }
+        } else if (obj instanceof char[]) {
+            try {
+                return new String((char[]) obj).getBytes(CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java platform
+                return new byte[0];
+            }
+        } else {
+            // no other types, ignore class cast expection
+            return (byte[]) obj;
+        }
+    }
+    
+
+    /**
+     * Convert <code>obj</code> to <code>char[]</code>. If obj is
byte[],
+     * then using UTF-8 charset. when <code>obj</code> is <code>null</code>,
+     * zero length char array would be returned.
+     * 
+     * @param obj
+     *            object to be covert
+     * @return UTF-8 char[]
+     */
+    public static char[] getCharArray(Object obj) {
+        if (obj == null) {
+            return new char[0];
+        }
+
+        if (obj instanceof String) {
+            return ((String) obj).toCharArray();
+        } else if (obj instanceof byte[]) {
+            try {
+                return new String((byte[]) obj, CODING_CHARSET).toCharArray();
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java
+                // platform
+                return new char[0];
+            }
+        } else {
+            // no other types, ignore class cast expection
+            return (char[]) obj;
         }
     }
 }

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/SaslBind.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/SaslBind.java?rev=594819&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/SaslBind.java
(added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/sasl/SaslBind.java
Wed Nov 14 02:06:08 2007
@@ -0,0 +1,294 @@
+package org.apache.harmony.jndi.provider.ldap.sasl;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.naming.AuthenticationNotSupportedException;
+import javax.naming.Context;
+import javax.naming.ldap.Control;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.RealmChoiceCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.apache.harmony.jndi.provider.ldap.BindOp;
+import org.apache.harmony.jndi.provider.ldap.LdapClient;
+import org.apache.harmony.jndi.provider.ldap.LdapResult;
+import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
+import org.apache.harmony.jndi.provider.ldap.parser.ParseException;
+
+/**
+ * A class used to perform SASL Bind Operation
+ */
+public class SaslBind {
+
+    // provider supported sasl mechanisms
+    public static final String DIGEST_MD5 = "DIGEST-MD5";
+
+    public static final String CRAM_MD5 = "CRAM-MD5";
+
+    public static final String GSSAPI = "GSSAPI";
+
+    public static final String EXTERNAL = "EXTERNAL";
+
+    private static Set<String> supportedSaslMechs = new HashSet<String>();
+
+    static {
+        supportedSaslMechs.add(DIGEST_MD5);
+        supportedSaslMechs.add(CRAM_MD5);
+        supportedSaslMechs.add(GSSAPI);
+        supportedSaslMechs.add(EXTERNAL);
+    }
+
+    public enum AuthMech {
+        None, Simple, SASL
+    };
+
+    private AuthMech authMech;
+
+    private String saslMech;
+
+    // -------------------------------------------------------------------
+    // Constructor
+    // -------------------------------------------------------------------
+
+    public SaslBind() {
+
+    }
+
+    // -------------------------------------------------------------------
+    // Methods
+    // -------------------------------------------------------------------
+
+    public AuthMech getAuthMech() {
+        return this.authMech;
+    }
+
+    /**
+     * Perform a LDAP SASL bind operation
+     * 
+     * @param env
+     * @throws IOException
+     * @throws AuthenticationNotSupportedException
+     * @return int result code of bind operation, see RFC4411. -1 means
+     *         authentication mechanisms in this binding operation is not SASL.
+     * @throws ParseException 
+     */
+    public LdapResult doSaslBindOperation(Hashtable env, LdapClient client, Control[] controls)
+            throws IOException, AuthenticationNotSupportedException {
+        // This method only deals with SASL bind. It will return
+        // immediatly if authentication mechanism is not SASL
+        externalValueAuthMech(env);
+        if (authMech == AuthMech.None || authMech == AuthMech.Simple) {
+            return null;
+        }
+
+        // Initial server name for SaslClient
+        String host = client.getAddress();
+
+        // Initial CallbackHandler for SaslClient
+        CallbackHandler cbh = (env.get("java.naming.security.sasl.callback") != null ? (CallbackHandler)
env
+                .get("java.naming.security.sasl.callback")
+                : new DefaultCallbackHandler(env));
+
+        // Initial authrization Id for SaslClient
+        String authorizationId = "";
+        if (env.get("java.naming.security.sasl.authorizationId") != null) {
+            authorizationId = (String) env
+                    .get("java.naming.security.sasl.authorizationId");
+        } else {
+            authorizationId = (String) env.get(Context.SECURITY_PRINCIPAL);
+        }
+
+        // Create SASL client to use for authentication
+        SaslClient saslClnt = Sasl.createSaslClient(new String[] { saslMech },
+                authorizationId, "ldap", host, env, cbh);
+
+        if (saslClnt == null) {
+            throw new SaslException("SASL client not available");
+        }
+
+        // If the specific mechanism needs initial response, get one
+        byte[] response = (saslClnt.hasInitialResponse() ? saslClnt
+                .evaluateChallenge(new byte[0]) : null);
+
+        // do bind operation, including the initial
+        // response (if any)
+        BindOp bind = new BindOp("", "", saslMech, response);
+        client.doOperation(bind, controls);
+        LdapResult res = bind.getResult();
+
+        // If DefaultCallbackHandler is used, DIGEST-MD5 needs realm in
+        // callbacke handler
+        if (DIGEST_MD5.equals(saslMech)
+                && cbh instanceof DefaultCallbackHandler) {
+            ((DefaultCallbackHandler) cbh).setRealm(getRealm(new String(bind
+                    .getServerSaslCreds())));
+        }
+
+        // Authentication done?
+        while (!saslClnt.isComplete()
+                && (res.getResultCode() == LdapResult.SASL_BIND_IN_PROGRESS || res
+                        .getResultCode() == LdapResult.SUCCESS)) {
+
+            // No, process challenge to get an appropriate next
+            // response
+            byte[] challenge = bind.getServerSaslCreds();
+            response = saslClnt.evaluateChallenge(challenge);
+
+            // May be a success message with no further response
+            if (res.getResultCode() == LdapResult.SUCCESS) {
+
+                if (response != null) {
+                    // Protocol error; supposed to be done already
+                    throw new SaslException("Protocol error in "
+                            + "SASL session");
+                }
+                System.out.println("success");
+                break; // done
+            }
+
+            // Wrap the response in another bind request and send
+            // it off
+            bind.setSaslCredentials(response);
+            client.doOperation(bind, controls);
+            res = bind.getResult();
+        }
+
+        return bind.getResult();
+    }
+
+    public AuthMech valueAuthMech(Hashtable env)
+            throws AuthenticationNotSupportedException {
+        return externalValueAuthMech(env);
+    }
+
+    private AuthMech externalValueAuthMech(Hashtable env)
+            throws AuthenticationNotSupportedException {
+        if (env == null) {
+            // FIXME: handle exception here?
+            return null;
+        }
+
+        if (env.get(Context.SECURITY_AUTHENTICATION) == null) {
+            if (env.get(Context.SECURITY_PRINCIPAL) == null) {
+                this.authMech = AuthMech.None;
+            } else {
+                this.authMech = AuthMech.Simple;
+            }
+        } else if (((String) env.get(Context.SECURITY_AUTHENTICATION))
+                .equalsIgnoreCase("none")) {
+            this.authMech = AuthMech.None;
+        } else if (((String) env.get(Context.SECURITY_AUTHENTICATION))
+                .equalsIgnoreCase("simple")) {
+            this.authMech = AuthMech.Simple;
+        } else if (valueSaslMech((String) env
+                .get(Context.SECURITY_AUTHENTICATION))) {
+            this.authMech = AuthMech.SASL;
+        } else {
+            throw new AuthenticationNotSupportedException((String) env
+                    .get(Context.SECURITY_AUTHENTICATION));
+        }
+
+        return this.authMech;
+    }
+
+    /**
+     * Value if those mechanisms in the string are supported
+     * 
+     * @param auth
+     *            a space separated string of sasl mechanisms
+     * @return
+     */
+    private boolean valueSaslMech(String auth) {
+        boolean flag = false;
+        String[] saslMechs = auth.trim().split(" ");
+
+        for (int i = 0; i < saslMechs.length; i++) {
+            if (saslMechs != null && saslMechs[i] != "") {
+                if (supportedSaslMechs.contains(saslMechs[i])) {
+                    flag = true;
+                    saslMech = saslMechs[i];
+                    break;
+                }
+            }
+        }
+        return flag;
+    }
+
+    private String getRealm(String creds) {
+        String[] credsProps = creds.split(",");
+        for (int i = 0; i < credsProps.length; i++) {
+            if (credsProps[i].startsWith("realm")) {
+                System.out.println(credsProps[i]);
+                String realm = credsProps[i].substring(7, credsProps[i]
+                        .length() - 1);
+                System.out.println(realm);
+                return realm;
+            }
+        }
+        return "";
+    }
+}
+
+/*
+ * Default callback handler, may be customized through
+ * "java.naming.security.sasl.realm".
+ */
+class DefaultCallbackHandler implements CallbackHandler {
+    
+    private static final String JAVA_NAMING_SECURITY_SASL_REALM = "java.naming.security.sasl.realm";
+
+    private Hashtable env;
+
+    private String realm = "";
+
+    public DefaultCallbackHandler() {
+
+    }
+
+    public DefaultCallbackHandler(Hashtable env) {
+        this.env = env;
+    }
+
+    public void handle(Callback[] callbacks) throws java.io.IOException,
+            UnsupportedCallbackException {
+        for (int i = 0; i < callbacks.length; i++) {
+            if (callbacks[i] instanceof RealmChoiceCallback) {
+                // TODO what to do here?
+                // RealmChoiceCallback rcc = (RealmChoiceCallback) callbacks[i];
+
+            } else if (callbacks[i] instanceof RealmCallback) {
+                RealmCallback rc = (RealmCallback) callbacks[i];
+                if (env.get(JAVA_NAMING_SECURITY_SASL_REALM) != null) {
+                    realm = (String) env.get(JAVA_NAMING_SECURITY_SASL_REALM);
+                    rc.setText(realm);
+                } else {
+                    rc.setText(realm);
+                }
+            } else if (callbacks[i] instanceof PasswordCallback) {
+                PasswordCallback pc = (PasswordCallback) callbacks[i];
+                pc.setPassword(Utils.getCharArray(env
+                        .get(Context.SECURITY_CREDENTIALS)));
+            } else if (callbacks[i] instanceof NameCallback) {
+                //authentication Id
+                NameCallback nc = (NameCallback) callbacks[i];
+                nc.setName((String) env.get(Context.SECURITY_PRINCIPAL));
+            } else {
+                throw new UnsupportedCallbackException(callbacks[i]);
+            }
+        }
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+}



Mime
View raw message