Author: norman
Date: Sun Sep 27 17:38:54 2009
New Revision: 819359
URL: http://svn.apache.org/viewvc?rev=819359&view=rev
Log:
First draft of generic STARTTLS support + SMTPServer STARTTLS support
(JAMES-290)
Added:
james/server/trunk/phoenix-deployment/src/main/
james/server/trunk/phoenix-deployment/src/main/config/
james/server/trunk/phoenix-deployment/src/main/java/
james/server/trunk/phoenix-deployment/src/main/resources/
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/StartTlsCmdHandler.java
james/server/trunk/smtpserver-function/src/test/resources/test_keystore
(with props)
Modified:
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractProtocolServer.java
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/JamesConnectionBridge.java
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/ProtocolContext.java
james/server/trunk/phoenix-deployment/src/conf/james-config.xml
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPConfiguration.java
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/BaseFakeSMTPSession.java
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
Modified:
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractProtocolServer.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractProtocolServer.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractProtocolServer.java
(original)
+++
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractProtocolServer.java
Sun Sep 27 17:38:54 2009
@@ -25,11 +25,15 @@
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
+import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PostConstruct;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
import
org.apache.avalon.cornerstone.services.connection.AbstractHandlerFactory;
import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
@@ -53,6 +57,7 @@
import org.apache.avalon.framework.service.Serviceable;
import org.apache.excalibur.thread.ThreadPool;
import org.apache.james.api.dnsservice.DNSService;
+import org.apache.james.services.FileSystem;
/**
* Server which creates connection handlers. All new James service must
@@ -199,8 +204,14 @@
*/
private String streamDumpDir = null;
-
-
+ private FileSystem fSystem;
+ private SSLSocketFactory factory;
+
+ private String keystore;
+
+ private String secret;
+
+ private boolean useStartTLS;
/**
* Gets the DNS Service.
* @return the dnsServer
@@ -221,6 +232,10 @@
this.connectionManager = connectionManager;
}
+ public void setFileSystem(FileSystem fSystem) {
+ this.fSystem = fSystem;
+ }
+
/**
* @see
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
*/
@@ -231,6 +246,7 @@
(JamesConnectionManager)componentManager.lookup(JamesConnectionManager.ROLE);
setConnectionManager(connectionManager);
dnsService = (DNSService) comp.lookup(DNSService.ROLE);
+ fSystem= (FileSystem) comp.lookup(FileSystem.ROLE);
}
/**
@@ -282,6 +298,7 @@
} else {
serverSocketType = confSocketType;
}
+
StringBuilder infoBuffer;
threadGroup = conf.getChild("threadGroup").getValue(null);
@@ -376,6 +393,20 @@
.append(" per IP connections for " +getServiceType());
logger.info(infoBuffer.toString());
+ Configuration tlsConfig = conf.getChild("startTLS");
+ if (tlsConfig != null) {
+ useStartTLS = tlsConfig.getAttributeAsBoolean("enable",
false);
+ System.err.println("config=" + useStartTLS);
+
+ if (useStartTLS) {
+ keystore =
tlsConfig.getChild("keystore").getValue(null);
+ if (keystore == null) {
+ throw new
ConfigurationException("keystore needs to get configured");
+ }
+ secret =
tlsConfig.getChild("secret").getValue("");
+ loadJCEProviders(conf, getLogger());
+ }
+ }
}
private void loadJCEProviders(Configuration conf, final Logger logger)
throws ConfigurationException {
@@ -479,7 +510,7 @@
// keeping these looked up services locally, because they are only
needed beyond initialization
ThreadManager threadManager = (ThreadManager)
componentManager.lookup(ThreadManager.ROLE);
SocketManager socketManager = (SocketManager)
componentManager.lookup(SocketManager.ROLE);
-
+
initializeThreadPool(threadManager);
initializeServerSocket(socketManager);
@@ -494,10 +525,48 @@
theWatchdogFactory = getWatchdogFactory();
+ if (useStartTLS) {
+ initStartTLS();
+ }
// Allow subclasses to perform initialisation
doInit();
}
+ private void initStartTLS() throws Exception {
+ KeyStore ks = null;
+ KeyManagerFactory kmf = null;
+ SSLContext sslcontext = null;
+
+ // This loads the key material, and initialises the
+ // SSLSocketFactory
+ // This should be done once!!
+ // Note: in order to load SunJCE provider the jre/lib/ext
should be
+ // added
+ // to the java.ext.dirs see the note in run.sh script
+ try {
+ // just to see SunJCE is loaded
+ Provider[] provs = Security.getProviders();
+ for (int i = 0; i < provs.length; i++)
+ getLogger().debug("Provider[" + i + "]=" +
provs[i].getName());
+
+ char[] passphrase = secret.toCharArray();
+ ks = KeyStore.getInstance("JKS");
+ ks.load(fSystem.getResource(keystore), passphrase);
+ kmf = KeyManagerFactory.getInstance("SunX509",
"SunJSSE");
+ kmf.init(ks, passphrase);
+ sslcontext = SSLContext.getInstance("TLS", "SunJSSE");
+ sslcontext.init(kmf.getKeyManagers(), null, null);
+ } catch (Exception e) {
+ getLogger().error("Exception accessing keystore: " + e);
+ throw e;
+ }
+ factory = sslcontext.getSocketFactory();
+ // just to see the list of supported ciphers
+ String[] ss = factory.getSupportedCipherSuites();
+ getLogger().debug("list of supported ciphers");
+ for (int i = 0; i < ss.length; i++)
+ getLogger().debug(ss[i]);
+ }
/**
* Hook for subclasses to perform an required initialisation
@@ -843,9 +912,15 @@
serviceShortNameString = serviceType;
}
final String name = serviceShortNameString + "Handler-" +
handlerCount.getAndAdd(1);
- final JamesConnectionBridge delegatingJamesHandler =
- new JamesConnectionBridge(newProtocolHandlerInstance(),
dnsService, name, getLogger());
+ final JamesConnectionBridge delegatingJamesHandler;
+
+ if (useStartTLS) {
+ delegatingJamesHandler = new
JamesConnectionBridge(newProtocolHandlerInstance(), dnsService, name,
getLogger(), factory);
+ } else {
+ delegatingJamesHandler = new
JamesConnectionBridge(newProtocolHandlerInstance(), dnsService, name,
getLogger());
+ }
return delegatingJamesHandler;
+
}
protected abstract ProtocolHandler newProtocolHandlerInstance();
@@ -858,5 +933,10 @@
return JamesConnectionBridge.class;
}
+
+ public boolean useStartTLS() {
+ return useStartTLS;
+ }
+
}
Modified:
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/JamesConnectionBridge.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/JamesConnectionBridge.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/JamesConnectionBridge.java
(original)
+++
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/JamesConnectionBridge.java
Sun Sep 27 17:38:54 2009
@@ -31,6 +31,9 @@
import java.net.Socket;
import java.net.SocketException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
import org.apache.avalon.excalibur.pool.Poolable;
import org.apache.avalon.framework.container.ContainerUtil;
@@ -118,6 +121,15 @@
private final Log log;
+ private SSLSocketFactory factory;
+ private boolean secureEnabled = false;
+
+ public JamesConnectionBridge(final ProtocolHandler delegated, final
DNSService dnsServer, final String name,
+ final Logger logger, final SSLSocketFactory factory) {
+ this(delegated, dnsServer, name, logger);
+ this.factory = factory;
+ }
+
public JamesConnectionBridge(final ProtocolHandler delegated, final
DNSService dnsServer, final String name,
final Logger logger) {
this.protocolHandler = delegated;
@@ -146,20 +158,8 @@
synchronized (this) {
handlerThread = Thread.currentThread();
}
- in = new BufferedInputStream(socket.getInputStream(),
DEFAULT_INPUT_BUFFER_SIZE);
- outs = new BufferedOutputStream(socket.getOutputStream(),
DEFAULT_OUTPUT_BUFFER_SIZE);
- // enable tcp dump for debug
- if (tcplogprefix != null) {
- outs = new SplitOutputStream(outs, new
FileOutputStream(tcplogprefix+"out"));
- in = new CopyInputStream(in, new
FileOutputStream(tcplogprefix+"in"));
- }
-
- // An ASCII encoding can be used because all transmissions other
- // that those in the message body command are guaranteed
- // to be ASCII
- inReader = new CRLFTerminatedReader(in, "ASCII");
-
- out = new InternetPrintWriter(outs, true);
+
+ connectStreams(socket);
} catch (RuntimeException e) {
StringBuilder exceptionBuffer =
new StringBuilder(256)
@@ -198,7 +198,34 @@
}
}
- /**
+
+ private SSLSocket secureSocket(Socket socket) throws IOException {
+ SSLSocket sslsock = (SSLSocket) factory.createSocket(socket,
socket
+ .getInetAddress().getHostName(),
socket.getPort(), true);
+ sslsock.setUseClientMode(false);
+
+ return sslsock;
+ }
+
+
+ private void connectStreams(Socket socket) throws IOException {
+ in = new BufferedInputStream(socket.getInputStream(),
DEFAULT_INPUT_BUFFER_SIZE);
+ outs = new BufferedOutputStream(socket.getOutputStream(),
DEFAULT_OUTPUT_BUFFER_SIZE);
+ // enable tcp dump for debug
+ if (tcplogprefix != null) {
+ outs = new SplitOutputStream(outs, new
FileOutputStream(tcplogprefix+"out"));
+ in = new CopyInputStream(in, new
FileOutputStream(tcplogprefix+"in"));
+ }
+
+ // An ASCII encoding can be used because all transmissions other
+ // that those in the message body command are guaranteed
+ // to be ASCII
+ inReader = new CRLFTerminatedReader(in, "ASCII");
+
+ out = new InternetPrintWriter(outs, true);
+ }
+
+ /**
* The method clean up and close the allocated resources
*/
private void cleanHandler() {
@@ -435,6 +462,7 @@
protocolHandler.resetHandler();
remoteHost = null;
remoteIP = null;
+ secureEnabled = false;
}
/**
@@ -500,4 +528,24 @@
public void execute() {
idleClose();
}
+
+ /**
+ * @see org.apache.james.socket.ProtocolContext#isSecure()
+ */
+ public boolean isSecure() {
+ return secureEnabled;
+ }
+
+ /**
+ * @see org.apache.james.socket.ProtocolContext#secure()
+ */
+ public void secure() throws IOException {
+ if (factory == null) {
+ throw new UnsupportedOperationException("StartTLS not
supported");
+ }
+ this.secureEnabled = true;
+
+ socket = secureSocket(socket);
+ connectStreams(socket);
+ }
}
Modified:
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/ProtocolContext.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/ProtocolContext.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/ProtocolContext.java
(original)
+++
james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/ProtocolContext.java
Sun Sep 27 17:38:54 2009
@@ -20,6 +20,7 @@
package org.apache.james.socket;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -98,4 +99,17 @@
* @return not null
*/
public Log getLogger();
+
+ /**
+ * Secure the current socket using tls/ssl
+ * @throws IOException
+ */
+ public void secure() throws IOException;
+
+ /**
+ * Return if the current socket is using tls/ssl
+ *
+ * @return isSecure
+ */
+ public boolean isSecure();
}
\ No newline at end of file
Modified: james/server/trunk/phoenix-deployment/src/conf/james-config.xml
URL:
http://svn.apache.org/viewvc/james/server/trunk/phoenix-deployment/src/conf/james-config.xml?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
--- james/server/trunk/phoenix-deployment/src/conf/james-config.xml (original)
+++ james/server/trunk/phoenix-deployment/src/conf/james-config.xml Sun Sep 27
17:38:54 2009
@@ -963,12 +963,27 @@
<!--
<useTLS>true</useTLS>
-->
+
<!-- Use provider elements to specify additional JCE providers.
The jars should be put into $JAMES_HOME/lib.
For example, Uncomment this if you want to use
BouncyCastle JCE (http://www.bouncycastle.org)
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-->
+ <!-- Set enable to true to support STARTTLS.
+ To use this you need to copy sunjce_provider.jar to /path/james/lib
directory.
+ -->
+
+ <startTLS enable="false">
+
+ <!-- To create a new keystore execute:
+ keytool -genkey -alias james -keyalg RSA -keystore
/path/to/james/conf/keystore
+ -->
+ <keystore>file://conf/keystore</keystore>
+ <secret></secret>
+ <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+ </startTLS>
+
<handler>
<!-- This is the name used by the server to identify itself in the
SMTP -->
<!-- protocol. If autodetect is TRUE, the server will discover its
-->
@@ -1648,5 +1663,4 @@
<min-spare-threads>20</min-spare-threads>
</thread-group>
</thread-manager>
-
</config>
Modified:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPConfiguration.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPConfiguration.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPConfiguration.java
(original)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPConfiguration.java
Sun Sep 27 17:38:54 2009
@@ -89,5 +89,7 @@
* @return true or false
*/
boolean useAddressBracketsEnforcement();
+
+ boolean isStartTLSSupported();
}
Modified:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
(original)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
Sun Sep 27 17:38:54 2009
@@ -398,4 +398,16 @@
public Log getLogger() {
return context.getLogger();
}
+
+ public boolean isTLSStarted() {
+ return context.isSecure();
+ }
+
+ public void secure() throws IOException {
+ context.secure();
+ }
+
+ public boolean isStartTLSSupported() {
+ return getConfigurationData().isStartTLSSupported();
+ }
}
Modified:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java
(original)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java
Sun Sep 27 17:38:54 2009
@@ -119,8 +119,7 @@
= new SMTPHandlerConfigurationDataImpl();
private boolean addressBracketsEnforcement = true;
-
-
+
/**
* Gets the current instance loader.
* @return the loader
@@ -227,7 +226,6 @@
smtpGreeting =
handlerConfiguration.getChild("smtpGreeting").getValue(null);
addressBracketsEnforcement =
handlerConfiguration.getChild("addressBracketsEnforcement").getValueAsBoolean(true);
-
} else {
// TODO Remove this in next not backwards compatible release!
if (hello == null)
mailetcontext.setAttribute(Constants.HELLO_NAME, "localhost");
@@ -344,6 +342,10 @@
}
return authRequired;
}
+
+ public boolean isStartTLSSupported() {
+ return SMTPServer.this.useStartTLS();
+ }
//TODO: IF we create here an interface to get DNSServer
// we should access it from the SMTPHandlers
@@ -355,5 +357,5 @@
final SMTPHandler theHandler = new SMTPHandler(handlerChain,
theConfigData);
return theHandler;
}
-
+
}
Modified:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java
(original)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java
Sun Sep 27 17:38:54 2009
@@ -19,6 +19,7 @@
package org.apache.james.smtpserver;
+import java.io.IOException;
import java.util.Map;
import org.apache.commons.logging.Log;
@@ -188,5 +189,12 @@
* @return log, not null
*/
Log getLogger();
+
+ boolean isStartTLSSupported();
+
+ boolean isTLSStarted();
+
+ void secure() throws IOException;
+
}
Modified:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java
(original)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java
Sun Sep 27 17:38:54 2009
@@ -25,6 +25,7 @@
import org.apache.james.smtpserver.core.esmtp.AuthCmdHandler;
import org.apache.james.smtpserver.core.esmtp.EhloCmdHandler;
import org.apache.james.smtpserver.core.esmtp.MailSizeEsmtpExtension;
+import org.apache.james.smtpserver.core.esmtp.StartTlsCmdHandler;
import java.util.LinkedList;
import java.util.List;
@@ -54,7 +55,7 @@
private final String AUTHREQUIREDTORELAY =
AuthRequiredToRelayRcptHook.class.getName();
private final String SENDERAUTHIDENTITYVERIFICATION =
SenderAuthIdentifyVerificationRcptHook.class.getName();
private final String DATALINEMESSAGEHOOKHANDLER =
DataLineMessageHookHandler.class.getName();
-
+ private final String STARTTLSHANDLER = StartTlsCmdHandler.class.getName();
/**
* @see org.apache.james.smtpserver.HandlersPackage#getHandlers()
*/
@@ -82,7 +83,7 @@
commands.add(SENDERAUTHIDENTITYVERIFICATION);
commands.add(POSTMASTERABUSEHOOK);
commands.add(DATALINEMESSAGEHOOKHANDLER);
-
+ commands.add(STARTTLSHANDLER);
return commands;
}
}
Added:
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/StartTlsCmdHandler.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/StartTlsCmdHandler.java?rev=819359&view=auto
==============================================================================
---
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/StartTlsCmdHandler.java
(added)
+++
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/StartTlsCmdHandler.java
Sun Sep 27 17:38:54 2009
@@ -0,0 +1,104 @@
+/****************************************************************
+ * 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.smtpserver.core.esmtp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.james.dsn.DSNStatus;
+import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
+import org.apache.james.smtpserver.SMTPRetCode;
+import org.apache.james.smtpserver.SMTPSession;
+
+/**
+ * Handles STARTTLS command
+ */
+public class StartTlsCmdHandler implements CommandHandler, EhloExtension {
+ /**
+ * The name of the command handled by the command handler
+ */
+ private final static String COMMAND_NAME = "STARTTLS";
+
+ /**
+ * @see org.apache.james.smtpserver.CommandHandler#getImplCommands()
+ */
+ public Collection<String> getImplCommands() {
+ Collection<String> commands = new ArrayList<String>();
+ commands.add(COMMAND_NAME);
+ return commands;
+ }
+
+ /**
+ * Handler method called upon receipt of a STARTTLS command. Resets
+ * message-specific, but not authenticated user, state.
+ *
+ * @see
org.apache.james.smtpserver.CommandHandler#onCommand(org.apache.james.smtpserver.SMTPSession,
+ * java.lang.String, java.lang.String)
+ */
+ public SMTPResponse onCommand(SMTPSession session, String command,
+ String parameters) {
+ SMTPResponse response = null;
+ if (session.isStartTLSSupported()) {
+ if (session.isTLSStarted()) {
+ response = new SMTPResponse("500",
DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_CMD) + "
TLS already active RFC2487 5.2");
+ } else {
+ if ((parameters == null) ||
(parameters.length() == 0)) {
+ response = new SMTPResponse("220",
DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.UNDEFINED_STATUS) + " Ready to
start TLS");
+ } else {
+ response = new SMTPResponse("501 "+
DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG) + "
Syntax error (no parameters allowed) with STARTTLS command");
+ }
+ }
+ try {
+ if (!session.isTLSStarted()) {
+ session.secure();
+ // force reset
+ session.resetState();
+ }
+ } catch (IOException e) {
+ response = new
SMTPResponse(SMTPRetCode.LOCAL_ERROR,"Temporary error while trying to start
TLS");
+ }
+ } else {
+ StringBuilder result = new StringBuilder();
+ result.append(DSNStatus.getStatus(DSNStatus.PERMANENT,
DSNStatus.DELIVERY_INVALID_CMD))
+ .append(" Command ")
+ .append(command)
+ .append(" unrecognized.");
+ response = new
SMTPResponse(SMTPRetCode.SYNTAX_ERROR_COMMAND_UNRECOGNIZED, result);
+ }
+ return response;
+ }
+
+ /**
+ * @see
org.apache.james.smtpserver.core.esmtp.EhloExtension#getImplementedEsmtpFeatures(org.apache.james.smtpserver.SMTPSession)
+ */
+ public List<String> getImplementedEsmtpFeatures(SMTPSession session) {
+ List<String> esmtpextensions = new ArrayList<String>();
+ // SMTP STARTTLS
+ if (!session.isTLSStarted() && session.isStartTLSSupported()) {
+ esmtpextensions.add("STARTTLS");
+ }
+ return esmtpextensions;
+
+ }
+
+}
Modified:
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/BaseFakeSMTPSession.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/BaseFakeSMTPSession.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/BaseFakeSMTPSession.java
(original)
+++
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/BaseFakeSMTPSession.java
Sun Sep 27 17:38:54 2009
@@ -20,6 +20,7 @@
package org.apache.james.smtpserver;
+import java.io.IOException;
import java.util.Map;
import org.apache.commons.logging.Log;
@@ -178,4 +179,17 @@
public Log getLogger() {
return log;
}
+
+ public boolean isStartTLSSupported() {
+ return getConfigurationData().isStartTLSSupported();
+ }
+
+ public boolean isTLSStarted() {
+ throw new UnsupportedOperationException("Unimplemented Stub Method");
+ }
+
+ public void secure() throws IOException {
+ throw new UnsupportedOperationException("Unimplemented Stub Method");
+
+ }
}
Modified:
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
(original)
+++
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
Sun Sep 27 17:38:54 2009
@@ -46,6 +46,7 @@
import org.apache.commons.net.smtp.SMTPReply;
import org.apache.james.api.dnsservice.DNSService;
import org.apache.james.api.user.UsersRepository;
+import org.apache.james.services.FileSystem;
import org.apache.james.services.MailServer;
import org.apache.james.socket.JamesConnectionManager;
import org.apache.james.socket.SimpleConnectionManager;
@@ -53,6 +54,7 @@
import org.apache.james.test.mock.avalon.MockSocketManager;
import org.apache.james.test.mock.avalon.MockStore;
import org.apache.james.test.mock.avalon.MockThreadManager;
+import org.apache.james.test.mock.james.MockFileSystem;
import org.apache.james.test.mock.james.MockMailServer;
import org.apache.james.test.util.Util;
import org.apache.james.userrepository.MockUsersRepository;
@@ -151,7 +153,6 @@
private MockUsersRepository m_usersRepository = new MockUsersRepository();
private FakeLoader m_serviceManager;
private AlterableDNSServer m_dnsServer;
-
public SMTPServerTest() {
super("SMTPServerTest");
m_smtpListenerPort = Util.getNonPrivilegedPort();
@@ -214,6 +215,8 @@
m_serviceManager.put(DNSService.ROLE, m_dnsServer);
m_serviceManager.put("dnsserver", m_dnsServer);
m_serviceManager.put(Store.ROLE, new MockStore());
+ m_serviceManager.put(FileSystem.ROLE, new MockFileSystem());
+
return m_serviceManager;
}
@@ -250,6 +253,35 @@
assertNotNull("mail received by mail server",
m_mailServer.getLastMail());
}
+ public void testStartTLSInEHLO() throws Exception {
+ m_testConfiguration.setStartTLS();
+ finishSetUp(m_testConfiguration);
+
+ SMTPClient smtpProtocol = new SMTPClient();
+ smtpProtocol.connect("127.0.0.1", m_smtpListenerPort);
+
+ // no message there, yet
+ assertNull("no mail received by mail server",
m_mailServer.getLastMail());
+
+ smtpProtocol.sendCommand("EHLO "+InetAddress.getLocalHost());
+ String[] capabilityRes = smtpProtocol.getReplyStrings();
+
+ List capabilitieslist = new ArrayList();
+ for (int i = 1; i < capabilityRes.length; i++) {
+ capabilitieslist.add(capabilityRes[i].substring(4));
+ }
+
+ assertEquals("capabilities", 4, capabilitieslist.size());
+ assertTrue("capabilities present PIPELINING",
capabilitieslist.contains("PIPELINING"));
+ assertTrue("capabilities present ENHANCEDSTATUSCODES",
capabilitieslist.contains("ENHANCEDSTATUSCODES"));
+ assertTrue("capabilities present 8BITMIME",
capabilitieslist.contains("8BITMIME"));
+ assertTrue("capabilities present STARTTLS",
capabilitieslist.contains("STARTTLS"));
+
+ smtpProtocol.quit();
+ smtpProtocol.disconnect();
+
+ }
+
/**
* TODO: Understand why this fails!
*
Modified:
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java
(original)
+++
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java
Sun Sep 27 17:38:54 2009
@@ -29,6 +29,7 @@
import
org.apache.james.smtpserver.core.filter.fastfail.ResolvableEhloHeloHandler;
import
org.apache.james.smtpserver.core.filter.fastfail.ReverseEqualsEhloHeloHandler;
import
org.apache.james.smtpserver.core.filter.fastfail.ValidSenderDomainHandler;
+import org.apache.james.test.mock.util.AttrValConfiguration;
import org.apache.james.test.util.Util;
public class SMTPTestConfiguration extends DefaultConfiguration {
@@ -50,6 +51,7 @@
private int m_maxRcpt = 0;
private boolean m_useRBL = false;
private boolean m_addressBracketsEnforcement = true;
+ private boolean m_startTLS = false;
public SMTPTestConfiguration(int smtpListenerPort) {
@@ -140,7 +142,9 @@
this.m_addressBracketsEnforcement = addressBracketsEnforcement;
}
-
+ public void setStartTLS() {
+ m_startTLS = true;
+ }
public void init() throws ConfigurationException {
setAttribute("enabled", true);
@@ -157,6 +161,13 @@
handlerConfig.addChild(Util.getValuedConfiguration("authRequired",
m_authorizingMode));
handlerConfig.addChild(Util.getValuedConfiguration("heloEhloEnforcement",
m_heloEhloEnforcement+""));
handlerConfig.addChild(Util.getValuedConfiguration("addressBracketsEnforcement",
m_addressBracketsEnforcement+""));
+
+ DefaultConfiguration tlsConfig = new DefaultConfiguration("startTLS");
+ tlsConfig.setAttribute("enable", m_startTLS);
+ tlsConfig.addChild(new
AttrValConfiguration("keystore","file://conf/test_keystore"));
+ tlsConfig.addChild(Util.getValuedConfiguration("secret", "jamestest"));
+ addChild(tlsConfig);
+
if (m_verifyIdentity)
handlerConfig.addChild(Util.getValuedConfiguration("verifyIdentity", "" +
m_verifyIdentity));
DefaultConfiguration config = new DefaultConfiguration("handlerchain");
Modified:
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java?rev=819359&r1=819358&r2=819359&view=diff
==============================================================================
---
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
(original)
+++
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
Sun Sep 27 17:38:54 2009
@@ -34,11 +34,9 @@
import org.apache.james.api.vut.ErrorMappingException;
import org.apache.james.api.vut.VirtualUserTable;
import org.apache.james.api.vut.VirtualUserTableStore;
-import org.apache.james.services.MailServer;
import org.apache.james.smtpserver.core.filter.fastfail.ValidRcptHandler;
import org.apache.james.smtpserver.hook.HookReturnCode;
import org.apache.james.test.mock.avalon.MockLogger;
-import org.apache.james.test.mock.avalon.MockServiceManager;
import org.apache.james.test.mock.james.MockVirtualUserTableStore;
import org.apache.james.userrepository.MockUsersRepository;
import org.apache.mailet.MailAddress;
@@ -50,7 +48,6 @@
private final static String INVALID_USER = "invalid";
private final static String USER1 = "user1";
private final static String USER2 = "user2";
- private MockServiceManager serviceMan;
UsersRepository users;
ValidRcptHandler handler;
@@ -106,10 +103,6 @@
throw new UnsupportedOperationException("Unimplemented Stub
Method");
}
- public MailServer getMailServer() {
- throw new UnsupportedOperationException("Unimplemented Stub
Method");
- }
-
public long getMaxMessageSize() {
throw new UnsupportedOperationException("Unimplemented Stub
Method");
}
@@ -122,10 +115,6 @@
throw new UnsupportedOperationException("Unimplemented Stub
Method");
}
- public UsersRepository getUsersRepository() {
-
- return users;
- }
public boolean isRelayingAllowed(String remoteIP) {
throw new UnsupportedOperationException("Unimplemented Stub
Method");
@@ -142,6 +131,10 @@
public boolean isAuthRequired(String remoteIP) {
throw new UnsupportedOperationException("Unimplemented Stub
Method");
}
+
+ public boolean isStartTLSSupported() {
+ return false;
+ }
};
return conf;
Added: james/server/trunk/smtpserver-function/src/test/resources/test_keystore
URL:
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/resources/test_keystore?rev=819359&view=auto
==============================================================================
Binary file - no diff available.
Propchange:
james/server/trunk/smtpserver-function/src/test/resources/test_keystore
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]