You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2011/03/02 21:40:37 UTC
svn commit: r1076369 - in /commons/proper/net/trunk/src: changes/changes.xml
main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java
main/java/org/apache/commons/net/pop3/POP3.java
main/java/org/apache/commons/net/pop3/POP3Reply.java
Author: sebb
Date: Wed Mar 2 20:40:36 2011
New Revision: 1076369
URL: http://svn.apache.org/viewvc?rev=1076369&view=rev
Log:
NET-352 SASL PLAIN & CRAM-MD5 authentication
Added:
commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java (with props)
Modified:
commons/proper/net/trunk/src/changes/changes.xml
commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3.java
commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3Reply.java
Modified: commons/proper/net/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/changes/changes.xml?rev=1076369&r1=1076368&r2=1076369&view=diff
==============================================================================
--- commons/proper/net/trunk/src/changes/changes.xml (original)
+++ commons/proper/net/trunk/src/changes/changes.xml Wed Mar 2 20:40:36 2011
@@ -54,6 +54,9 @@ The <action> type attribute can be add,u
<body>
<release version="3.0" date="TBA" description="TBA">
+ <action issue="NET-352" dev="sebb" type="add" due-to="Bogdan Drozdowski" due-to-email="bogdandr # op . pl">
+ SASL PLAIN & CRAM-MD5 authentication.
+ </action>
<action issue="NET-357" dev="sebb" type="add" due-to="Bogdan Drozdowski" due-to-email="bogdandr # op . pl">
The POP3 client does not support SSL/TLS connections.
</action>
Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java?rev=1076369&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java Wed Mar 2 20:40:36 2011
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.pop3;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.net.pop3.POP3Client;
+import org.apache.commons.net.pop3.POP3Reply;
+import org.apache.commons.net.util.Base64;
+
+
+/**
+ * A POP3 Cilent class with protocol and authentication extensions support
+ * (RFC2449 and RFC2195).
+ * @see POP3Client
+ */
+public class ExtendedPOP3Client extends POP3SClient
+{
+ /** The CAPA command. */
+ public static final String capaCommand = "CAPA";
+ /** The AUTH command. */
+ public static final String authCommand = "AUTH";
+
+ /**
+ * The default ExtendedPOP3Client constructor.
+ * Creates a new Extended POP3 Client.
+ * @throws NoSuchAlgorithmException
+ */
+ public ExtendedPOP3Client() throws NoSuchAlgorithmException
+ {
+ super();
+ }
+
+ /***
+ * Send a CAPA command to the POP3 server.
+ * @return True if the command was successful, false if not.
+ * @exception IOException If a network I/O error occurs in the process of
+ * sending the NOOP command.
+ ***/
+ public boolean capa() throws IOException
+ {
+ return (sendCommand(capaCommand) == POP3Reply.OK);
+ }
+
+ /***
+ * Authenticate to the POP3 server by sending the AUTH 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(ExtendedPOP3Client.AUTH_METHOD method,
+ String username, String password)
+ throws IOException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidKeySpecException
+ {
+ if (sendCommand(authCommand + " " + AUTH_METHOD.getAuthName(method))
+ != POP3Reply.OK_INT) return false;
+
+ if (method.equals(AUTH_METHOD.PLAIN))
+ {
+ // the server sends an empty response ("+ "), so we don't have to read it.
+ return sendCommand(
+ new String(
+ Base64.encodeBase64(("\000" + username + "\000" + password).getBytes())
+ )
+ ) == POP3Reply.OK;
+ }
+ else if (method.equals(AUTH_METHOD.CRAM_MD5))
+ {
+ // get the CRAM challenge
+ 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:
+ return sendCommand(new String(Base64.encodeBase64(toEncode))) == POP3Reply.OK;
+ }
+ else return false; // safety check
+ }
+
+ /**
+ * Converts the given byte array to a String containing the hex values of the bytes.
+ * For example, the byte 'A' will be converted to '41', because this is the ASCII code
+ * (and the byte value) of the capital letter 'A'.
+ * @param a The byte array to convert.
+ * @return The resulting String of hex codes.
+ */
+ private String _convertToHexString(byte[] a)
+ {
+ String result = "";
+ for (int i = 0; i < a.length; i++)
+ {
+ if ( (a[i] & 0x0FF) <= 15 ) result += "0";
+ result += Integer.toHexString(a[i] & 0x0FF);
+ }
+ return result;
+ }
+
+ /**
+ * The enumeration of currently-supported authentication methods.
+ */
+ public static enum AUTH_METHOD
+ {
+ /** The standarised (RFC4616) PLAIN method, which sends the password unencrypted (insecure). */
+ PLAIN("PLAIN"),
+
+ /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure). */
+ CRAM_MD5("CRAM_MD5");
+
+ private final String methodName;
+
+ AUTH_METHOD(String methodName){
+ this.methodName = methodName;
+ }
+ /**
+ * Gets the name of the given authentication method suitable for the server.
+ * @param method The authentication method to get the name for.
+ * @return The name of the given authentication method suitable for the server.
+ */
+ public static final String getAuthName(AUTH_METHOD method)
+ {
+ return method.methodName;
+ }
+ }
+}
Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/ExtendedPOP3Client.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3.java?rev=1076369&r1=1076368&r2=1076369&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3.java Wed Mar 2 20:40:36 2011
@@ -70,6 +70,8 @@ public class POP3 extends SocketClient
public static final int UPDATE_STATE = 2;
static final String _OK = "+OK";
+ // The reply indicating intermediate response to a command.
+ static final String _OK_INT = "+ ";
static final String _ERROR = "-ERR";
// We have to ensure that the protocol communication is in ASCII
@@ -121,6 +123,8 @@ public class POP3 extends SocketClient
_replyCode = POP3Reply.OK;
else if (line.startsWith(_ERROR))
_replyCode = POP3Reply.ERROR;
+ else if (line.startsWith(_OK_INT))
+ _replyCode = POP3Reply.OK_INT;
else
throw new
MalformedServerReplyException(
@@ -242,7 +246,7 @@ public class POP3 extends SocketClient
* <p>
* @param command The POP3 command to send.
* @param args The command arguments.
- * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
+ * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT).
***/
public int sendCommand(String command, String args) throws IOException
{
@@ -273,7 +277,7 @@ public class POP3 extends SocketClient
* reply code.
* <p>
* @param command The POP3 command to send.
- * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
+ * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT).
***/
public int sendCommand(String command) throws IOException
{
@@ -286,7 +290,7 @@ public class POP3 extends SocketClient
* @param command The POP3 command to send
* (one of the POP3Command constants).
* @param args The command arguments.
- * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
+ * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT).
***/
public int sendCommand(int command, String args) throws IOException
{
@@ -299,7 +303,7 @@ public class POP3 extends SocketClient
* <p>
* @param command The POP3 command to send
* (one of the POP3Command constants).
- * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
+ * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT).
***/
public int sendCommand(int command) throws IOException
{
Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3Reply.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3Reply.java?rev=1076369&r1=1076368&r2=1076369&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3Reply.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/pop3/POP3Reply.java Wed Mar 2 20:40:36 2011
@@ -32,6 +32,9 @@ public final class POP3Reply
/*** The reply code indicating failure of an operation. ***/
public static final int ERROR = 1;
+ /** The reply code indicating intermediate response to a command. */
+ public static final int OK_INT = 2;
+
// Cannot be instantiated.
private POP3Reply()
{}