Showing posts with label tomcat. Show all posts
Showing posts with label tomcat. Show all posts

Wednesday, January 06, 2010

Tomcat SSL configuration. Import certificate chain to keystore (emit error “keytool error: java.lang.Exception: Input not an X.509 certificate”)

I seldom use mutual authentication in the context of SSL. Recently, in our derived project (integration with MyOSG), we need to enforce use of mutual SSL authentication.

Enable client authentication in Tomcat server

At first, I enabled it in tomcat server configuration file

An important option is "clientAuth”.
Note: before this step, I have generated and imported a certificate for tomcat server.

Import user certificate

This is done by the end users who wish to access the protected services. They need to

  1. import received certificate from CA to their browser
    Actually, both the private key and certificate need to be imported.
    For Firefox, only pkcs#12 format is supported.  If the private key has been imported, you just need to import certificate whose format can be PEM, binary, etc.
  2. import server’s certificate into trusted ca repository in browser
    The aim is to make the browser trust the certificate received from remote service. It’s useful when the service certificate is not issued by a well-known top-level CA.

After those two steps, I directed my browser to the service url. Unfortunately, I got the following error:

image

After digging a little bit, I found out the cause was that tomcat server does not trust certificate sent by my browser. So the solution is simple: add certificate chain related to my certificate to tomcat keystore.

I got the certificate chain from the issuer of my certificate. It’s in PKCS#7 format and contains two certificates in the file. You can view PKCS7-formatted file using following commands:
1) openssl pkcs7 -print_certs -text < pkcs7_cert_chain.pem
2) keytool -printcert –file pkcs7_cert_chain.pem

When I tried to import it into keystore using following command
    keytool -importcert -file pkcs7_cert_chain.pem -keystore keystore -alias test-cert –trustcacerts
I got the following error
    keytool error: java.lang.Exception: Input not an X.509 certificate
I am sure keytool can recognize the file because the following command prints out information in the file correctly.
    keytool -printcert –file pkcs7_cert_chain.pem

Solution

After reading keytool manual carefully, I found following statements:

Importing a New Trusted Certificate

    Before adding the certificate to the keystore, keytool tries to verify it by attempting to construct
    a chain of trust from that certificate to a self-signed certificate (belonging to a root CA), using
    trusted certificates that are already available in the keystore.

Importing a Certificate Reply

    ……

      o If the reply is a PKCS#7 formatted certificate chain, the chain is first ordered (with the user
        certificate first and the self-signed root CA certificate last), before keytool attempts to
        match the root CA certificate provided in the reply with any of the trusted certificates in the
        keystore or the "cacerts" keystore file (if the -trustcacerts option was specified). If no match
        can be found, the information of the root CA certificate is printed out, and the user is
        prompted to verify it, e.g., by comparing the displayed certificate fingerprints with the fin-
        gerprints obtained from some other (trusted) source of information, which might be the root CA
        itself. The user then has the option of aborting the import operation. If the -noprompt option
        is given, however, there will be no interaction with the user.

So, what I was doing is to import a trusted certificate chain. This is not allowed directly. keytool just accepts cert file that includes a single certificate.

So I extracted two certificates into two files, and fed them into keytool one by one. Details:
Use command
    openssl pkcs7 -print_certs < pkcs7_cert_chain.pem
to display the two certificates in the original pkcs7 file. And then copied and pasted each cert into an individual file.

Note: when you are importing a certificate reply from a CA, certificate chain can be imported directly into keystore. However, before doing that, you must guarantee that the corresponding private key has already been imported in to the same keystore.

Monday, November 02, 2009

X connection to localhost:xx.x broken (explicit kill or server shutdown)

When I run tomcat server, I got this weird problem. It seems that tomcat tries to access GUI, which is contrary to my thought that tomcat is a background daemon.

A simple google search brought me lots of posts about this problem: http://www.google.com/search?hl=en&client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&hs=ugP&q=tomcat+connection+to+localhost%3A+broken+%28explicit+kill+or+server+shutdown%29&aq=f&oq=&aqi=

According to suggestion from this post http://bugs.mysql.com/bug.php?id=24226, I just unset environment variable *DISPLAY* in *startup.sh*.
In bash, use *unset DISPLAY*

Tuesday, June 02, 2009

H2 Exception "Database may be already in use: Locked by another process"

I wrote two Java web servlet apps (oauth consumer app, and oauth server app) both of which rely on H2 as database engine. I want H2 to be run in embedded mode instead of server mode. According to the official document, following statement should be added to web.xml

<listener>
    <listener-class>org.h2.server.web.DbStarter</listener-class>
</listener>

This class has methods that listen to the servlet context event (context initialization, context destroyed).

When I deploy just one of the two web apps to tomcat, it works fine. When I deploy both of them, following exception is thrown

Exception in thread "main" org.h2.jdbc.JdbcSQLException: Database may be already in use: Locked by another process. Possible solutions: close all other connecti on(s); use the server mode [90020-63]

I am 100% sure that those two apps use different databases. To make myself 200% sure that my code does not create or use additional databases unintentionaly, I rechecked my code many many times. But my code looks just fine. So I doubted it may be because of the H2 database engine.
Then I used command 'lsof' to list opened files by tomcat java process. Surprisingly, a database named 'test' is created under my home directory.
I reread the document http://www.h2database.com/html/tutorial.html#web_applications, and I got what I missed before.

For details on how to access the database, see the file DbStarter.java. By default the DbStarter listener opens an embedded connection using the database URL 'jdbc:h2:~/test', user name 'sa', and password 'sa'.

Code of class DbStarter can be accessed at http://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/server/web/DbStarter.java.
I am just curious about why a default database is created by class DbStarter.

Solutions
(1) remove the listener declaration in web.xml
In other words, remove
    <listener> <listener-class>org.h2.server.web.DbStarter</listener-class> </listener>
(2) change url of created database.

  <context-param>
    <param-name>db.url</param-name>
    <param-value>jdbc:h2:your_new_db_url</param-value>
  </context-param>

Sunday, May 17, 2009

Change ROOT app in Tomcat

Recently, I tried new version of shindig - shindig-1.1-SNAPSHOT-java (http://incubator.apache.org/shindig/download/index.html). It is a reference implementation for OpenSocial 0.9 spec.

The old problem (described at http://cglreport.zhenhua.info/2009/02/shindig-server-on-tomcat.html) has not been solved.
At first I wanted to try it by deploying the war as root application in tomcat.

One easy solution is to rename the war file to ROOT.war.
I used another solution.
Steps:
Deployment:
  (1) create directory <tomcat_root>/myapps
  (2) put the war file (shindig-server-1.1-SNAPSHOT.war) to the directory created in step 1.
  (3) rename the original directory ROOT. (This step may be overlooked sometimes)
Configuration:
  (1) Add file <tomcat_root>/conf/Catalina/localhost/ROOT.xml
  (2) Content of the file is

<?xml version="1.0" encoding="UTF-8"?>
<Context
    path=""
    docBase="/globalhome/zhguo/servers/apache-tomcat-6.0.18/myapps/shindig-server-1.1-SNAPSHOT.war"
    debug="0"
    reloadable="true">
</Context>
  (3) restart tomcat

Saturday, February 07, 2009

Enable/Disabl Directory Listing in Tomcat

By default, directory listing (list content of a directory instead of render a web page) is forbidden in Tomcat.

To enable it globally, modified file <tomcat>/conf/web.xml.
Default setting for default servlet is:

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

Change the param-value for parameter listings to true.

To enable it for a specific web application, add following snippet to the web.xml of the application

    <servlet>
        <servlet-name>default_new</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.DefaultServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- The mapping for the default servlet -->
    <servlet-mapping>
        <servlet-name>default_new</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
Note: servet-name can not be default because it is name of tomcat's default servlet . So you need to use a different name. Also servlet-mapping element is necessary to make it work.

Shindig server on Tomcat

Shindig can be run with built-in jetty server without problems. But after I deployed the war to Tomcat, there are some problems. I got a blank page when I tried to render a gadget. I searched for the problem, some other guys got this problem as well.

Other posts related to this problem:
http://mail-archives.apache.org/mod_mbox/incubator-shindig-dev/200805.mbox/%3C483C780B.6080802@oracle.com%3E

Finally I figured out how to make shindig work on Tomcat.
Why does not it work?
It ignores the context path. In other words, the implementation only considers the situation that the application is deployed as root application.

Two possible Solutions
(1) make shindig war the root application
Two alternative ways:
    (*) rename it to ROOT.war and deploy it to tomcat. (The original ROOT application cannot be used)
    (*) change conf/context.xml to set shindig application as root application
(2) Modify shindig configuration files <shindig>/java/common/conf/shindig.properties and <shindig>/config/container.js to add context path in all related urls.
It seems to work well. I am not sure whether there is any potential problem.

Thursday, April 10, 2008

Tomcat virtual/physical path mapping

In my web2.0 application, users can upload files to server. I want to build mapping from virtual path to physical path. It means that the resources accessed are located in a separate directory instead of tomcat sub directory.

Context container can be used to achieve that goal. Official document is here http://tomcat.apache.org/tomcat-6.0-doc/config/context.html.
In my case, I modified configuration file server.xml and insert following text into Host element:

<context crosscontext="true" docbase="E:\\temp\imgService" path="/imgService"></context>

Actually, at first, I tried to modify context.xml instead of service.xml because it is less invasive. However, it didn't work and I don't know why.

Monday, March 24, 2008

DB4O corrupts in Tomcat with Axis2

I integrated Db4o in our project. Db4o is used to persist state information of workflow. After I integrated it, it seemed to work OK. State information can be successfully stored into its object database. And information can be retrieved successfully. However, after I restarted Tomcat, Db4o corrupted during retrieval of data from database. I tried different kinds of query language Db4o supports. Unfortunately, none of these methods work.

For Native Query, the error in Tomcat log is:

java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.db4o.query.Predicate.appliesTo(Unknown Source)
    at com.db4o.inside.query.PredicateEvaluation.evaluate(Unknown Source)
    at com.db4o.Platform4.evaluationEvaluate(Unknown Source)
    at com.db4o.QConEvaluation.visit(Unknown Source)
    at com.db4o.Tree.traverse(Unknown Source)
    at com.db4o.QCandidates.filter(Unknown Source)
    at com.db4o.QConEvaluation.evaluateEvaluationsExec(Unknown Source)
    at com.db4o.QCon.evaluateEvaluations(Unknown Source)
    at com.db4o.QCandidates.evaluate(Unknown Source)
    at com.db4o.QCandidates.execute(Unknown Source)
    at com.db4o.QQueryBase.executeLocal(Unknown Source)
    at com.db4o.QQueryBase.execute1(Unknown Source)
    at com.db4o.QQueryBase.getQueryResult(Unknown Source)
    at com.db4o.QQueryBase.execute(Unknown Source)
    at com.db4o.inside.query.NativeQueryHandler.execute(Unknown Source)
    at com.db4o.YapStreamBase.query(Unknown Source)
    at com.db4o.YapStreamBase.query(Unknown Source)
    at org.cogkit.cyberaide.axis2ws.StatusDB.getStatusByUID(StatusServiceInterfaceSkeleton.java:1204)
    at org.cogkit.cyberaide.axis2ws.StatusServiceInterfaceSkeleton.getJSONStatusByUID(StatusServiceInterfaceSkeleton.java:184)
    at org.cogkit.cyberaide.axis2ws.StatusServiceInterfaceMessageReceiverInOut.invokeBusinessLogic(StatusServiceInterfaceMessageRece
iverInOut.java:80)
    at org.apache.axis2.receivers.AbstractInOutSyncMessageReceiver.invokeBusinessLogic(AbstractInOutSyncMessageReceiver.java:42)
    at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:96)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:145)
    at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:275)
    at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:120)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:595)

It seems that the error results from incompatible type conversion. I am sure I followed the instructions elaborated in the official document.

Then, I tried SODA. The output was weirder. The program could not function as I expected. State information could not be retrieved successfully. However, when I investigated tomcat log, no error report existed in log!!! So, I had no way to tell what happened under the hood. This was pretty annoying. It seemed that Db4o indeed retrieved something. However, the fields of the object retrieved are invalid.

I read almost all posts in Db4o forum/community. I tried all suggested solutions. But it still doesn't work. I tried different versions of Db4o, none of them solved my problem.

It has taken me lots of time. Currently, I am not sure whether I can solve it finally...