/** * Authenticate to the IMAP server by sending the AUTHENTICATE command with the selected * mechanism, using the given username and the given password. * * <p> * * @return True if successfully completed, false if not. * @exception IOException If an I/O error occurs while either sending a command to the server or * receiving a reply from the server. * @exception NoSuchAlgorithmException If the CRAM hash algorithm cannot be instantiated by the * Java runtime system. * @exception InvalidKeyException If the CRAM hash algorithm failed to use the given password. * @exception InvalidKeySpecException If the CRAM hash algorithm failed to use the given password. */ public boolean auth(AuthenticatingIMAPClient.AUTH_METHOD method, String username, String password) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { if (!IMAPReply.isContinuation(sendCommand(IMAPCommand.AUTHENTICATE, method.getAuthName()))) { return false; } switch (method) { case PLAIN: { // the server sends an empty response ("+ "), so we don't have to read it. int result = sendData( new String( Base64.encodeBase64(("\000" + username + "\000" + password).getBytes()))); if (result == IMAPReply.OK) { setState(IMAP.IMAPState.AUTH_STATE); } return result == IMAPReply.OK; } case CRAM_MD5: { // get the CRAM challenge (after "+ ") byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(2).trim()); // get the Mac instance Mac hmac_md5 = Mac.getInstance("HmacMD5"); hmac_md5.init(new SecretKeySpec(password.getBytes(), "HmacMD5")); // compute the result: byte[] hmacResult = _convertToHexString(hmac_md5.doFinal(serverChallenge)).getBytes(); // join the byte arrays to form the reply byte[] usernameBytes = username.getBytes(); byte[] toEncode = new byte[usernameBytes.length + 1 /* the space */ + hmacResult.length]; System.arraycopy(usernameBytes, 0, toEncode, 0, usernameBytes.length); toEncode[usernameBytes.length] = ' '; System.arraycopy(hmacResult, 0, toEncode, usernameBytes.length + 1, hmacResult.length); // send the reply and read the server code: int result = sendData(new String(Base64.encodeBase64(toEncode))); if (result == IMAPReply.OK) { setState(IMAP.IMAPState.AUTH_STATE); } return result == IMAPReply.OK; } case LOGIN: { // the server sends fixed responses (base64("Username") and // base64("Password")), so we don't have to read them. if (sendData(new String(Base64.encodeBase64(username.getBytes()))) != IMAPReply.CONT) { return false; } int result = sendData(new String(Base64.encodeBase64(password.getBytes()))); if (result == IMAPReply.OK) { setState(IMAP.IMAPState.AUTH_STATE); } return result == IMAPReply.OK; } } return false; // safety check }
/** * Encode a password as a base64-encoded char[] array. * * @param password as a byte array. * @return password as a char array. */ static char[] encodePassword(byte[] password) { return new String(Base64.encodeBase64(password)).toCharArray(); }
/** * Encode a byte[] identifier as a Base64-encoded string. * * @param identifier identifier to encode * @return Base64-encoded string */ static String encodeIdentifier(byte[] identifier) { return new String(Base64.encodeBase64(identifier)); }
/** * Encode a byte[] identifier as a Base64-encoded string. * * @param identifier identifier to encode * @return Base64-encoded string */ static String encodeIdentifier(byte[] identifier) { return new String(Base64.encodeBase64(identifier), Charset.defaultCharset()); }