commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1074025 - in /commons/proper/net/trunk/src: changes/changes.xml main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
Date Thu, 24 Feb 2011 02:37:25 GMT
Author: sebb
Date: Thu Feb 24 02:37:24 2011
New Revision: 1074025

URL: http://svn.apache.org/viewvc?rev=1074025&view=rev
Log:
NET-353 The SMTPClient does not support authentication.

Added:
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
  (with props)
Modified:
    commons/proper/net/trunk/src/changes/changes.xml

Modified: commons/proper/net/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/changes/changes.xml?rev=1074025&r1=1074024&r2=1074025&view=diff
==============================================================================
--- commons/proper/net/trunk/src/changes/changes.xml (original)
+++ commons/proper/net/trunk/src/changes/changes.xml Thu Feb 24 02:37:24 2011
@@ -53,6 +53,9 @@ The <action> type attribute can be add,u
 
     <body>
         <release version="2.3" date="TBA" description="TBA">
+            <action issue="NET-353" dev="sebb" type="add" due-to="Bogdan Drozdowski">
+            The SMTPClient does not support authentication.
+            </action>
             <action issue="NET-356" dev="sebb" type="add" due-to="Bogdan Drozdowski">
             The SMTP client does not support SSL/TLS connections.
             </action>

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java?rev=1074025&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
(added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
Thu Feb 24 02:37:24 2011
@@ -0,0 +1,261 @@
+/*
+ * 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.smtp;
+
+import java.io.IOException;
+import java.net.InetAddress;
+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.smtp.SMTPClient;
+import org.apache.commons.net.smtp.SMTPReply;
+import org.apache.commons.net.util.Base64;
+
+
+/**
+ * An SMTP Client class with authentication support (RFC4954).
+ * 
+ * @see SMTPClient
+ */
+public class AuthenticatingSMTPClient extends SMTPSClient
+{
+    /** The AUTH command. */
+    public static final String authCommand = "AUTH";
+    /** The EHLO command. */
+    public static final String ehloCommand = "EHLO";
+
+    /**
+     * The default AuthenticatingSMTPClient constructor.
+     * Creates a new Authenticating SMTP Client.
+     * @throws NoSuchAlgorithmException 
+     */
+    public AuthenticatingSMTPClient() throws NoSuchAlgorithmException
+    {
+        super();
+    }
+
+    /**
+     * Overloaded constructor that takes an encoding specification
+     * @param encoding The encoding to use
+     * @throws NoSuchAlgorithmException 
+     */
+    public AuthenticatingSMTPClient(String encoding) throws NoSuchAlgorithmException {
+        super(encoding);
+    }
+
+    /***
+     * A convenience method to send the ESMTP EHLO command to the server,
+     * receive the reply, and return the reply code.
+     * <p>
+     * @param hostname The hostname of the sender.
+     * @return The reply code received from the server.
+     * @exception SMTPConnectionClosedException
+     *      If the SMTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send SMTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @exception IOException  If an I/O error occurs while either sending the
+     *      command or receiving the server reply.
+     ***/
+    public int ehlo(String hostname) throws IOException
+    {
+        return sendCommand(ehloCommand, hostname);
+    }
+
+    /***
+     * Login to the ESMTP server by sending the EHLO command with the
+     * given hostname as an argument.  Before performing any mail commands,
+     * you must first login.
+     * <p>
+     * @param hostname  The hostname with which to greet the SMTP server.
+     * @return True if successfully completed, false if not.
+     * @exception SMTPConnectionClosedException
+     *      If the SMTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send SMTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @exception IOException  If an I/O error occurs while either sending a
+     *      command to the server or receiving a reply from the server.
+     ***/
+    public boolean elogin(String hostname) throws IOException
+    {
+        return SMTPReply.isPositiveCompletion(ehlo(hostname));
+    }
+
+
+    /***
+     * Login to the ESMTP server by sending the EHLO command with the
+     * client hostname as an argument.  Before performing any mail commands,
+     * you must first login.
+     * <p>
+     * @return True if successfully completed, false if not.
+     * @exception SMTPConnectionClosedException
+     *      If the SMTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send SMTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @exception IOException  If an I/O error occurs while either sending a
+     *      command to the server or receiving a reply from the server.
+     ***/
+    public boolean elogin() throws IOException
+    {
+        String name;
+        InetAddress host;
+
+        host = getLocalAddress();
+        name = host.getHostName();
+
+        if (name == null)
+            return false;
+
+        return SMTPReply.isPositiveCompletion(ehlo(name));
+    }
+
+    /***
+     * Returns the integer values of the enhanced reply code of the last SMTP reply.
+     * @return The integer values of the enhanced reply code of the last SMTP reply.
+     *  First digit is in the first array element.
+     ***/
+    public int[] getEnhancedReplyCode()
+    {
+        String reply = getReplyString().substring(4);
+        String[] parts = reply.substring(0, reply.indexOf(' ')).split ("\\.");
+        int[] res = new int[parts.length];
+        for (int i = 0; i < parts.length; i++)
+        {
+            res[i] = Integer.parseInt (parts[i]);
+        }
+        return res;
+    }
+
+    /***
+     * Authenticate to the SMTP 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 SMTPConnectionClosedException
+     *      If the SMTP server prematurely closes the connection as a result
+     *      of the client being idle or some other reason causing the server
+     *      to send SMTP reply code 421.  This exception may be caught either
+     *      as an IOException or independently as itself.
+     * @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(AuthenticatingSMTPClient.AUTH_METHOD method,
+                        String username, String password)
+                        throws IOException, NoSuchAlgorithmException,
+                        InvalidKeyException, InvalidKeySpecException
+    {
+        if (!SMTPReply.isPositiveIntermediate(sendCommand(
+            authCommand + " " + AUTH_METHOD.getAuthName(method)))) return false;
+
+        if (method.equals(AUTH_METHOD.PLAIN))
+        {
+            // the server sends an empty response ("334 "), so we don't have to read it.
+            return SMTPReply.isPositiveCompletion(sendCommand(
+                new String(
+                    Base64.encodeBase64(("\000" + username + "\000" + password).getBytes())
+                    )
+                ));
+        }
+        else if (method.equals(AUTH_METHOD.CRAM_MD5))
+        {
+            // get the CRAM challenge
+            byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(4).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 SMTPReply.isPositiveCompletion(sendCommand(
+                new String(Base64.encodeBase64(toEncode))));
+        }
+        else if (method.equals(AUTH_METHOD.LOGIN))
+        {
+            // the server sends fixed responses (base64("Username") and
+            // base64("Password")), so we don't have to read them.
+            if (!SMTPReply.isPositiveIntermediate(sendCommand(
+                new String(Base64.encodeBase64(username.getBytes()))))) return false;
+            return SMTPReply.isPositiveCompletion(sendCommand(
+                new String(Base64.encodeBase64(password.getBytes()))));
+        }
+        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,
+        /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure).
*/
+        CRAM_MD5,
+        /** The unstandarised Microsoft LOGIN method, which sends the password unencrypted
(insecure). */
+        LOGIN;
+
+        /**
+         * 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)
+        {
+            if (method.equals(AUTH_METHOD.PLAIN)) return "PLAIN";
+            else if (method.equals(AUTH_METHOD.CRAM_MD5)) return "CRAM-MD5";
+            else if (method.equals(AUTH_METHOD.LOGIN)) return "LOGIN";
+            else return null;
+        }
+    }
+}
+
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



Mime
View raw message