You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2004/03/15 18:16:03 UTC
cvs commit: avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets AbstractTLSSocketFactory.java DefaultServerSocketFactory.java DefaultSocketFactory.java DefaultSocketManager-schema.xml DefaultSocketManager.java DefaultSocketManager.xinfo SSLFactoryBuilder.java TLSServerSocketFactory.java TLSSocketFactory.java package.html
mcconnell 2004/03/15 09:16:03
Added: cornerstone/sockets/api .cvsignore project.xml
cornerstone/sockets/api/src/java/org/apache/avalon/cornerstone/services/sockets
ServerSocketFactory.java SocketFactory.java
SocketManager.java package.html
cornerstone/sockets/impl .cvsignore maven.xml project.xml
cornerstone/sockets/impl/conf block.xml
cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets
AbstractTLSSocketFactory.java
DefaultServerSocketFactory.java
DefaultSocketFactory.java
DefaultSocketManager-schema.xml
DefaultSocketManager.java
DefaultSocketManager.xinfo SSLFactoryBuilder.java
TLSServerSocketFactory.java TLSSocketFactory.java
package.html
Log:
Update to use native avalon tags. Bumped implementation version to 1.1.
Revision Changes Path
1.1 avalon-components/cornerstone/sockets/api/.cvsignore
Index: .cvsignore
===================================================================
maven.log
velocity.log
build.properties
target
maven.log
1.1 avalon-components/cornerstone/sockets/api/project.xml
Index: project.xml
===================================================================
<?xml version="1.0" encoding="ISO-8859-1"?>
<project>
<extend>${basedir}/../../project.xml</extend>
<groupId>cornerstone-sockets</groupId>
<id>cornerstone-sockets-api</id>
<name>Cornerstone Sockets API</name>
<currentVersion>1.0</currentVersion>
<package>org.apache.avalon.cornerstone.services.sockets</package>
<inceptionYear>2001</inceptionYear>
<shortDescription>Cornerstone Sockets API</shortDescription>
</project>
1.1 avalon-components/cornerstone/sockets/api/src/java/org/apache/avalon/cornerstone/services/sockets/ServerSocketFactory.java
Index: ServerSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.services.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
/**
* The interface used to create server sockets.
*
* @author Peter Donald
*/
public interface ServerSocketFactory
{
/**
* Creates a socket on specified port.
*
* @param port the port
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
ServerSocket createServerSocket( int port )
throws IOException;
/**
* Creates a socket on specified port with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
ServerSocket createServerSocket( int port, int backLog )
throws IOException;
/**
* Creates a socket on a particular network interface on specified port
* with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @param bindAddress the network interface to bind to.
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
ServerSocket createServerSocket( int port, int backLog, InetAddress bindAddress )
throws IOException;
}
1.1 avalon-components/cornerstone/sockets/api/src/java/org/apache/avalon/cornerstone/services/sockets/SocketFactory.java
Index: SocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.services.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
/**
* The interface used to create client sockets.
*
* @author Peter Donald
*/
public interface SocketFactory
{
/**
* Create a socket and connect to remote address specified.
*
* @param address the remote address
* @param port the remote port
* @return the socket
* @exception IOException if an error occurs
*/
Socket createSocket( InetAddress address, int port )
throws IOException;
/**
* Create a socket and connect to remote address specified
* originating from specified local address.
*
* @param address the remote address
* @param port the remote port
* @param localAddress the local address
* @param localPort the local port
* @return the socket
* @exception IOException if an error occurs
*/
Socket createSocket( InetAddress address, int port,
InetAddress localAddress, int localPort )
throws IOException;
}
1.1 avalon-components/cornerstone/sockets/api/src/java/org/apache/avalon/cornerstone/services/sockets/SocketManager.java
Index: SocketManager.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.services.sockets;
/**
* Service to manager the socket factories.
*
* @author Peter Donald
*/
public interface SocketManager
{
String ROLE = SocketManager.class.getName();
/**
* Retrieve a server socket factory by name.
*
* @param name the name of server socket factory
* @return the ServerSocketFactory
* @exception Exception if server socket factory is not available
*/
ServerSocketFactory getServerSocketFactory( String name )
throws Exception;
/**
* Retrieve a client socket factory by name.
*
* @param name the name of client socket factory
* @return the SocketFactory
* @exception Exception if socket factory is not available
*/
SocketFactory getSocketFactory( String name )
throws Exception;
}
1.1 avalon-components/cornerstone/sockets/api/src/java/org/apache/avalon/cornerstone/services/sockets/package.html
Index: package.html
===================================================================
<body>
Defintion of the sockets service.
</body>
1.1 avalon-components/cornerstone/sockets/impl/.cvsignore
Index: .cvsignore
===================================================================
maven.log
velocity.log
build.properties
target
maven.log
1.1 avalon-components/cornerstone/sockets/impl/maven.xml
Index: maven.xml
===================================================================
<project default="jar:install-snapshot">
<postGoal name="java:prepare-filesystem">
<attainGoal name="avalon:meta"/>
</postGoal>
</project>
1.1 avalon-components/cornerstone/sockets/impl/project.xml
Index: project.xml
===================================================================
<?xml version="1.0" encoding="ISO-8859-1"?>
<project>
<extend>${basedir}/../../project.xml</extend>
<groupId>cornerstone-sockets</groupId>
<id>cornerstone-sockets-impl</id>
<name>Cornerstone Socket Manager Implementation</name>
<currentVersion>1.1</currentVersion>
<package>org.apache.avalon.cornerstone.blocks.sockets</package>
<inceptionYear>2001</inceptionYear>
<shortDescription>Cornerstone Sockets</shortDescription>
<dependencies>
<!-- cornerstone dependencies -->
<dependency>
<groupId>cornerstone-sockets</groupId>
<artifactId>cornerstone-sockets-api</artifactId>
<version>1.0</version>
</dependency>
<!-- avalon dependencies -->
<dependency>
<groupId>avalon-framework</groupId>
<artifactId>avalon-framework-api</artifactId>
<version>4.1.5</version>
</dependency>
<dependency>
<groupId>avalon-framework</groupId>
<artifactId>avalon-framework-impl</artifactId>
<version>4.1.5</version>
</dependency>
<!-- pre JDK 1.4 dependencies -->
<dependency>
<id>xml-apis</id>
<version>1.0.b2</version>
<url>http://xml.apache.org/xerces2-j/</url>
</dependency>
<dependency>
<id>xerces</id>
<version>2.2.1</version>
<url>http://xml.apache.org/xerces2-j/</url>
</dependency>
</dependencies>
</project>
1.1 avalon-components/cornerstone/sockets/impl/conf/block.xml
Index: block.xml
===================================================================
<!--
Thread Block deployment directive.
-->
<container name="sockets">
<services>
<service type="org.apache.avalon.cornerstone.services.sockets.SocketManager">
<source>manager</source>
</service>
</services>
<classloader>
<classpath>
<repository>
<resource id="avalon-framework:avalon-framework-impl" version="4.1.5"/>
<resource id="cornerstone-sockets:cornerstone-sockets-api" version="1.0"/>
<resource id="cornerstone-sockets:cornerstone-sockets-impl" version="1.0"/>
</repository>
</classpath>
</classloader>
<component name="manager"
class="org.apache.avalon.cornerstone.blocks.sockets.DefaultSocketManager"
activation="true">
<configuration>
<server-sockets>
<factory name="plain"
class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketFactory"/>
</server-sockets>
<client-sockets>
<factory name="plain"
class="org.apache.avalon.cornerstone.blocks.sockets.DefaultSocketFactory"/>
</client-sockets>
</configuration>
</component>
</container>
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/AbstractTLSSocketFactory.java
Index: AbstractTLSSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
/**
* Contains the code common for both TLS socket factories. They both
* need to use an SSLFactoryBuilder which is configured using
* configuration and context given by the container. Then, they both
* set timeouts on the manufactured sockets.
*
* @author <a href="mailto:greg-avalon-apps at nest.cx">Greg Steuck</a>
*/
public abstract class AbstractTLSSocketFactory
extends AbstractLogEnabled
implements Contextualizable, Configurable, Initializable
{
private final static int WAIT_FOREVER = 0;
protected int m_socketTimeOut;
private Context m_context;
private Configuration m_childConfig;
public void contextualize( final Context context )
{
m_context = context;
}
/**
* Configures the factory.
*
* @param configuration the Configuration
* @exception ConfigurationException if an error occurs
*/
public void configure( final Configuration configuration )
throws ConfigurationException
{
m_socketTimeOut = configuration.getChild( "timeout" ).getValueAsInteger( WAIT_FOREVER );
m_childConfig = configuration.getChild( "ssl-factory", false );
if( m_childConfig == null )
{
final String message = "ssl-factory child not found, please" +
" update your configuration according to" +
" the documentation. Reverting to the" +
" old configuration format.";
getLogger().warn( message );
// not completely compatible though
m_childConfig = configuration;
}
}
/**
* Creates an SSL factory using the confuration values.
*/
public void initialize() throws Exception
{
final SSLFactoryBuilder builder = new SSLFactoryBuilder();
setupLogger( builder );
ContainerUtil.contextualize( builder, m_context );
ContainerUtil.configure( builder, m_childConfig );
ContainerUtil.initialize( builder );
visitBuilder( builder );
ContainerUtil.shutdown( builder );
m_context = null;
m_childConfig = null;
}
/**
* The child factories have to use an instance of
* <tt>SSLFactoryBuilder</tt> to obtain their factories. So they
* are given an instance when it's ready. Another alternative was
* to have the SSLFactoryBuilder export buildContext method, but
* that would mean SSLContext which is deep in Sun guts will be
* aired in 3-4 classes instead of 1.
*/
protected abstract void visitBuilder( SSLFactoryBuilder builder );
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/DefaultServerSocketFactory.java
Index: DefaultServerSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import org.apache.avalon.cornerstone.services.sockets.ServerSocketFactory;
/**
* Factory implementation for vanilla TCP sockets.
*
* @author Peter Donald
* @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
*/
public class DefaultServerSocketFactory
implements ServerSocketFactory
{
/**
* Creates a socket on specified port.
*
* @param port the port
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( final int port )
throws IOException
{
return new ServerSocket( port );
}
/**
* Creates a socket on specified port with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( int port, int backLog )
throws IOException
{
return new ServerSocket( port, backLog );
}
/**
* Creates a socket on a particular network interface on specified port
* with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @param bindAddress the network interface to bind to.
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( int port, int backLog, InetAddress bindAddress )
throws IOException
{
return new ServerSocket( port, backLog, bindAddress );
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/DefaultSocketFactory.java
Index: DefaultSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import org.apache.avalon.cornerstone.services.sockets.SocketFactory;
/**
* The vanilla implementation of SocketFactory.
*
* @author Peter Donald
*/
public class DefaultSocketFactory
implements SocketFactory
{
/**
* Create a socket and connect to remote address specified.
*
* @param address the remote address
* @param port the remote port
* @return the socket
* @exception IOException if an error occurs
*/
public Socket createSocket( final InetAddress address, final int port )
throws IOException
{
return new Socket( address, port );
}
/**
* Create a socket and connect to remote address specified
* originating from specified local address.
*
* @param address the remote address
* @param port the remote port
* @param localAddress the local address
* @param localPort the local port
* @return the socket
* @exception IOException if an error occurs
*/
public Socket createSocket( final InetAddress address,
final int port,
final InetAddress localAddress,
final int localPort )
throws IOException
{
return new Socket( address, port, localAddress, localPort );
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/DefaultSocketManager-schema.xml
Index: DefaultSocketManager-schema.xml
===================================================================
<?xml version="1.0"?>
<grammar
xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
xmlns:a="http://jakarta.apache.org/phoenix/schema-annotations/1.0"
>
<start>
<element name="root">
<optional>
<element name="server-sockets">
<oneOrMore>
<ref name="factory"/>
</oneOrMore>
</element>
<element name="client-sockets">
<oneOrMore>
<ref name="factory"/>
</oneOrMore>
</element>
</optional>
</element>
</start>
<define name="factory">
<element name="factory">
<attribute name="name"/>
<attribute name="class"/>
</element>
</define>
</grammar>
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/DefaultSocketManager.java
Index: DefaultSocketManager.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import java.util.HashMap;
import org.apache.avalon.cornerstone.services.sockets.ServerSocketFactory;
import org.apache.avalon.cornerstone.services.sockets.SocketFactory;
import org.apache.avalon.cornerstone.services.sockets.SocketManager;
import org.apache.avalon.framework.CascadingException;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
/**
* Implementation of SocketManager.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
* @avalon.component name="socket-manager" lifestyle="singleton"
* @avalon.service type="org.apache.avalon.cornerstone.services.sockets.SocketManager"
*/
public class DefaultSocketManager
extends AbstractLogEnabled
implements SocketManager, Contextualizable, Configurable, Initializable
{
protected final HashMap m_serverSockets = new HashMap();
protected final HashMap m_sockets = new HashMap();
protected Context m_context;
protected Configuration m_configuration;
public void contextualize( final Context context )
{
m_context = context;
}
/**
* Configure the SocketManager.
*
* @param configuration the Configuration
* @exception ConfigurationException if an error occurs
* @avalon.configuration schema="http://relaxng.org/ns/structure/1.0"
*/
public void configure( final Configuration configuration )
throws ConfigurationException
{
m_configuration = configuration;
}
public void initialize()
throws Exception
{
final Configuration[] serverSockets =
m_configuration.getChild( "server-sockets" ).getChildren( "factory" );
for( int i = 0; i < serverSockets.length; i++ )
{
final Configuration element = serverSockets[ i ];
final String name = element.getAttribute( "name" );
final String className = element.getAttribute( "class" );
setupServerSocketFactory( name, className, element );
}
final Configuration[] clientSockets =
m_configuration.getChild( "client-sockets" ).getChildren( "factory" );
for( int i = 0; i < clientSockets.length; i++ )
{
final Configuration element = clientSockets[ i ];
final String name = element.getAttribute( "name" );
final String className = element.getAttribute( "class" );
setupClientSocketFactory( name, className, element );
}
}
protected void setupServerSocketFactory( final String name,
final String className,
final Configuration configuration )
throws Exception
{
final Object object = createFactory( name, className, configuration );
if( !( object instanceof ServerSocketFactory ) )
{
throw new Exception( "Error creating factory " + name +
" with class " + className + " as " +
"it does not implement the correct " +
"interface (ServerSocketFactory)" );
}
m_serverSockets.put( name, object );
}
protected void setupClientSocketFactory( final String name,
final String className,
final Configuration configuration )
throws Exception
{
final Object object = createFactory( name, className, configuration );
if( !( object instanceof SocketFactory ) )
{
throw new Exception( "Error creating factory " + name +
" with class " + className + " as " +
"it does not implement the correct " +
"interface (SocketFactory)" );
}
m_sockets.put( name, object );
}
protected Object createFactory( final String name,
final String className,
final Configuration configuration )
throws Exception
{
Object factory = null;
try
{
final ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
factory = classLoader.loadClass( className ).newInstance();
}
catch( final Throwable e )
{
final String error =
"Error creating factory with class " + className;
getLogger().error( "## CLASSLOADER: " + Thread.currentThread().getContextClassLoader() );
throw new CascadingException( error, e );
}
ContainerUtil.enableLogging( factory, getLogger() );
ContainerUtil.contextualize( factory, m_context );
ContainerUtil.configure( factory, configuration );
ContainerUtil.initialize( factory );
return factory;
}
/**
* Retrieve a server socket factory by name.
*
* @param name the name of server socket factory
* @return the ServerSocketFactory
* @exception Exception if server socket factory is not available
*/
public ServerSocketFactory getServerSocketFactory( String name )
throws Exception
{
final ServerSocketFactory factory = (ServerSocketFactory)m_serverSockets.get( name );
if( null != factory )
{
return factory;
}
else
{
throw new Exception( "Unable to locate server socket factory " +
"named " + name );
}
}
/**
* Retrieve a client socket factory by name.
*
* @param name the name of client socket factory
* @return the SocketFactory
* @exception Exception if socket factory is not available
*/
public SocketFactory getSocketFactory( final String name )
throws Exception
{
final SocketFactory factory = (SocketFactory)m_sockets.get( name );
if( null != factory )
{
return factory;
}
else
{
throw new Exception( "Unable to locate client socket factory " +
"named " + name );
}
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/DefaultSocketManager.xinfo
Index: DefaultSocketManager.xinfo
===================================================================
<?xml version="1.0"?>
<!DOCTYPE blockinfo PUBLIC "-//PHOENIX/Block Info DTD Version 1.0//EN"
"http://jakarta.apache.org/avalon/dtds/phoenix/blockinfo_1_0.dtd">
<blockinfo>
<block>
<version>1.0</version>
<schema-type>http://relaxng.org/ns/structure/1.0</schema-type>
</block>
<services>
<service name="org.apache.avalon.cornerstone.services.sockets.SocketManager"/>
</services>
</blockinfo>
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/SSLFactoryBuilder.java
Index: SSLFactoryBuilder.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.Arrays;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocketFactory;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
/**
* Builds SSLContexts with desired properties. Hides all the gory
* details of SSLContext productions behind nice Avalon
* interfaces. Married to Sun JCA implementation.
* <p>
* Configuration looks like:
* <pre>
* <ssl-factory>
* <keystore>
* <file>conf/keystore</file> <!-- keystore file location -->
* <password></password> <!-- Key Store file password, only used to check keystore integrity -->
* <key-password></key-password> <!-- Only required when you need to decrypt a private key -->
* <type>JKS</type> <!-- Key Store file format, defaults to JKS -->
* <algorithm>SunX509</algorithm> <!-- Cryptography provider ID, defaults to SunX509 -->
* </keystore>
* <!-- SSL protocol to use, defaults to TLS, another possible value is SSL -->
* <protocol>TLS</protocol>
* </ssl-factory>
* </pre>
* </p>
* <p>
* Notes on keystore files. Absolute paths are supported. Relative
* paths are interpreted relative to .sar base directory. Defaults to
* conf/keystore. Since keystore usually contains sensitive keys it
* maybe beneficial to <b>not</b> include the keystores into the .sar
* files.
* </p>
* @author <a href="mailto:greg-avalon-apps at nest.cx">Greg Steuck</a>
*/
public class SSLFactoryBuilder extends AbstractLogEnabled
implements Configurable, Contextualizable, Disposable, Initializable
{
private File m_baseDirectory;
private File m_keystoreFile;
private String m_keystorePassword;
private String m_keyPassword;
private String m_protocol;
private String m_provider;
private String m_keystoreFormat;
private SSLContext m_ctx;
static
{
// Registers Sun's providers
java.security.Security.addProvider( new sun.security.provider.Sun() );
java.security.Security.addProvider( new com.sun.net.ssl.internal.ssl.Provider() );
}
/**
* Requires a BlockContext. We'll see how we end up expressing
* these dependencies.
*/
public void contextualize( final Context context ) throws ContextException
{
m_baseDirectory = (File)context.get( "app.home" );
}
public void configure( final Configuration configuration )
throws ConfigurationException
{
final Configuration storeConfig = configuration.getChild( "keystore" );
final String fileName = storeConfig.getChild( "file" ).getValue( "conf/keystore" );
final File configuredFile = new File( fileName );
if( !configuredFile.isAbsolute() )
{
m_keystoreFile = new File( m_baseDirectory, fileName );
}
else
{
m_keystoreFile = configuredFile;
}
m_keystorePassword = storeConfig.getChild( "password" ).getValue( null );
m_keyPassword = storeConfig.getChild( "key-password" ).getValue( null );
// key is named incorrectly, left as is for compatibility
m_provider = storeConfig.getChild( "algorithm" ).getValue( "SunX509" );
// key is named incorrectly, left as is for compatibility
m_keystoreFormat = storeConfig.getChild( "type" ).getValue( "JKS" );
// ugly compatibility workaround follows
m_protocol = configuration.getChild( "protocol" ).
getValue( storeConfig.getChild( "protocol" ).getValue( "TLS" ) );
}
/**
* Produces a fresh ssl socket factory with configured parameters.
*/
public SSLSocketFactory buildSocketFactory()
{
return m_ctx.getSocketFactory();
}
/**
* Produces a fresh ssl server socket factory with configured
* parameters.
*/
public SSLServerSocketFactory buildServerSocketFactory()
{
return m_ctx.getServerSocketFactory();
}
public void initialize()
throws IOException, GeneralSecurityException
{
final FileInputStream keyStream = new FileInputStream( m_keystoreFile );
try
{
m_ctx = makeContext( keyStream, m_keystorePassword,
m_keyPassword, m_protocol,
m_provider, m_keystoreFormat );
}
finally
{
try
{
keyStream.close();
}
catch( IOException e )
{
// avoids hiding exceptions from makeContext
// by catching this IOException
getLogger().error( "Error keyStream.close failed", e );
}
}
}
public void dispose()
{
m_keystorePassword = null;
m_keyPassword = null;
}
/**
* Creates an SSL context which uses the keys and certificates
* provided by the given <tt>keyStream</tt>. For simplicity the
* same key stream (keystore) is used for both key and trust
* factory.
*
* @param keyStream to read the keys from
* @param keystorePassword password for the keystore, can be null
* if integrity verification is not desired
* @param keyPassword passphrase which unlocks the keys in the key file
* (should really be a char[] so that it can be cleaned after use)
* @param protocol the standard name of the requested protocol
* @param provider the standard name of the requested algorithm
* @param keystoreFormat the type of keystore
*
* @return context configured with these keys and certificates
* @throws IOException if files can't be read
* @throws GeneralSecurityException is something goes wrong inside
* cryptography framework
*/
private static SSLContext makeContext( InputStream keyStream,
String keystorePassword,
String keyPassword,
String protocol,
String provider,
String keystoreFormat )
throws IOException, GeneralSecurityException
{
final KeyStore keystore = loadKeystore( keyStream,
keystorePassword,
keystoreFormat );
final KeyManagerFactory kmf = KeyManagerFactory.getInstance( provider );
// even though undocumented Sun's implementation doesn't allow
// null passphrases, but zero sized arrays are OK
final char[] passChars = ( keyPassword != null ) ?
keyPassword.toCharArray() : new char[ 0 ];
try
{
kmf.init( keystore, passChars );
}
finally
{
Arrays.fill( passChars, (char)0 );
}
final TrustManagerFactory tmf =
TrustManagerFactory.getInstance( provider );
tmf.init( keystore );
final SSLContext result = SSLContext.getInstance( protocol );
result.init( kmf.getKeyManagers(),
tmf.getTrustManagers(),
new java.security.SecureRandom() );
return result;
}
/**
* Builds a keystore loaded from the given stream. The passphrase
* is used to verify the keystore file integrity.
* @param keyStream to load from
* @param passphrase for the store integrity verification (or null if
* integrity check is not wanted)
* @param keystoreFormat the type of keystore
* @return loaded key store
* @throws IOException if file can not be read
* @throws GeneralSecurityException if key store can't be built
*/
private static KeyStore loadKeystore( InputStream keyStream,
String passphrase,
String keystoreFormat )
throws GeneralSecurityException, IOException
{
final KeyStore ks = KeyStore.getInstance( keystoreFormat );
if( passphrase != null )
{
final char[] passChars = passphrase.toCharArray();
try
{
ks.load( keyStream, passChars );
}
finally
{
Arrays.fill( passChars, (char)0 );
}
}
else
{
ks.load( keyStream, null );
}
return ks;
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/TLSServerSocketFactory.java
Index: TLSServerSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import org.apache.avalon.cornerstone.services.sockets.ServerSocketFactory;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Manufactures TLS server sockets. Configuration element inside a
* SocketManager would look like:
* <pre>
* <factory name="secure"
* class="org.apache.avalon.cornerstone.blocks.sockets.TLSServerSocketFactory" >
* <ssl-factory /> <!-- see {@link SSLFactoryBuilder} -->
* <timeout> 0 </timeout>
* <!-- With this option set to a non-zero timeout, a call to
* accept() for this ServerSocket will block for only this amount of
* time. If the timeout expires, a java.io.InterruptedIOException is
* raised, though the ServerSocket is still valid. Default value is 0. -->
* <authenticate-client>false</authenticate-client>
* <!-- Whether or not the client must present a certificate to
* confirm its identity. Defaults to false. -->
* </factory>
* </pre>
*
* @author Peter Donald
* @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
* @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
* @author <a href="mailto:">Harish Prabandham</a>
* @author <a href="mailto:">Costin Manolache</a>
* @author <a href="mailto:">Craig McClanahan</a>
* @author <a href="mailto:myfam@surfeu.fi">Andrei Ivanov</a>
* @author <a href="mailto:greg-avalon-apps at nest.cx">Greg Steuck</a>
*/
public class TLSServerSocketFactory
extends AbstractTLSSocketFactory
implements ServerSocketFactory
{
private SSLServerSocketFactory m_factory;
protected boolean m_keyStoreAuthenticateClients;
/**
* Configures the factory.
*
* @param configuration the Configuration
* @exception ConfigurationException if an error occurs
*/
public void configure( final Configuration configuration )
throws ConfigurationException
{
super.configure( configuration );
m_keyStoreAuthenticateClients =
configuration.getChild( "authenticate-client" ).getValueAsBoolean( false );
}
protected void visitBuilder( SSLFactoryBuilder builder )
{
m_factory = builder.buildServerSocketFactory();
}
/**
* Creates a socket on specified port.
*
* @param port the port
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( final int port )
throws IOException
{
final ServerSocket serverSocket = m_factory.createServerSocket( port );
initServerSocket( serverSocket );
return serverSocket;
}
/**
* Creates a socket on specified port with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( int port, int backLog )
throws IOException
{
final ServerSocket serverSocket = m_factory.createServerSocket( port, backLog );
initServerSocket( serverSocket );
return serverSocket;
}
/**
* Creates a socket on a particular network interface on specified port
* with a specified backLog.
*
* @param port the port
* @param backLog the backLog
* @param bindAddress the network interface to bind to.
* @return the created ServerSocket
* @exception IOException if an error occurs
*/
public ServerSocket createServerSocket( int port, int backLog, InetAddress bindAddress )
throws IOException
{
final ServerSocket serverSocket =
m_factory.createServerSocket( port, backLog, bindAddress );
initServerSocket( serverSocket );
return serverSocket;
}
protected void initServerSocket( final ServerSocket serverSocket )
throws IOException
{
final SSLServerSocket socket = (SSLServerSocket)serverSocket;
// Set client authentication if necessary
socket.setNeedClientAuth( m_keyStoreAuthenticateClients );
// Sets socket timeout
socket.setSoTimeout( m_socketTimeOut );
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/TLSSocketFactory.java
Index: TLSSocketFactory.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation
* Licensed 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.avalon.cornerstone.blocks.sockets;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.avalon.cornerstone.services.sockets.SocketFactory;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Contextualizable;
/**
* Manufactures TLS client sockets. Configuration element inside a
* SocketManager would look like:
* <pre>
* <factory name="secure"
* class="org.apache.avalon.cornerstone.blocks.sockets.TLSSocketFactory" >
* <ssl-factory /> <!-- see {@link SSLFactoryBuilder} -->
* <timeout> 0 </timeout>
* <!-- if the value is greater than zero, a read() call on the
* InputStream associated with this Socket will block for only this
* amount of time in milliseconds. Default value is 0. -->
* <verify-server-identity>true|false</verify-server-identity>
* <!-- whether or not the server identity should be verified.
* Defaults to false. -->
* </factory>
* </pre>
* <p>
* Server identity verification currently includes only comparing the
* certificate Common Name received with the host name in the
* passed address. Identity verification requires that SSL
* handshake is completed for the socket, so it takes longer
* to get a verified socket (and won't play well with non-blocking
* application like SEDA).
* </p>
* <p>
* Another thing to keep in mind when using identity verification is
* that <tt>InetAddress</tt> objects for the remote hosts should be
* built using {@link java.net.InetAddress#getByName} with
* the host name (matching the certificate CN) as the
* argument. Failure to do so may cause relatively costly DNS lookups
* and false rejections caused by inconsistencies between forward and
* reverse resolution.
* </p>
*
* @author Peter Donald
* @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
* @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
* @author <a href="mailto:">Harish Prabandham</a>
* @author <a href="mailto:">Costin Manolache</a>
* @author <a href="mailto:">Craig McClanahan</a>
* @author <a href="mailto:myfam@surfeu.fi">Andrei Ivanov</a>
* @author <a href="mailto:greg-avalon-apps at nest.cx">Greg Steuck</a>
*/
public class TLSSocketFactory
extends AbstractTLSSocketFactory
implements SocketFactory, Contextualizable, Configurable, Initializable
{
private SSLSocketFactory m_factory;
private boolean m_verifyServerIdentity;
/**
* Configures the factory.
*
* @param configuration the Configuration
* @exception ConfigurationException if an error occurs
*/
public void configure( final Configuration configuration )
throws ConfigurationException
{
super.configure( configuration );
m_verifyServerIdentity = configuration.getChild( "verify-server-identity" ).getValueAsBoolean( false );
}
protected void visitBuilder( SSLFactoryBuilder builder )
{
m_factory = builder.buildSocketFactory();
}
/**
* Performs the unconditional part of socket initialization that
* applies to all Sockets.
*/
private Socket initSocket( final Socket socket )
throws IOException
{
socket.setSoTimeout( m_socketTimeOut );
return socket;
}
/**
* Wraps an ssl socket over an existing socket and compares the
* host name from the address to the common name in the server
* certificate.
* @param bareSocket plain socket connected to the server
* @param address destination of the <tt>bareSocket</tt>
* @param port destination of the <tt>bareSocket</tt>
* @return SSL socket wrapped around original socket with server
* identity verified
*/
private SSLSocket sslWrap( Socket bareSocket, InetAddress address,
int port )
throws IOException
{
final String hostName = address.getHostName();
final SSLSocket sslSocket = (SSLSocket)
m_factory.createSocket( bareSocket, hostName, port, true );
sslSocket.startHandshake();
final SSLSession session = sslSocket.getSession();
final String DN =
session.getPeerCertificateChain()[ 0 ].getSubjectDN().getName();
final String CN = getCN( DN );
if( !hostName.equals( CN ) )
{
final String message = "Host name mismatch, expected '" +
hostName + "' recevied DN is " + DN;
throw new IOException( message );
}
if( getLogger().isDebugEnabled() )
{
final String message = "DN of the server " + DN;
getLogger().debug( message );
final String message2 = "Session id " +
bytesToString( session.getId() );
getLogger().debug( message2 );
}
return sslSocket;
}
private StringBuffer bytesToString( byte[] data )
{
final StringBuffer result = new StringBuffer( data.length * 3 );
String sep = "";
for( int i = 0; i < data.length; i++ )
{
final byte signedValue = data[ i ];
final int unsignedByteValue =
( signedValue >= 0 ) ? signedValue : 256 + signedValue;
result.append( sep )
.append( Integer.toHexString( unsignedByteValue ) );
sep = ":";
}
return result;
}
/**
* Extracts the Common Name from the given Distinguished
* Name. Normally CN is the first part of the DN.
* <b>If you know of a more direct way to determine the CN,
* please let us know</b>.
*
* @return the common name or null if DN is malformed
*/
private String getCN( String DN )
{
final int startOfCN = DN.indexOf( "CN=" );
if( startOfCN < 0 )
{
return null;
}
final int startOfHostName = startOfCN + "CN=".length();
final int endOfHostName = DN.indexOf( ',', startOfHostName );
if( endOfHostName > 0 )
{
return DN.substring( startOfHostName, endOfHostName );
}
else
{
return null;
}
}
/**
* Creates a socket connected to the specified remote address.
*
* @param address the remote address
* @param port the remote port
* @return the socket
* @exception IOException if an error occurs
*/
public Socket createSocket( InetAddress address, int port ) throws IOException
{
// Uses 2 different approaches to socket construction, due to
// sslWrap dependency on wrapping createSocket which in turn
// requires that address be resolved to the host name.
if( m_verifyServerIdentity )
{
return sslWrap( initSocket( new Socket( address, port ) ),
address, port );
}
else
{
return initSocket( m_factory.createSocket( address, port ) );
}
}
/**
* Creates a socket and connected to the specified remote address
* originating from specified local address.
*
* @param address the remote address
* @param port the remote port
* @param localAddress the local address
* @param localPort the local port
* @return the socket
* @exception IOException if an error occurs
*/
public Socket createSocket( final InetAddress address,
final int port,
final InetAddress localAddress,
final int localPort )
throws IOException
{
// Uses 2 different approaches to socket construction, due to
// sslWrap dependency on wrapping createSocket which in turn
// requires that address be resolved to the host name.
if( m_verifyServerIdentity )
{
return sslWrap( initSocket( new Socket( address, port,
localAddress,
localPort ) ),
address, port );
}
else
{
return initSocket( m_factory.createSocket( address, port ) );
}
}
}
1.1 avalon-components/cornerstone/sockets/impl/src/java/org/apache/avalon/cornerstone/blocks/sockets/package.html
Index: package.html
===================================================================
<body>
Default implementation of a sockets manager.
</body>
---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org