How to avoid adding principal in glassfish-web.xml file when using auth-method=CLIENT-CERT?

1.3k Views Asked by At

I have just started writing a web application for Glassfish 4.1 and I've started of with the security stuff.

Users accessing the application will identify them self with a client certificate. I created a self-signed root CA. Added this root CA to domain-dir/config/cacerts.jks. Created a client certificate, signed it with root CA and added it to my web browser.

web.xml:

<web-app>
  <!-- other stuff -->
  <security-constraint>
    <web-resource-collection>
        <web-resource-name>foo</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>operator</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
  </security-constraint>
  <login-config>
    <auth-method>CLIENT-CERT</auth-method>
  </login-config>
  <security-role>
    <role-name>operator</role-name>
  </security-role>
</web-app>

glassfish-web.xml:

<glassfish-web-app>
  <context-root>/foo</context-root>
  <security-role-mapping>
    <role-name>operator</role-name>
    <principal-name>CN=user</principal-name>
  </security-role-mapping>
</glassfish-web-app>

This works, but I don't want to have to add a principal-name in glassfish-web.xml for each new user. I would like to fetch that information from a database together with group information for each user.

I have looked into and tried to write my own realm extending com.sun.appserv.security.AppservRealm.I have added the realm in the proper way, but it can only be used if I set auth-method in web.xml to BASIC. Using CLIENT-CERT will ignore the realm-name element:

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>my-realm</realm-name>
</login-config>

<login-config>
  <auth-method>CLIENT-CERT</auth-method>
  <realm-name>my-realm</realm-name>
</login-config>

In the second case, the pre-defined realm 'certificate' will be used. And using BASIC will obviously not use a client certificate.

There is another way and that is to modify domain-dir/config/domain.xml and replace

...
<config name="server-config">
  ...
  <security-service>
    ...
    <auth-realm classname="com.sun.enterprise.security.auth.realm.certificate.CertificateRealm" name="certificate"></auth-realm>

with

...
<config name="server-config">
  ...
  <security-service>
    ...
    <auth-realm classname="org.foo.MyCertificateRealm" name="certificate"></auth-realm>

But that doesn't help either. I get the following warning in the log: "Certificate authentication requires certificate realm." Googling told me that the used realm must be an instance of CertificateRealm and I take it it means com.sun.enterprise.security.auth.realm.certificate.CertificateRealm, but that class is final, so I can't extend it.

Is there no way to have your principals and their groups defined somewhere else than in glassfish-web.xml? Should I ditch Glassfish and use something else, like JBoss?

EDIT 2015-03-31:

Soon after asking this question I tried out Jetty and there I managed to do what I wanted to do. I was even able to combine CLIENT-CERT authentication with FORM authentication in a way that if the client doesn't provide a valid certificate, the user is re-directed to a form based log-in page and can authenticate herself with a user name and password.

Roles are then added to the user at the time of authentication so that Jetty can control access to resources.

If control of role-assignment to a user in Glassfish in CLIENT-CERT mode can be accomplished without having to add each user to glassfish-web.xml, but to be able to pull this information from e.g. a data base, and allowing Glassfish to control access to resources is still a valid question. But I'm in no hurry to receive an answer.

1

There are 1 best solutions below

1
On

I got the same problem and resolve it whith this link: here

Just use the property assign-groups in the domain.xml file like that:

<auth-realm classname="com.sun.enterprise.security.auth.realm.certificate.CertificateRealm" name="certificate"> <property name="assign-groups" value="allusers"></property> </auth-realm>

allusers will be the group dynamically created for all users who successfully log in with a valid certificate.

Replace the principal tag and value, by the group-name tag and value as allusers. So you will have to just modify your glassfish-web.xml like that:

<glassfish-web-app>
  <context-root>/foo</context-root>
  <security-role-mapping>
    <role-name>operator</role-name>
    <group-name>allusers</group-name>
  </security-role-mapping>
</glassfish-web-app>

No need to add Principals in the web.xml. You can after check in a Servlet which certificate is connected by retrieving it with:

X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");

and check the DN part with something like:

String dn = certs[0].getSubjectX500Principal().getName();

Hope it helps.Thanks!