1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.ctv.util;
35
36 import java.io.IOException;
37 import java.net.InetAddress;
38 import java.net.InetSocketAddress;
39 import java.net.Socket;
40 import java.net.UnknownHostException;
41 import java.security.cert.X509Certificate;
42 import java.util.ArrayList;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.StringTokenizer;
46
47 import javax.net.ssl.SSLContext;
48 import javax.net.ssl.SSLPeerUnverifiedException;
49 import javax.net.ssl.SSLSession;
50 import javax.net.ssl.SSLSocket;
51 import javax.net.ssl.SSLSocketFactory;
52 import javax.security.auth.x500.X500Principal;
53
54 import org.apache.commons.httpclient.ConnectTimeoutException;
55 import org.apache.commons.httpclient.params.HttpConnectionParams;
56 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
57 import org.springframework.util.AntPathMatcher;
58
59 public class SslContextSecureProtocolSocketFactory implements SecureProtocolSocketFactory
60 {
61
62 private SSLContext sslContext;
63 private boolean verifyHostname;
64
65 public SslContextSecureProtocolSocketFactory( SSLContext sslContext, boolean verifyHostname )
66 {
67 this.verifyHostname = true;
68 this.sslContext = sslContext;
69 this.verifyHostname = verifyHostname;
70 }
71
72 public SslContextSecureProtocolSocketFactory( SSLContext sslContext )
73 {
74 this( sslContext, true );
75 }
76
77 public SslContextSecureProtocolSocketFactory( boolean verifyHostname )
78 {
79 this( (SSLContext) null, verifyHostname );
80 }
81
82 public SslContextSecureProtocolSocketFactory( )
83 {
84 this( (SSLContext) null, true );
85 }
86
87 public synchronized void setHostnameVerification( boolean verifyHostname )
88 {
89 this.verifyHostname = verifyHostname;
90 }
91
92 public synchronized boolean getHostnameVerification( )
93 {
94 return this.verifyHostname;
95 }
96
97 public Socket createSocket( String host, int port, InetAddress clientHost, int clientPort ) throws IOException, UnknownHostException
98 {
99 SSLSocketFactory sf = this.getSslSocketFactory( );
100 SSLSocket sslSocket = (SSLSocket) sf.createSocket( host, port, clientHost, clientPort );
101 this.verifyHostname( sslSocket );
102 return sslSocket;
103 }
104
105 public Socket createSocket( String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params )
106 throws IOException, UnknownHostException, ConnectTimeoutException
107 {
108 if ( params == null )
109 {
110 throw new IllegalArgumentException( "Parameters may not be null" );
111 }
112 else
113 {
114 int timeout = params.getConnectionTimeout( );
115 Socket socket = null;
116 SSLSocketFactory socketfactory = this.getSslSocketFactory( );
117 if ( timeout == 0 )
118 {
119 socket = socketfactory.createSocket( host, port, localAddress, localPort );
120 }
121 else
122 {
123 socket = socketfactory.createSocket( );
124 InetSocketAddress localaddr = new InetSocketAddress( localAddress, localPort );
125 InetSocketAddress remoteaddr = new InetSocketAddress( host, port );
126 socket.bind( localaddr );
127 socket.connect( remoteaddr, timeout );
128 }
129
130 this.verifyHostname( (SSLSocket) socket );
131 return socket;
132 }
133 }
134
135 public Socket createSocket( String host, int port ) throws IOException, UnknownHostException
136 {
137 SSLSocketFactory sf = this.getSslSocketFactory( );
138 SSLSocket sslSocket = (SSLSocket) sf.createSocket( host, port );
139 this.verifyHostname( sslSocket );
140 return sslSocket;
141 }
142
143 public Socket createSocket( Socket socket, String host, int port, boolean autoClose ) throws IOException, UnknownHostException
144 {
145 SSLSocketFactory sf = this.getSslSocketFactory( );
146 SSLSocket sslSocket = (SSLSocket) sf.createSocket( socket, host, port, autoClose );
147 this.verifyHostname( sslSocket );
148 return sslSocket;
149 }
150
151 private void verifyHostname( SSLSocket socket ) throws SSLPeerUnverifiedException, UnknownHostException
152 {
153 synchronized( this )
154 {
155 if ( !this.verifyHostname )
156 {
157 return;
158 }
159 }
160
161 SSLSession session = socket.getSession( );
162 String hostname = session.getPeerHost( );
163
164 try
165 {
166 InetAddress.getByName( hostname );
167 }
168 catch( UnknownHostException var10 )
169 {
170 throw new UnknownHostException( "Could not resolve SSL sessions server hostname: " + hostname );
171 }
172
173 X509Certificate [ ] certs = (X509Certificate [ ]) ( (X509Certificate [ ]) session.getPeerCertificates( ) );
174 if ( certs != null && certs.length != 0 )
175 {
176 X500Principal subjectDN = certs [0].getSubjectX500Principal( );
177 List cns = this.getCNs( subjectDN );
178 boolean foundHostName = false;
179 Iterator i$ = cns.iterator( );
180 AntPathMatcher matcher = new AntPathMatcher( );
181 while ( i$.hasNext( ) )
182 {
183 String cn = (String) i$.next( );
184 if ( matcher.match( cn.toLowerCase( ), hostname.toLowerCase( ) ) )
185 {
186 foundHostName = true;
187 break;
188 }
189 }
190
191 if ( !foundHostName )
192 {
193 throw new SSLPeerUnverifiedException( "HTTPS hostname invalid: expected \'" + hostname + "\', received \'" + cns + "\'" );
194 }
195 }
196 else
197 {
198 throw new SSLPeerUnverifiedException( "No server certificates found!" );
199 }
200 }
201
202 private List<String> getCNs( X500Principal subjectDN )
203 {
204 ArrayList cns = new ArrayList( );
205 StringTokenizer st = new StringTokenizer( subjectDN.getName( ), "," );
206
207 while ( st.hasMoreTokens( ) )
208 {
209 String cnField = st.nextToken( );
210 if ( cnField.startsWith( "CN=" ) )
211 {
212 cns.add( cnField.substring( 3 ) );
213 }
214 }
215
216 return cns;
217 }
218
219 protected SSLSocketFactory getSslSocketFactory( )
220 {
221 SSLSocketFactory sslSocketFactory = null;
222 synchronized( this )
223 {
224 if ( this.sslContext != null )
225 {
226 sslSocketFactory = this.sslContext.getSocketFactory( );
227 }
228 }
229
230 if ( sslSocketFactory == null )
231 {
232 sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault( );
233 }
234
235 return sslSocketFactory;
236 }
237
238 public synchronized void setSSLContext( SSLContext sslContext )
239 {
240 this.sslContext = sslContext;
241 }
242 }