Author: kkolinko Date: Sat Jun 2 21:06:49 2012 New Revision: 1345575 URL: http://svn.apache.org/viewvc?rev=1345575&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52500 Add configurable mechanism to retrieve user names from X509 client certificates. It is backport of r1298476 with clean-ups (r1298542, r1298577, r1298590, r1298592).
Note (a small difference wrt 7.0): RealmBase.init() cannot throw a LifecycleException, so I am just logging an error when there is configuration error with X509UsernameRetrieverClassName property. Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java - copied, changed from r1345563, tomcat/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509UsernameRetriever.java - copied unchanged from r1345563, tomcat/trunk/java/org/apache/catalina/realm/X509UsernameRetriever.java Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1345575&r1=1345574&r2=1345575&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Sat Jun 2 21:06:49 2012 @@ -79,19 +79,6 @@ PATCHES PROPOSED TO BACKPORT: -0: markt - https://issues.apache.org/bugzilla/show_bug.cgi?id=52579#c8 -1: -* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52500 - Add configurable mechanism to retrieve user names from X509 client certificates. - trunk patch: http://svn.apache.org/viewvc?view=revision&revision=r1298476 - additional clean-up patches (good for markt?): - http://svn.apache.org/viewvc?view=revision&revision=r1298542 - http://svn.apache.org/viewvc?view=revision&revision=r1298577 - http://svn.apache.org/viewvc?view=revision&revision=r1298590 - http://svn.apache.org/viewvc?view=revision&revision=r1298592 - +1: schultz, fhanik - +1: markt if clean-up is also applied - +1: kkolinko: with clean-ups (r1298542, r1298577, r1298590, r1298592) - -1: - * Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52723 Correct theoretical resource leak in StandardManager http://svn.apache.org/viewvc?rev=1299036&view=rev Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties?rev=1345575&r1=1345574&r2=1345575&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties Sat Jun 2 21:06:49 2012 @@ -75,6 +75,11 @@ realmBase.notAuthenticated=Configuration realmBase.notStarted=This Realm has not yet been started realmBase.authenticateFailure=Username {0} NOT successfully authenticated realmBase.authenticateSuccess=Username {0} successfully authenticated +realmBase.gotX509Username=Got user name from X509 certificate: {0} +realmBase.createUsernameRetriever.ClassCastException=Class {0} is not an X509UsernameRetriever. +realmBase.createUsernameRetriever.ClassNotFoundException=Cannot find class {0}. +realmBase.createUsernameRetriever.InstantiationException=Cannot create object of type {0}. +realmBase.createUsernameRetriever.IllegalAccessException=Cannot create object of type {0}. userDatabaseRealm.authenticateError=Login configuration error authenticating username {0} userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0} userDatabaseRealm.noDatabase=No UserDatabase component found under key {0} Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java?rev=1345575&r1=1345574&r2=1345575&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java Sat Jun 2 21:06:49 2012 @@ -154,7 +154,17 @@ public abstract class RealmBase */ protected boolean validate = true; - + /** + * The name of the class to use for retrieving user names from X509 + * certificates. + */ + protected String x509UsernameRetrieverClassName; + + /** + * The object that will extract user names from X509 client certificates. + */ + protected X509UsernameRetriever x509UsernameRetriever; + /** * The all role mode. */ @@ -278,6 +288,28 @@ public abstract class RealmBase } + /** + * Gets the name of the class that will be used to extract user names + * from X509 client certificates. + * @return The name of the class that will be used to extract user names + * from X509 client certificates. + */ + public String getX509UsernameRetrieverClassName() { + return x509UsernameRetrieverClassName; + } + + /** + * Sets the name of the class that will be used to extract user names + * from X509 client certificates. The class must implement + * X509UsernameRetriever. + * + * @param className The name of the class that will be used to extract user names + * from X509 client certificates. + * @see X509UsernameRetriever + */ + public void setX509UsernameRetrieverClassName(String className) { + this.x509UsernameRetrieverClassName = className; + } // --------------------------------------------------------- Public Methods @@ -1213,9 +1245,14 @@ public abstract class RealmBase * Return the Principal associated with the given certificate. */ protected Principal getPrincipal(X509Certificate usercert) { - return(getPrincipal(usercert.getSubjectDN().getName())); + String username = x509UsernameRetriever.getUsername(usercert); + + if(log.isDebugEnabled()) + log.debug(sm.getString("realmBase.gotX509Username", username)); + + return(getPrincipal(username)); } - + /** * Return the Principal associated with the given user name. @@ -1359,7 +1396,14 @@ public abstract class RealmBase if (container != null) { this.containerLog = container.getLogger(); } - + + try { + x509UsernameRetriever = + createUsernameRetriever(x509UsernameRetrieverClassName); + } catch (LifecycleException ex) { + log.error(ex.getMessage(), ex); + } + initialized=true; if( container== null ) { ObjectName parent=null; @@ -1460,4 +1504,23 @@ public abstract class RealmBase } } + private static X509UsernameRetriever createUsernameRetriever(String className) + throws LifecycleException { + if(null == className || "".equals(className.trim())) + return new X509SubjectDnRetriever(); + + try { + @SuppressWarnings("unchecked") + Class<? extends X509UsernameRetriever> clazz = (Class<? extends X509UsernameRetriever>)Class.forName(className); + return clazz.newInstance(); + } catch (ClassNotFoundException e) { + throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.ClassNotFoundException", className), e); + } catch (InstantiationException e) { + throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.InstantiationException", className), e); + } catch (IllegalAccessException e) { + throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.IllegalAccessException", className), e); + } catch (ClassCastException e) { + throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.ClassCastException", className), e); + } + } } Copied: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java (from r1345563, tomcat/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java) URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java?p2=tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java&p1=tomcat/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java&r1=1345563&r2=1345575&rev=1345575&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/X509SubjectDnRetriever.java Sat Jun 2 21:06:49 2012 @@ -24,7 +24,6 @@ import java.security.cert.X509Certificat */ public class X509SubjectDnRetriever implements X509UsernameRetriever { - @Override public String getUsername(X509Certificate clientCert) { return clientCert.getSubjectDN().getName(); } Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1345575&r1=1345574&r2=1345575&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Sat Jun 2 21:06:49 2012 @@ -109,6 +109,11 @@ <code>org.apache.catalina.filters</code> package so that it is available for all web applications. (kkolinko) </add> + <add> + <bug>52500</bug>: Added configurable mechanism to retrieve user names + from X509 client certificates. Based on a patch provided by + Michael Furman. (schultz/kkolinko) + </add> <fix> <bug>52719</bug>: Fix a theoretical resource leak in the JAR validation that checks for non-permitted classes in web application JARs. (markt) Modified: tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml?rev=1345575&r1=1345574&r2=1345575&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml Sat Jun 2 21:06:49 2012 @@ -182,6 +182,14 @@ attributes.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>See the <a href="../realm-howto.html">Container-Managed Security Guide</a> for more @@ -276,6 +284,14 @@ attributes.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>See the <a href="../realm-howto.html#DataSourceRealm"> @@ -518,6 +534,14 @@ expression.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>See the <a href="../realm-howto.html">Container-Managed Security Guide</a> for more @@ -554,6 +578,14 @@ and role information.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>See the @@ -605,6 +637,14 @@ default value is <code>conf/tomcat-users.xml</code>.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>The XML document referenced by the <code>pathname</code> attribute must @@ -696,6 +736,14 @@ <code>false</code>.</p> </attribute> + <attribute name="X509UsernameRetrieverClassName" required="false"> + <p>When using X509 client certificates, this specifies the class name + that will be used to retrieve the user name from the certificate. + The class must implement the + <code>org.apache.catalina.realm.X509UsernameRetriever</code> + interface. The default is to use the certificate's SubjectDN + as the username.</p> + </attribute> </attributes> <p>See the <a href="../realm-howto.html">Container-Managed Security --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org