Hi,
The problem I reached is quite specific. I've searched Internet for any
hint but without success. So I would like to ask you for any pointers.

I have two tomcat servers "A" and "B":

A - tomcat 7.0.41 (local machine Linux Mint 15)
B - tomcat 7.0.42 (Ubuntu 12.04.2 on AWS EC2)

************************************************************************************************************************

In B I have defined REST service:

web.xml:
...

<servlet>
  <servlet-name>service</servlet-name>

<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
  <param-name>jersey.config.server.provider.packages</param-name>
  <param-value>com.systemincloud.machine.connector.service.cmd</param-value>
  </init-param>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>

<param-value>com.systemincloud.machine.connector.service.Service</param-value>
    </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>service</servlet-name>
  <url-pattern>/service/*</url-pattern>
</servlet-mapping>

server.xml:
<Connector port="443" protocol="HTTP/1.1"
                  SSLEnabled="true" ciphers="SSL_RSA_WITH_RC4_128_SHA"
                  maxThreads="150" scheme="https" secure="true"
          clientAuth="false" sslProtocol="TLS" keystorePass="******"
          truststoreFile="../.truststore" truststorePass="******"/>

The first REST request to B is coming from server A. I am using
jersey-client-2.0.jar:
public String newInstance(String dns, String fileName, InputStream file,
Map<String, String> parameters) {
    WebTarget service = getService(dns);
    FormDataMultiPart multiPart = new FormDataMultiPart();
    multiPart.field("fileName", fileName);
    multiPart.bodyPart(new FormDataBodyPart("model", file,
MediaType.APPLICATION_OCTET_STREAM_TYPE));
    Form f = new Form(new MultivaluedHashMap<String, String>(parameters));
    multiPart.field("parameters", f,
MediaType.APPLICATION_FORM_URLENCODED_TYPE);
    NewInstanceResponse response =
service.path(PATH).path("newInstance").request(MediaType.APPLICATION_JSON).post(Entity.entity(multiPart,
MediaType.MULTIPART_FORM_DATA_TYPE), NewInstanceResponse.class);
    return response.getSystemInstanceId();
}

In InputStream I have a file (jar) from local hardrive.

And I have no problems with such a configuration and application work as
expected. In wireshark I get:
After a lot of:
5173 77.673830000 192.168.30.144 54.229.*.* TCP 1514 [TCP segment of a
reassembled PDU]
I get (however only this POST wireshark is not decrypting):
52215 110.765747000 54.229.*.* 192.168.30.144 HTTP 312 HTTP/1.1 200 OK
 (application/json)

****************************************************************************************************************************

Problem starts when I configure ssl client authentication for REST service:
web.xml
...
<security-constraint>
  <web-resource-collection>
  <web-resource-name>Service Api</web-resource-name>
  <url-pattern>/service/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  <role-name>sic-service</role-name>
  </auth-constraint>
</security-constraint>
<login-config>
  <auth-method>CLIENT-CERT</auth-method>
  <realm-name>Service Api</realm-name>
</login-config>
<security-role>
    <role-name>sic-service</role-name>
</security-role>
...

tomcat-users.xml:
...
<role rolename="sic-service"/>
    <role rolename="manager-script"/>
  <user username="CN=*.*.*.*, OU=System in Cloud, O=System in Cloud,
L=Cracow, ST=Malopolskie, C=PL"
  password="null"
             roles="sic-service"/>
...

In server A I have:
X509KeyManager dkms = null;
try {
  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(new FileInputStream(new File(keystore_path)),
keystore_password.toCharArray());
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509",
"SunJSSE");
  kmf.init(ks, keystore_password.toCharArray());
    KeyManager kms[] = kmf.getKeyManagers();
    for (int i = 0; i < kms.length; i++) {
        if (kms[i] instanceof X509KeyManager) dkms = (X509KeyManager)
kms[i];
    }
} catch (KeyStoreException | NoSuchAlgorithmException |
CertificateException| IOException | NoSuchProviderException |
UnrecoverableKeyException e1) {
    e1.printStackTrace();
}
KeyManager defaultKms[] = new KeyManager[] { dkms };
TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers(){return null;}
    public void checkClientTrusted(X509Certificate[] certs, String
authType){}
    public void checkServerTrusted(X509Certificate[] certs, String
authType){}
}};
SSLContext sc = null;
try {
  sc = SSLContext.getInstance("TLS");
  sc.init(defaultKms, trustAllCerts, new SecureRandom());
} catch (Exception e) {
  e.printStackTrace();
}
client = ClientBuilder.newBuilder()
                              .withConfig(config)
                              .hostnameVerifier(new HostnameVerifier() {
@Override public boolean verify(String hostname, SSLSession session) {
return true; } })
  .sslContext(sc)
                               .build();


I tested authetication with WizTools REST Client 3.2. however with REST
requests without multipart form.

Now. When I run above application on server A

In wireshark I have:
around only 40
439 15.718628000 192.168.30.144 54.229.101.121 TCP 1514 [TCP segment of a
reassembled PDU]
then 7 times
475 15.808478000 192.168.30.144 54.229.101.121 TLSv1 1514 Ignored Unknown
Record
then
486 15.835327000 54.229.101.121 192.168.30.144 HTTP 1282 HTTP/1.1 401
Unauthorized  (text/html)
487 15.851888000 54.229.101.121 192.168.30.144 HTTP 235 HTTP/1.1 400 Bad
Request

And there is one re-transmission of whole communication (with Key Exchange)
with the same result.

In server A, I have error:
SEVERE: Servlet.service() for servlet [API] in context with path [] threw
exception [javax.ws.rs.ProcessingException: java.io.IOException: Error
writing to server] with root cause
java.io.IOException: Error writing to server
at
sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:625)
at
sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:637)
at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1320)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
at
sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
at
org.glassfish.jersey.client.HttpUrlConnector._apply(HttpUrlConnector.java:293)
at
org.glassfish.jersey.client.HttpUrlConnector.apply(HttpUrlConnector.java:200)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:215)
at
org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:650)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:421)
at
org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:646)
at
org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:402)
at
org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:305)
at
com.systemincloud.service.cmd.MachineClient.newInstance(MachineClient.java:117)
at
com.systemincloud.service.cmd.NewInstanceExecutor.execute(NewInstanceExecutor.java:28)
at
com.systemincloud.service.connector.cmd.NewInstanceCmd.post(NewInstanceCmd.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at
org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
        ...

In server B I have:
catalina.out:
...
Aug 21, 2013 1:28:37 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 10522 ms
Aug 21, 2013 1:29:38 PM org.apache.coyote.http11.AbstractHttp11Processor
process
INFO: Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at
DEBUG level.

localhost.2013-08-21.log
Aug 21, 2013 1:28:34 PM org.apache.catalina.core.StandardContext
listenerStart
FINE: Sending application start events
Aug 21, 2013 1:28:34 PM org.apache.catalina.core.StandardContext filterStart
FINE: Starting filters
Aug 21, 2013 1:29:38 PM org.apache.catalina.authenticator.SSLAuthenticator
authenticate
FINE:  Looking up certificates
Aug 21, 2013 1:29:38 PM org.apache.catalina.authenticator.SSLAuthenticator
authenticate
FINE:  Looking up certificates

localhost_access_log.2013-08-21.txt:
91.198.177.112 - - [21/Aug/2013:13:29:38 +0000] "POST /service/newInstance
HTTP/1.1" 401 1037
91.198.177.112 - - [21/Aug/2013:13:29:38 +0000] "??
)????>H??^Tj??)c??^S??\%^R?????*??;,? ^D0(? ^DsE??+?^NlZF2^L?Bk?" 400 -
91.198.177.112 - - [21/Aug/2013:13:29:38 +0000] "POST /service/newInstance
HTTP/1.1" 401 1037
91.198.177.112 - - [21/Aug/2013:13:29:38 +0000] "??
)????>H??^Tj??)c??^S??\%^R?????*??;,? ^D0(? ^DsE??+?^NlZF2^L?Bk?" 400 -


**********************************************************************************
Other observations:
 + Non multipart requests work with no problems.
 + problems do not depend on type of file content (tried txt, jar), name or
size (tried from 800kB to 50 MB);
 + If just before multipart request I do simple request:
WebTarget service = getService(dns);
service.path(PATH).path("newToken").request(MediaType.APPLICATION_JSON)
           .post(Entity.entity(new NewTokenRequest(token),
MediaType.APPLICATION_JSON), NewTokenResponse.class);
the next multipart request is correctly received on server B. And this is
for me a workaround for today.

My knowledge of SSL is basic so I still haven't done deeper analyse in
protocol. Can you give me some directions what can I try to solve my
problem.

Thank you,

Marek






-- 
Marek Jagielski
+48 513 402 596

Reply via email to