From 43601a506d31745d1d597bb7add83ffed14ece89 Mon Sep 17 00:00:00 2001 From: Roland Weber Date: Sat, 20 Jan 2007 16:48:33 +0000 Subject: [PATCH] SocketFactory.isSecure(...) git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@498143 13f79535-47bb-0310-9956-ffa450edef68 --- .../contrib/conn/TalkativeSocketFactory.java | 9 ++++- .../apache/http/conn/PlainSocketFactory.java | 35 ++++++++++++++++++ src/java/org/apache/http/conn/Scheme.java | 24 +++++++------ .../org/apache/http/conn/SocketFactory.java | 34 ++++++++++++++++++ .../impl/DefaultSocketConnectionOperator.java | 6 ++-- .../http/conn/ssl/SSLSocketFactory.java | 36 +++++++++++++++++++ src/test/org/apache/http/conn/TestScheme.java | 4 +-- 7 files changed, 130 insertions(+), 18 deletions(-) diff --git a/src/contrib/org/apache/http/contrib/conn/TalkativeSocketFactory.java b/src/contrib/org/apache/http/contrib/conn/TalkativeSocketFactory.java index 2bc98367b..c5e041b89 100644 --- a/src/contrib/org/apache/http/contrib/conn/TalkativeSocketFactory.java +++ b/src/contrib/org/apache/http/contrib/conn/TalkativeSocketFactory.java @@ -95,12 +95,19 @@ public Socket connectSocket(Socket sock, String host, int port, HttpParams params) throws IOException { - // just delegate the call to the default + // just delegate the call to the default factory return PlainSocketFactory.getSocketFactory().connectSocket (sock, host, port, localAddress, localPort, params); } + // non-javadoc, see interface org.apache.http.conn.SocketFactory + public boolean isSecure(Socket sock) + throws IllegalArgumentException { + + return false; + } + /** * Prepares a byte for debug printing. * diff --git a/src/java/org/apache/http/conn/PlainSocketFactory.java b/src/java/org/apache/http/conn/PlainSocketFactory.java index 4b6e37da6..0b2df13ac 100644 --- a/src/java/org/apache/http/conn/PlainSocketFactory.java +++ b/src/java/org/apache/http/conn/PlainSocketFactory.java @@ -114,6 +114,41 @@ public Socket connectSocket(Socket sock, String host, int port, } // connectSocket + /** + * Checks whether a socket connection is secure. + * This factory creates plain socket connections + * which are not considered secure. + * + * @param sock the connected socket + * + * @return false + * + * @throws IllegalArgumentException if the argument is invalid + */ + public final boolean isSecure(Socket sock) + throws IllegalArgumentException { + + if (sock == null) { + throw new IllegalArgumentException("Socket may not be null."); + } + // This class check assumes that createSocket() calls the constructor + // directly. If it was using javax.net.SocketFactory, we couldn't make + // an assumption about the socket class here. + if (sock.getClass() != Socket.class) { + throw new IllegalArgumentException + ("Socket not created by this factory."); + } + // This check is performed last since it calls a method implemented + // by the argument object. getClass() is final in java.lang.Object. + if (sock.isClosed()) { + throw new IllegalArgumentException("Socket is closed."); + } + + return false; + + } // isSecure + + /** * Compares this factory with an object. * There is only one instance of this class. diff --git a/src/java/org/apache/http/conn/Scheme.java b/src/java/org/apache/http/conn/Scheme.java index fa2ee160f..a6380f94e 100644 --- a/src/java/org/apache/http/conn/Scheme.java +++ b/src/java/org/apache/http/conn/Scheme.java @@ -124,12 +124,13 @@ public static Scheme getScheme(String id) /** The default port for this scheme */ private int defaultPort; - /** True if this scheme is secure */ - private boolean secure; + /** True if this scheme allows for layered connections */ + private boolean layered; /** - * Constructs a new Protocol. Whether the created scheme is secure depends on - * the class of factory. + * Constructs a new scheme. + * Whether the created scheme allows for layered connections + * depends on the class of factory. * * @param name the scheme name (e.g. http, https) * @param factory the factory for creating sockets for communication using @@ -151,7 +152,7 @@ public Scheme(final String name, final SocketFactory factory, int defaultPort) { this.name = name; this.socketFactory = factory; this.defaultPort = defaultPort; - this.secure = (factory instanceof SecureSocketFactory); + this.layered = (factory instanceof SecureSocketFactory); } /** @@ -179,11 +180,12 @@ public String getName() { } /** - * Returns true if this scheme is secure - * @return true if this scheme is secure + * Indicates whether this scheme allows for layered connections. + * @return true if layered connections are possible, + * false otherwise */ - public boolean isSecure() { - return secure; + public boolean isLayered() { + return layered; } /** @@ -223,7 +225,7 @@ public boolean equals(Object obj) { return ( defaultPort == p.getDefaultPort() && name.equalsIgnoreCase(p.getName()) - && secure == p.isSecure() + && layered == p.isLayered() && socketFactory.equals(p.getSocketFactory())); } else { @@ -240,7 +242,7 @@ public int hashCode() { int hash = LangUtils.HASH_SEED; hash = LangUtils.hashCode(hash, this.defaultPort); hash = LangUtils.hashCode(hash, this.name.toLowerCase()); - hash = LangUtils.hashCode(hash, this.secure); + hash = LangUtils.hashCode(hash, this.layered); hash = LangUtils.hashCode(hash, this.socketFactory); return hash; } diff --git a/src/java/org/apache/http/conn/SocketFactory.java b/src/java/org/apache/http/conn/SocketFactory.java index c9ffff705..43909b640 100644 --- a/src/java/org/apache/http/conn/SocketFactory.java +++ b/src/java/org/apache/http/conn/SocketFactory.java @@ -100,4 +100,38 @@ Socket connectSocket( HttpParams params ) throws IOException, UnknownHostException, ConnectTimeoutException; + + /** + * Checks whether a socket provides a secure connection. + * The socket must be {@link #connectSocket connected} + * by this factory. + * The factory will not perform I/O operations + * in this method. + *
+ * As a rule of thumb, plain sockets are not secure and + * TLS/SSL sockets are secure. However, there may be + * application specific deviations. For example, a plain + * socket to a host in the same intranet ("trusted zone") + * could be considered secure. On the other hand, a + * TLS/SSL socket could be considered insecure based on + * the cypher suite chosen for the connection. + * + * @param sock the connected socket to check + * + * @return true if the connection of the socket + * should be considered secure, or + * false if it should not + * + * @throws IllegalArgumentException + * if the argument is invalid, for example because it is + * not a connected socket or was created by a different + * socket factory. + * Note that socket factories are not required to + * check these conditions, they may simply return a default + * value when called with an invalid socket argument. + */ + boolean isSecure(Socket sock) + throws IllegalArgumentException + ; + } diff --git a/src/java/org/apache/http/conn/impl/DefaultSocketConnectionOperator.java b/src/java/org/apache/http/conn/impl/DefaultSocketConnectionOperator.java index 4dda2b5b8..a97549a41 100644 --- a/src/java/org/apache/http/conn/impl/DefaultSocketConnectionOperator.java +++ b/src/java/org/apache/http/conn/impl/DefaultSocketConnectionOperator.java @@ -112,8 +112,7 @@ public void openConnection(UnmanagedClientConnection conn, (sock, target.getHostName(), target.getPort(), local, 0, params); prepareSocket(sock, context, params); - //@@@ ask the factory whether the new socket is secure? - boolean secure = (sf instanceof SecureSocketFactory); + final boolean secure = sf.isSecure(sock); conn.open(sock, target, secure, params); //@@@ error handling: unprepare the connection? @@ -166,8 +165,7 @@ public void updateSecureConnection(UnmanagedClientConnection conn, (conn.getSocket(), target.getHostName(), target.getPort(), true); prepareSocket(sock, context, params); - //@@@ ask the factory whether the new socket is secure? - boolean secure = true; + final boolean secure = ssf.isSecure(sock); conn.update(sock, target, secure, params); //@@@ error handling: close the layered socket in case of exception? diff --git a/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java index 212d25ce8..6c1232b94 100644 --- a/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java +++ b/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java @@ -295,6 +295,42 @@ public Socket connectSocket( return sslock; } + + /** + * Checks whether a socket connection is secure. + * This factory creates TLS/SSL socket connections + * which, by default, are considered secure. + *
+ * Derived classes may override this method to perform + * runtime checks, for example based on the cypher suite. + * + * @param sock the connected socket + * + * @return true + * + * @throws IllegalArgumentException if the argument is invalid + */ + public boolean isSecure(Socket sock) + throws IllegalArgumentException { + + if (sock == null) { + throw new IllegalArgumentException("Socket may not be null."); + } + // This instanceof check is in line with createSocket() above. + if (!(sock instanceof SSLSocket)) { + throw new IllegalArgumentException + ("Socket not created by this factory."); + } + // This check is performed last since it calls the argument object. + if (sock.isClosed()) { + throw new IllegalArgumentException("Socket is closed."); + } + + return false; + + } // isSecure + + /** * @see SecureSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) */ diff --git a/src/test/org/apache/http/conn/TestScheme.java b/src/test/org/apache/http/conn/TestScheme.java index 7acfdd201..b433c9219 100644 --- a/src/test/org/apache/http/conn/TestScheme.java +++ b/src/test/org/apache/http/conn/TestScheme.java @@ -62,12 +62,12 @@ public void testConstructor() { assertEquals("http", http.getName()); assertEquals(80, http.getDefaultPort()); assertEquals(PlainSocketFactory.getSocketFactory(), http.getSocketFactory()); - assertFalse(http.isSecure()); + assertFalse(http.isLayered()); Scheme https = new Scheme("http", SSLSocketFactory.getSocketFactory(), 443); assertEquals("http", https.getName()); assertEquals(443, https.getDefaultPort()); assertEquals(SSLSocketFactory.getSocketFactory(), https.getSocketFactory()); - assertTrue(https.isSecure()); + assertTrue(https.isLayered()); try { new Scheme(null, PlainSocketFactory.getSocketFactory(), 80);