1 package com.terradue.jcatalogue.client.internal.ahc;
2
3 import static com.terradue.jcatalogue.client.internal.lang.Assertions.checkArgument;
4 import static com.terradue.jcatalogue.client.internal.lang.Assertions.checkNotNull;
5 import static java.util.Arrays.asList;
6
7 import java.io.File;
8 import java.net.URI;
9 import java.security.KeyStore;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16
17 import javax.net.ssl.KeyManager;
18 import javax.net.ssl.KeyManagerFactory;
19 import javax.net.ssl.SSLContext;
20 import javax.net.ssl.TrustManager;
21
22 import org.apache.commons.ssl.KeyMaterial;
23
24 import com.ning.http.client.AsyncHandler;
25 import com.ning.http.client.AsyncHttpClient;
26 import com.ning.http.client.AsyncHttpClientConfig;
27 import com.ning.http.client.Cookie;
28 import com.ning.http.client.Realm;
29 import com.ning.http.client.RequestBuilder;
30 import com.ning.http.client.resumable.ResumableIOExceptionFilter;
31 import com.terradue.jcatalogue.client.HttpAuthScheme;
32 import com.terradue.jcatalogue.client.HttpMethod;
33 import com.terradue.jcatalogue.client.Parameter;
34
35
36
37
38 public final class HttpInvoker
39 {
40
41 private final Map<String, Realm> realms = new HashMap<String, Realm>();
42
43 private final List<KeyManager> keyManagers = new ArrayList<KeyManager>();
44
45 private final TrustManager[] trustManagers = new TrustManager[] { new DummyTrustManager() };
46
47 private final ConcurrentMap<String, ConcurrentMap<String, Cookie>> cookiesRegistry = new ConcurrentHashMap<String, ConcurrentMap<String, Cookie>>();
48
49 private final ConcurrentMap<String, UmSsoAccess> umSsoCredentials = new ConcurrentHashMap<String, UmSsoAccess>();
50
51 private final AsyncHttpClient httpClient;
52
53 public HttpInvoker()
54 {
55 SSLContext context = null;
56 try
57 {
58 context = SSLContext.getInstance( "TLS" );
59 context.init( new KeyManager[] {}, trustManagers, null );
60 }
61 catch ( Exception e )
62 {
63 throw new IllegalStateException( "Impossible to initialize SSL context", e );
64 }
65
66 int timeout = 45 * 60 * 60 * 1000;
67
68 httpClient = new AsyncHttpClient( new AsyncHttpClientConfig.Builder()
69 .setRequestTimeoutInMs( timeout )
70 .setAllowPoolingConnection( true )
71 .addIOExceptionFilter( new ResumableIOExceptionFilter() )
72 .setMaximumConnectionsPerHost( 10 )
73 .setMaximumConnectionsTotal( 100 )
74 .addResponseFilter( new UmSsoStatusResponseFilter( umSsoCredentials,
75 cookiesRegistry ) )
76 .setFollowRedirects( true )
77 .setMaximumNumberOfRedirects( Integer.MAX_VALUE )
78 .setSSLContext( context )
79 .build() );
80 }
81
82 public <T> T invoke( HttpMethod httpMethod, URI uri, AsyncHandler<T> handler, Parameter...parameters )
83 {
84 checkNotNull( uri, "Input URI cannot be null" );
85
86 RequestBuilder requestBuilder = new RequestBuilder( httpMethod.toString() ).setUrl( uri.toString() );
87
88
89 Map<String, Cookie> domainCookies = cookiesRegistry.get( uri.getHost() );
90 if ( domainCookies != null && !domainCookies.isEmpty() )
91 {
92 for ( Cookie cookie : domainCookies.values() )
93 {
94 requestBuilder.addCookie( cookie );
95 }
96 }
97
98
99 for ( Parameter parameter : parameters )
100 {
101 if ( HttpMethod.GET == httpMethod )
102 {
103 requestBuilder.addQueryParameter( parameter.getName(), parameter.getValue() );
104 }
105 else
106 {
107 requestBuilder.addParameter( parameter.getName(), parameter.getValue() );
108 }
109 }
110
111
112 if ( realms.containsKey( uri.getHost() ) )
113 {
114 requestBuilder.setRealm( realms.get( uri.getHost() ) );
115 }
116
117 try
118 {
119 return httpClient.executeRequest( requestBuilder.build(), handler ).get();
120 }
121 catch ( Exception e )
122 {
123 throw new RuntimeException( "An error occurred while invoking " + uri, e );
124 }
125 }
126
127 public void registerRealm( String host, String username, String password, boolean preemptive, HttpAuthScheme authScheme )
128 {
129 host = checkNotNull( host, "host cannot be null" );
130 username = checkNotNull( username, "username cannot be null" );
131 password = checkNotNull( password, "password cannot be null" );
132 authScheme = checkNotNull( authScheme, "authScheme cannot be null" );
133
134 realms.put( host, new Realm.RealmBuilder()
135 .setPrincipal( username )
136 .setPassword( password )
137 .setUsePreemptiveAuth( preemptive )
138 .setScheme( authScheme.getAuthScheme() )
139 .build() );
140 }
141
142 public void registerSSLProxy( File proxyCertificate )
143 {
144 registerSSLCerificates( proxyCertificate, proxyCertificate, null );
145 }
146
147
148
149
150 public void registerSSLCerificates( File sslCertificate, File sslKey, String sslPassword )
151 {
152 checkFile( sslCertificate );
153 checkFile( sslKey );
154
155 if ( sslPassword == null )
156 {
157 sslPassword = "";
158 }
159
160 final char[] password = sslPassword.toCharArray();
161
162 try
163 {
164 final KeyStore store = new KeyMaterial( sslCertificate, sslKey, password ).getKeyStore();
165 store.load( null, password );
166
167
168 final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( "SunX509" );
169
170 keyManagerFactory.init( store, password );
171
172 keyManagers.addAll( asList( keyManagerFactory.getKeyManagers() ) );
173
174 httpClient.getConfig().getSSLContext().init( keyManagers.toArray( new KeyManager[keyManagers.size()] ),
175 trustManagers,
176 null );
177 }
178 catch ( Exception e )
179 {
180 throw new IllegalStateException( "Impossible to initialize SSL certificate/key", e );
181 }
182 }
183
184 private static void checkFile( File file )
185 {
186 checkArgument( file.exists(), "File %s not found, please verify it exists", file );
187 checkArgument( !file.isDirectory(), "File %s must be not a directory", file );
188 }
189
190 public void registerUmSsoAccess( String loginFormUrl, HttpMethod httpMethod, Parameter...parameters )
191 {
192 loginFormUrl = checkNotNull( loginFormUrl, "loginFormUrl cannot be null" );
193
194 registerUmSsoCredentials( URI.create( loginFormUrl ), httpMethod, parameters );
195 }
196
197 public void registerUmSsoCredentials( URI loginFormUrl, HttpMethod httpMethod, Parameter...parameters )
198 {
199 loginFormUrl = checkNotNull( loginFormUrl, "loginFormUrl cannot be null" );
200 httpMethod = checkNotNull( httpMethod, "httpMethod cannot be null" );
201 parameters = checkNotNull( parameters, "loginFormUrl cannot be null" );
202
203 umSsoCredentials.put( loginFormUrl.getHost(), new UmSsoAccess( loginFormUrl, httpMethod, parameters ) );
204 }
205
206 public void shutDown()
207 {
208 httpClient.close();
209 }
210
211 }