开发者

Setting up client-cert authentication with roles on Tomcat 6.0

I'm setting up a web application that uses client certificate authentication. For right now, I've just set up a test user account and a 'user' role to test authentication and authorization. I'm using a DataSourceRealm and a postgreSQL database configured as such:

<Realm className="org.apache.catalina.realm.DataSourceRealm"
    dataSourceName="jdbc/postgres" localDataSource="true"
    userTable="users" userNameCol="username" userCredCol="password"
    userRoleTable="user_roles" roleNameCol="role" />

<Resource auth="Container" type="javax.sql.DataSource" name="jdbc/postgres"
    driverClassName="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/test"
    maxActive="100" maxIdle="30" maxWait="-1"
    username="test" password="test" />

When I first set up the database and application I used FORM authentication with the following configuration in web.xml:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Test</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>

    <auth-constraint>
        <role-name>user</role-name>
    </auth-constraint>

    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/login.jsp</form-login-page>
        <form-error-page>/login-failed.jsp</form-error-page>
    </form-login-config>
</login-config>

The database contained the user: testuser and assigned the role: user. Login with FORM authentication worked as expected.

I then changed the FORM authentication method to CLIENT-CERT and set up the necessary certificates, CA, etc. The connector in server.xml is configured like this:

   <Connector SSLEnabled="true" clientAuth="true"
    maxThreads="150" port="8443" protocol="HTTP/1.1" scheme="https"
    keystoreFile="C:\Workspace\Test\keystore.jks"
    keystorePass="changeit"
    truststoreFile="C:\Workspace\Test\truststore.jks"
    truststorePass="changeit"
    secure="true" sslProtocol="TLS"/>

The user is identified in the database as "CN=testuser,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU"

If I leave the auth-constraint开发者_如何学Python specifying the "user" role I get a 403 permission denied error accessing any page. It looks like authentication succeeds but it cannot determine the user's role from the database. If I comment out the auth-constraint, authentication succeeds and I can access the protected page.

It looks like it cannot look up the user's role in the database though the only thing in the db I changed was how the username is represented. After authentication the following code:

X500Principal p = certs[0].getSubjectX500Principal();
out.println (p.getName());

produces "CN=testuser,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU" which is the value stored in the username column in the database which is also mapped to the 'user' role in the user_roles table.

test=> select * from users;
                         username                          | password
-----------------------------------------------------------+----------
 CN=testuser,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU |
(1 row)

test=> select * from user_roles;
                         username                          | role
-----------------------------------------------------------+------
 CN=testuser,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU | user
(1 row)

What else should I be doing to be able to lookup the user roles? From everything I've seen so far it looks like this should work. Thanks for any help.


I found the answer to my problem.

Even though

X500Principal p = certs[0].getSubjectX500Principal();
out.println (p.getName());

returns the subject DN as "CN=testuser,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU", turning on verbose logging on the DB shows "CN=testuser, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU" (with inserted spaces between the fields) being submitted to the database in the query.

LOG:  ... execute <unnamed>: SELECT null FROM users WHERE username = $1
parameters: $1 = 'CN=testuser, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU'
LOG:  ... execute <unnamed>: SELECT role FROM user_roles WHERE username = $1
parameters: $1 = 'CN=testuser, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU'

It seems X509Principal.getName() returns getName(X500Principal.RFC2253) where tomcat seems to be using getName(X500Principal.RFC1779). Updating the DB to use the RFC 1779 format solved my problem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜