| | |
| | | /** The message digest engine that will be used to create the MD5 digests. */ |
| | | private MessageDigest md5Digest; |
| | | |
| | | /** |
| | | * The lock that will be used to provide threadsafe access to the message |
| | | * digest. |
| | | */ |
| | | /** The lock that will be used to provide threadsafe access to the message digest. */ |
| | | private Object digestLock; |
| | | |
| | | /** |
| | | * The random number generator that we will use to create the server challenge. |
| | | */ |
| | | /** The random number generator that we will use to create the server challenge. */ |
| | | private SecureRandom randomGenerator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this SASL mechanism handler. No initialization |
| | | * should be done in this method, as it should all be performed in the |
| | |
| | | super(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void initializeSASLMechanismHandler( |
| | | CramMD5SASLMechanismHandlerCfg configuration) |
| | |
| | | throw new InitializationException(message, e); |
| | | } |
| | | |
| | | |
| | | // Create and fill the iPad and oPad arrays. |
| | | iPad = new byte[HMAC_MD5_BLOCK_LENGTH]; |
| | | oPad = new byte[HMAC_MD5_BLOCK_LENGTH]; |
| | | Arrays.fill(iPad, CRAMMD5_IPAD_BYTE); |
| | | Arrays.fill(oPad, CRAMMD5_OPAD_BYTE); |
| | | |
| | | |
| | | // Get the identity mapper that should be used to find users. |
| | | DN identityMapperDN = configuration.getIdentityMapperDN(); |
| | | identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN); |
| | |
| | | DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_CRAM_MD5, this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void finalizeSASLMechanismHandler() |
| | | { |
| | |
| | | DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_CRAM_MD5); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void processSASLBind(BindOperation bindOperation) |
| | | { |
| | |
| | | return; |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then the client did provide credentials. First, |
| | | // make sure that we have a stored version of the credentials associated |
| | | // with the client connection. If not, then it likely means that the client |
| | |
| | | // Wipe out the stored challenge so it can't be used again. |
| | | clientConnection.setSASLAuthStateInfo(null); |
| | | |
| | | |
| | | // Now look at the client credentials and make sure that we can decode them. |
| | | // It should be a username followed by a space and a digest string. Since |
| | | // the username itself may contain spaces but the digest string may not, |
| | |
| | | String userName = credString.substring(0, spacePos); |
| | | String digest = credString.substring(spacePos+1); |
| | | |
| | | |
| | | // Look at the digest portion of the provided credentials. It must have a |
| | | // length of exactly 32 bytes and be comprised only of hex characters. |
| | | if (digest.length() != 2*MD5_DIGEST_LENGTH) |
| | |
| | | return; |
| | | } |
| | | |
| | | |
| | | // Get the user entry for the authentication ID. Allow for an |
| | | // authentication ID that is just a username (as per the CRAM-MD5 spec), but |
| | | // also allow a value in the authzid form specified in RFC 2829. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // At this point, we should have a user entry. If we don't then fail. |
| | | if (userEntry == null) |
| | | { |
| | |
| | | bindOperation.setSASLAuthUserEntry(userEntry); |
| | | } |
| | | |
| | | |
| | | // Get the clear-text passwords from the user entry, if there are any. |
| | | List<ByteString> clearPasswords; |
| | | try |
| | |
| | | return; |
| | | } |
| | | |
| | | |
| | | // Iterate through the clear-text values and see if any of them can be used |
| | | // in conjunction with the challenge to construct the provided digest. |
| | | boolean matchFound = false; |
| | |
| | | return; |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then the authentication was successful. |
| | | bindOperation.setResultCode(ResultCode.SUCCESS); |
| | | |
| | |
| | | bindOperation.setAuthenticationInfo(authInfo); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Generates the appropriate HMAC-MD5 digest for a CRAM-MD5 authentication |
| | | * with the given information. |
| | |
| | | byte[] p = password.toByteArray(); |
| | | byte[] c = challenge.toByteArray(); |
| | | |
| | | |
| | | // Grab a lock to protect the MD5 digest generation. |
| | | synchronized (digestLock) |
| | | { |
| | |
| | | p = md5Digest.digest(p); |
| | | } |
| | | |
| | | |
| | | // Create byte arrays with data needed for the hash generation. |
| | | byte[] iPadAndData = new byte[HMAC_MD5_BLOCK_LENGTH + c.length]; |
| | | System.arraycopy(iPad, 0, iPadAndData, 0, HMAC_MD5_BLOCK_LENGTH); |
| | |
| | | byte[] oPadAndHash = new byte[HMAC_MD5_BLOCK_LENGTH + MD5_DIGEST_LENGTH]; |
| | | System.arraycopy(oPad, 0, oPadAndHash, 0, HMAC_MD5_BLOCK_LENGTH); |
| | | |
| | | |
| | | // Iterate through the bytes in the key and XOR them with the iPad and |
| | | // oPad as appropriate. |
| | | for (int i=0; i < p.length; i++) |
| | |
| | | oPadAndHash[i] ^= p[i]; |
| | | } |
| | | |
| | | |
| | | // Copy an MD5 digest of the iPad-XORed key and the data into the array to |
| | | // be hashed. |
| | | System.arraycopy(md5Digest.digest(iPadAndData), 0, oPadAndHash, |
| | | HMAC_MD5_BLOCK_LENGTH, MD5_DIGEST_LENGTH); |
| | | |
| | | |
| | | // Return an MD5 digest of the resulting array. |
| | | return md5Digest.digest(oPadAndHash); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isPasswordBased(String mechanism) |
| | | { |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isSecure(String mechanism) |
| | | { |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationAcceptable( |
| | | SASLMechanismHandlerCfg configuration, |
| | |
| | | return isConfigurationChangeAcceptable(config, unacceptableReasons); |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationChangeAcceptable( |
| | | CramMD5SASLMechanismHandlerCfg configuration, |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | CramMD5SASLMechanismHandlerCfg configuration) |