You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2012/01/12 15:17:36 UTC

svn commit: r1230560 - in /james/protocols/trunk: api/src/main/java/org/apache/james/protocols/api/ pop3/src/main/java/org/apache/james/protocols/pop3/ pop3/src/main/java/org/apache/james/protocols/pop3/core/ pop3/src/test/java/org/apache/james/protoco...

Author: norman
Date: Thu Jan 12 14:17:35 2012
New Revision: 1230560

URL: http://svn.apache.org/viewvc?rev=1230560&view=rev
Log:
Add support for APOP. See PROTOCOL-87

Added:
    james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java
Modified:
    james/protocols/trunk/api/src/main/java/org/apache/james/protocols/api/ProtocolConfigurationImpl.java
    james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3ProtocolHandlerChain.java
    james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java
    james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractPassCmdHandler.java
    james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java
    james/protocols/trunk/pop3/src/test/java/org/apache/james/protocols/pop3/POP3ServerTest.java

Modified: james/protocols/trunk/api/src/main/java/org/apache/james/protocols/api/ProtocolConfigurationImpl.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/api/src/main/java/org/apache/james/protocols/api/ProtocolConfigurationImpl.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/api/src/main/java/org/apache/james/protocols/api/ProtocolConfigurationImpl.java (original)
+++ james/protocols/trunk/api/src/main/java/org/apache/james/protocols/api/ProtocolConfigurationImpl.java Thu Jan 12 14:17:35 2012
@@ -19,6 +19,9 @@
 
 package org.apache.james.protocols.api;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 
 /**
  * Default implementation of a {@link ProtocolConfiguration} which allows to easily set the different configurations. 
@@ -31,14 +34,29 @@ public class ProtocolConfigurationImpl i
     
     private String greeting;
     private String softwareName = "JAMES Protocols Server";
-    private String helloName = "localhost";
+    private String helloName = null;
+    private static final String DEFAULT_HELLO_NAME;
+    
+    static {
+        String hName;
+        try {
+            hName = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+            hName = "localhost";
+        }
+        DEFAULT_HELLO_NAME = hName;
+    }
     
     /*
+     * 
      * (non-Javadoc)
      * 
      * @see org.apache.james.protocols.pop3.POP3Configuration#getHelloName()
      */
     public String getHelloName() {
+        if (helloName == null) {
+            return DEFAULT_HELLO_NAME;
+        }
         return helloName;
     }
     

Modified: james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3ProtocolHandlerChain.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3ProtocolHandlerChain.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3ProtocolHandlerChain.java (original)
+++ james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3ProtocolHandlerChain.java Thu Jan 12 14:17:35 2012
@@ -54,24 +54,28 @@ public class POP3ProtocolHandlerChain ex
     }
 
     /**
-     * The {@link AbstractPassCmdHandler} to use. If a <code>not null</code> {@link AbstractPassCmdHandler} is given, the {@link POP3ProtocolHandlerChain}
+     * The {@link AbstractPassCmdHandler}'s to use. If at least one {@link AbstractPassCmdHandler} is given, the {@link POP3ProtocolHandlerChain}
      * will add all default handlers
      * 
-     * @param passHandler
+     * @param authHandlers
      * @throws WiringException 
      */
-    public POP3ProtocolHandlerChain(AbstractPassCmdHandler passHandler) throws WiringException {
-        if (passHandler != null) {
-            addAll(initDefaultHandlers(passHandler));      
+    public POP3ProtocolHandlerChain(AbstractPassCmdHandler... authHandlers) throws WiringException {
+        if (authHandlers != null && authHandlers.length > 0) {
+            addAll(initDefaultHandlers(authHandlers));      
             wireExtensibleHandlers();
         }
     }
     
-    protected List<ProtocolHandler> initDefaultHandlers(AbstractPassCmdHandler passHandler) {
+    protected List<ProtocolHandler> initDefaultHandlers(AbstractPassCmdHandler... authHandlers) {
         List<ProtocolHandler> handlers = new ArrayList<ProtocolHandler>();
+        // add all pass handlers
+        for (AbstractPassCmdHandler handler: authHandlers) {
+            handlers.add(handler);
+        }
+        
         handlers.add(new CapaCmdHandler());
         handlers.add(new UserCmdHandler());
-        handlers.add(passHandler);
         handlers.add(new ListCmdHandler());
         handlers.add(new UidlCmdHandler());
         handlers.add(new RsetCmdHandler());

Modified: james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java (original)
+++ james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java Thu Jan 12 14:17:35 2012
@@ -30,6 +30,7 @@ public interface POP3Session extends Pro
 
     final static String UID_LIST = "UID_LIST";
     final static String DELETED_UID_LIST = "DELETED_UID_LIST";
+    final static String APOP_TIMESTAMP = "APOP_TIMESTAMP";
 
     // Authentication states for the POP3 interaction
     /** Waiting for user id */

Added: james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java?rev=1230560&view=auto
==============================================================================
--- james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java (added)
+++ james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java Thu Jan 12 14:17:35 2012
@@ -0,0 +1,103 @@
+/****************************************************************
+ * 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.james.protocols.pop3.core;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.james.protocols.api.ProtocolSession.State;
+import org.apache.james.protocols.api.Request;
+import org.apache.james.protocols.api.Response;
+import org.apache.james.protocols.pop3.POP3Response;
+import org.apache.james.protocols.pop3.POP3Session;
+import org.apache.james.protocols.pop3.mailbox.Mailbox;
+
+/**
+ * Handles the APOP command
+ * 
+ * @author Maurer
+ *
+ */
+public abstract class AbstractApopCmdHandler extends AbstractPassCmdHandler{
+
+    private static final Collection<String> COMMANDS = Collections.unmodifiableCollection(Arrays.asList("APOP"));
+    
+    @Override
+    public Response onCommand(POP3Session session, Request request) {
+        if (session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection) == null) {
+            // APOP timestamp was not found in the session so APOP is not supported
+            return POP3Response.ERR;
+        }
+        
+        String parameters = request.getArgument();
+        String parts[] = null;
+        boolean syntaxError = false;
+        if (parameters != null) {
+            parts = parameters.split(" ");
+            if (parts.length != 2) {
+                syntaxError = true;
+            }
+        } else {
+            syntaxError = true;
+        }
+        if (!syntaxError && session.getHandlerState() == POP3Session.AUTHENTICATION_READY) {
+
+            Response response = doAuth(session, parts[0], parts[1]);
+            
+            if (POP3Response.OK_RESPONSE.equals(response.getRetCode())) {
+                // the auth was successful so set the user
+                session.setUser(parts[0]);
+            }
+            return response;
+        } else {
+            session.setHandlerState(POP3Session.AUTHENTICATION_READY);
+            return AUTH_FAILED;
+        }
+
+    }
+
+    @Override
+    public Collection<String> getImplCommands() {
+        return COMMANDS;
+    }
+
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.protocols.pop3.core.AbstractPassCmdHandler#auth(org.apache.james.protocols.pop3.POP3Session, java.lang.String, java.lang.String)
+     */
+    protected final Mailbox auth(POP3Session session, String username, String password) throws Exception {
+        return auth(session, (String)session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection), username, password);
+    }
+
+
+    /**
+     * Authenticate a {@link POP3Session} and returns the {@link Mailbox} for it. If it can not get authenticated it will return <code>null</code>.
+     * 
+     * @param session
+     * @param apopTimestamp
+     * @param user
+     * @param digest
+     * @return mailbox
+     * @throws Exception
+     */
+    protected abstract Mailbox auth(POP3Session session, String apopTimestamp, String user, String digest) throws Exception;
+}

Modified: james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractPassCmdHandler.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractPassCmdHandler.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractPassCmdHandler.java (original)
+++ james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractPassCmdHandler.java Thu Jan 12 14:17:35 2012
@@ -36,7 +36,7 @@ import org.apache.james.protocols.pop3.m
 public abstract class AbstractPassCmdHandler extends RsetCmdHandler {
     private static final Collection<String> COMMANDS = Collections.unmodifiableCollection(Arrays.asList("PASS"));
     private static final Response UNEXPECTED_ERROR = new POP3Response(POP3Response.ERR_RESPONSE, "Unexpected error accessing mailbox").immutable();
-    private static final Response AUTH_FAILED = new POP3Response(POP3Response.ERR_RESPONSE, "Authentication failed.").immutable();
+    protected static final Response AUTH_FAILED = new POP3Response(POP3Response.ERR_RESPONSE, "Authentication failed.").immutable();
 
     /**
      * Handler method called upon receipt of a PASS command. Reads in and
@@ -44,33 +44,45 @@ public abstract class AbstractPassCmdHan
      */
     public Response onCommand(POP3Session session, Request request) {
         String parameters = request.getArgument();
-        POP3Response response = null;
         if (session.getHandlerState() == POP3Session.AUTHENTICATION_USERSET && parameters != null) {
-            String passArg = parameters;
-            try {
-                Mailbox mailbox = auth(session, passArg);
-                if (mailbox != null) {
-                    session.setUserMailbox(mailbox);
-                    stat(session);
-
-                    StringBuilder responseBuffer = new StringBuilder(64).append("Welcome ").append(session.getUser());
-                    response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString());
-                    session.setHandlerState(POP3Session.TRANSACTION);
-                } else {
-                    session.setHandlerState(POP3Session.AUTHENTICATION_READY);
-                    return AUTH_FAILED;
-                }
-            } catch (Exception e) {
-                session.getLogger().error("Unexpected error accessing mailbox for " + session.getUser(), e);
-                session.setHandlerState(POP3Session.AUTHENTICATION_READY);
-                return UNEXPECTED_ERROR;
-            }
+            return doAuth(session, session.getUser(), parameters);
         } else {
             session.setHandlerState(POP3Session.AUTHENTICATION_READY);
             return AUTH_FAILED;
         }
+    }
+    
+    
+    /**
+     * Authenticate a user and return the {@link Response}
+     * 
+     * @param session
+     * @param user
+     * @param pass
+     * @return response
+     */
+    protected final Response doAuth(POP3Session session, String user, String pass) {
+        try {
+            Mailbox mailbox = auth(session, user, pass);
 
-        return response;
+            if (mailbox != null) {
+                session.setUserMailbox(mailbox);
+                stat(session);
+
+                session.setHandlerState(POP3Session.TRANSACTION);
+                
+
+                StringBuilder responseBuffer = new StringBuilder(64).append("Welcome ").append(session.getUser());
+                return  new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString());
+            } else {
+                session.setHandlerState(POP3Session.AUTHENTICATION_READY);
+                return AUTH_FAILED;
+            }
+        } catch (Exception e) {
+            session.getLogger().error("Unexpected error accessing mailbox for " + session.getUser(), e);
+            session.setHandlerState(POP3Session.AUTHENTICATION_READY);
+            return UNEXPECTED_ERROR;
+        }
     }
 
     /**
@@ -84,9 +96,10 @@ public abstract class AbstractPassCmdHan
      * Authenticate a {@link POP3Session} and returns the {@link Mailbox} for it. If it can not get authenticated it will return <code>null</code>.
      * 
      * @param session
+     * @param user
      * @param password
      * @return mailbox
      * 
      */
-    protected abstract Mailbox auth(POP3Session session, String password) throws Exception;
+    protected abstract Mailbox auth(POP3Session session, String username, String password) throws Exception;
 }

Modified: james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java (original)
+++ james/protocols/trunk/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java Thu Jan 12 14:17:35 2012
@@ -19,7 +19,7 @@
 
 package org.apache.james.protocols.pop3.core;
 
-
+import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.ConnectHandler;
 import org.apache.james.protocols.pop3.POP3Response;
@@ -33,11 +33,19 @@ public class WelcomeMessageHandler imple
      */
     public Response onConnect(POP3Session session) {
         StringBuilder responseBuffer = new StringBuilder();
-        // Initially greet the connector
-        // Format is: Sat, 24 Jan 1998 13:16:09 -0500
-        responseBuffer.append(session.getConfiguration().getHelloName()).append(" POP3 server (").append(session.getConfiguration().getSoftwareName()).append(") ready ");
+        
+        // Generate the timestamp which can be also used with APOP. See RFC1939 APOP
+        responseBuffer.append("<").append(session.getSessionID()).append(".").append(System.currentTimeMillis()).append("@").append(session.getConfiguration().getHelloName()).append("> ");
+        
+        // store the timestamp for later usage
+        session.setAttachment(POP3Session.APOP_TIMESTAMP, responseBuffer.toString(), State.Connection);
+        
+        // complete the response banner and send it back to the client
+        responseBuffer.append("POP3 server (").append(session.getConfiguration().getSoftwareName()).append(") ready ");
         POP3Response response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString());
         return response;
     }
     
+   
+    
 }

Modified: james/protocols/trunk/pop3/src/test/java/org/apache/james/protocols/pop3/POP3ServerTest.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/pop3/src/test/java/org/apache/james/protocols/pop3/POP3ServerTest.java?rev=1230560&r1=1230559&r2=1230560&view=diff
==============================================================================
--- james/protocols/trunk/pop3/src/test/java/org/apache/james/protocols/pop3/POP3ServerTest.java (original)
+++ james/protocols/trunk/pop3/src/test/java/org/apache/james/protocols/pop3/POP3ServerTest.java Thu Jan 12 14:17:35 2012
@@ -39,8 +39,10 @@ import java.util.concurrent.atomic.Atomi
 
 import org.apache.commons.net.pop3.POP3Client;
 import org.apache.commons.net.pop3.POP3MessageInfo;
+import org.apache.commons.net.pop3.POP3Reply;
 import org.apache.james.protocols.api.handler.WiringException;
 import org.apache.james.protocols.netty.NettyServer;
+import org.apache.james.protocols.pop3.core.AbstractApopCmdHandler;
 import org.apache.james.protocols.pop3.core.AbstractPassCmdHandler;
 import org.apache.james.protocols.pop3.mailbox.Mailbox;
 import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
@@ -462,6 +464,42 @@ public class POP3ServerTest {
         }
         
     }
+    
+    
+    @Test
+    public void testAPop() throws Exception {
+        InetSocketAddress address = new InetSocketAddress("127.0.0.1", TestUtils.getFreePort());
+        
+        NettyServer server = null;
+        try {
+            TestApopCmdHandler handler = new TestApopCmdHandler();
+            server = new NettyServer(createProtocol(handler));
+            server.setListenAddresses(address);
+            server.bind();
+            
+            POP3Client client =  new POP3Client();
+            client.connect(address.getAddress().getHostAddress(), address.getPort());
+            String welcomeMessage = client.getReplyString();
+            
+            // check for valid syntax that include all info needed for APOP
+            assertTrue(welcomeMessage.trim().matches("\\+OK \\<\\d+\\.\\d+@.+\\> .+"));
+            
+            int reply = client.sendCommand("APOP invalid invalid");
+            assertEquals(POP3Reply.ERROR, reply);
+            
+            handler.add("valid", new MockMailbox("id"));
+            reply = client.sendCommand("APOP valid valid");
+            assertEquals(POP3Reply.OK, reply);
+            
+            assertTrue(client.logout());
+           
+        } finally {
+            if (server != null) {
+                server.unbind();
+            }
+        }
+        
+    }
     private void checkMessage(Message message, Reader reader) throws IOException {
         int read = 0;
         int i = -1;
@@ -503,12 +541,26 @@ public class POP3ServerTest {
         public void add(String username, Mailbox mailbox) {
             mailboxes.put(username, mailbox);
         }
+        
+        protected Mailbox auth(POP3Session session, String username, String password) throws Exception{
+            return mailboxes.get(username);
+        }
 
-        @Override
-        protected Mailbox auth(POP3Session session, String password) {
-            return mailboxes.get(session.getUser());
+        
+    }
+    
+    private final class TestApopCmdHandler extends AbstractApopCmdHandler {
+        private final Map<String, Mailbox> mailboxes = new HashMap<String, Mailbox>();
+       
+        public void add(String username, Mailbox mailbox) {
+            mailboxes.put(username, mailbox);
         }
 
+        @Override
+        protected Mailbox auth(POP3Session session, String apopTimestamp, String user, String digest) throws Exception {
+            return mailboxes.get(user);
+        }
+        
         
     }
     



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org