ASF Bugzilla – Attachment 28308 Details for
Bug 52500
Improve client certificate authentication
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
x509 java code
x509.patch (text/plain), 19.34 KB, created by
Michael
on 2012-02-13 07:50:05 UTC
(
hide
)
Description:
x509 java code
Filename:
MIME Type:
Creator:
Michael
Created:
2012-02-13 07:50:05 UTC
Size:
19.34 KB
patch
obsolete
>Index: org/apache/catalina/realm/UserNameRetrieverConfiguration.java >=================================================================== >--- org/apache/catalina/realm/UserNameRetrieverConfiguration.java (revision 0) >+++ org/apache/catalina/realm/UserNameRetrieverConfiguration.java (revision 0) >@@ -0,0 +1,31 @@ >+/* >+ * Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+package org.apache.catalina.realm; >+ >+ >+/** >+ * The interface <b>UserNameRetrieverConfiguration</b> allows to configure <b>UserNameRetriever</b> >+ * >+ * @author Michael Furman >+ */ >+public interface UserNameRetrieverConfiguration { >+ /** >+ * @param userNameRetrieveConfiguration - the parameter for the <b>UserNameRetriever</b> configuration >+ */ >+ public void setX509UserNameRetrieveConfiguration(String userNameRetrieveConfiguration); >+} >Index: org/apache/catalina/realm/UserNameRetriever.java >=================================================================== >--- org/apache/catalina/realm/UserNameRetriever.java (revision 0) >+++ org/apache/catalina/realm/UserNameRetriever.java (revision 0) >@@ -0,0 +1,31 @@ >+/* >+ * Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+package org.apache.catalina.realm; >+ >+import java.security.cert.X509Certificate; >+ >+/** >+ * The interface <b>UserNameRetriever</b> defines how to retrieve a user name from X509Certificate. >+ * The user name is the unique part of information from the client certificate >+ * that used to identify the identity of the user. >+ * The interface is used to get the user name during the client certificate authentication >+ * @author Michael Furman >+ */ >+public interface UserNameRetriever { >+ String getUserName(X509Certificate clientCert); >+} >Index: org/apache/catalina/realm/SubjectDnRetriever.java >=================================================================== >--- org/apache/catalina/realm/SubjectDnRetriever.java (revision 0) >+++ org/apache/catalina/realm/SubjectDnRetriever.java (revision 0) >@@ -0,0 +1,188 @@ >+/* >+ * Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+ >+package org.apache.catalina.realm; >+ >+import java.security.cert.X509Certificate; >+import java.util.Arrays; >+import java.util.List; >+ >+import javax.naming.InvalidNameException; >+import javax.naming.ldap.LdapName; >+import javax.naming.ldap.Rdn; >+ >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+ >+ >+/** >+ * Implementation of <b>UserNameRetriever</b> that takes a user name from the Subject Field of the X509Certificate. >+ * The user name is the unique part of information from the client certificate that used to identify the identity of the user. >+ * The Subject field (also called Subject Distinguish Name or SubjectDN) identifies the entity associated with the public key. >+ * The Subject field contains the following relevant attributes (it can also contain other attributes). >+ * >+ * Subject Attribute Subject Attribute Description Example >+ * CN Common Name CN=Bob BobFamily >+ * emailAddress Email Address emailAddress=bob@example.com >+ * C Country Name C=US >+ * ST State or Province Name ST=NY >+ * L Locality Name L=New York >+ * O Organization Name O=Work Organization >+ * OU Organizational Unit Name OU=Managers >+ * >+ * To retrieve the user name from the subject, you can use the entire SubjectDN field or the SubjectDN attribute. >+ * To retrieve the user name from entire SubjectDN field use the default constructor >+ * To retrieve the user name from the SubjectDN attribute, please provide the retrieve attribute name >+ * The the retrieve attribute name is a code letter based on a legend defined in the certificate itself. >+ * >+ * For example, the Email attribute is used to hold the User Name. >+ * Please provide "e" or "emailAddress" for the constructor. >+ * >+ * For example, the Common Name attribute is used to hold the User Name. >+ * Please provide "CN" for the constructor. >+ * >+ * @author Michael Furman >+ * >+ */ >+public class SubjectDnRetriever implements UserNameRetriever { >+ /** >+ * Logger for this class >+ */ >+ protected final Log log = LogFactory.getLog(getClass()); >+ >+ private static final String EMAIL_SUBJECT_ATTR = "emailAddress"; >+ >+ >+ /** >+ * The value is based on a legend defined in the certificate itself >+ * It tested with the following browsers: IE, FF and Chrome >+ * For new browsers may be will required to add a new legend value to the list. >+ */ >+ private static final List<String> EmailOptions = Arrays.asList(EMAIL_SUBJECT_ATTR.toLowerCase(), "e") ; >+ >+ >+ private String subjectDnAttribute = null; >+ private String subjectDnAttributeConfiguration = null; >+ >+ protected SubjectDnRetriever() { >+ setSubjectDnAttribute(null); >+ } >+ >+ protected SubjectDnRetriever(String retrieveAttr) { >+ setSubjectDnAttribute(retrieveAttr); >+ } >+ >+ public String getUserName(X509Certificate clientCert) { >+ if (log.isDebugEnabled()) { >+ log.debug("getUserName(X509Certificate) - start"); >+ } >+ String subject = getSubjectDN(clientCert); >+ String userName = null; >+ >+ if (subject != null) { >+ if (log.isDebugEnabled()) { >+ log.debug("Subject is [" + subject + "]."); >+ } >+ if (subjectDnAttribute == null) { >+ if (log.isDebugEnabled()) { >+ log.debug("subjectDnAttribute is null, so return the whole subject."); >+ } >+ userName = subject; >+ } else { >+ boolean foundUserName = false; >+ try { >+ LdapName ldapName = new LdapName(subject); >+ List<Rdn> list = ldapName.getRdns(); >+ if (list != null) { >+ for (Rdn rdn : list) { >+ String type = rdn.getType(); >+ if (subjectDnAttribute.equalsIgnoreCase(type.toString())) { >+ Object value = rdn.getValue(); >+ if (value instanceof String) { >+ userName = (String) value; >+ foundUserName = true; >+ if (log.isDebugEnabled()) { >+ log.debug("Success to retreive userName [" + userName + "]."); >+ } >+ break; >+ } >+ } >+ } >+ } >+ } catch (InvalidNameException e) { >+ log.info("subject [" + subject + "] is not valid name : [" + e.getMessage() + "]."); >+ } >+ if (!foundUserName) { >+ log.info("subject [" + subject + "] does not contain the required attribute [" + subjectDnAttributeConfiguration + "]. Return the whole subject."); >+ userName = subject; >+ } >+ } >+ >+ } >+ >+ if (log.isDebugEnabled()) { >+ log.debug("getUserName(X509Certificate) - end; Ret is [" + userName + "]."); >+ } >+ return userName; >+ } >+ >+ private void setSubjectDnAttribute(String subjectDnAttributeConfiguration) { >+ this.subjectDnAttributeConfiguration = subjectDnAttributeConfiguration; >+ subjectDnAttribute = mapSubjectDnAttribute(subjectDnAttributeConfiguration); >+ if (log.isDebugEnabled()) { >+ log.debug("setSubjectDnAttribute(String) - end; subjectDnAttribute [" + subjectDnAttribute + "]; subjectDnAttributeConfiguration [" + subjectDnAttributeConfiguration + "]"); >+ } >+ } >+ >+ >+ >+ private String mapSubjectDnAttribute(String subjectDnAttributeConfiguration) { >+ String ret = null; >+ if (subjectDnAttributeConfiguration != null) { >+ if (EmailOptions.contains(subjectDnAttributeConfiguration.toLowerCase())) { >+ ret = EMAIL_SUBJECT_ATTR; >+ } else { >+ ret = subjectDnAttributeConfiguration; >+ } >+ } >+ return ret; >+ } >+ >+ protected String getSubjectDN(X509Certificate clientCert) { >+ String subject = null; >+ if (clientCert != null) { >+ if ((clientCert.getSubjectDN()!= null) >+ && (clientCert.getSubjectDN().getName() != null)) { >+ subject = clientCert.getSubjectDN().getName(); >+ } else { >+ if (log.isDebugEnabled()) { >+ log.debug("Can not getSubjectDN, SubjectDN is null"); >+ } >+ } >+ } else { >+ if (log.isDebugEnabled()) { >+ log.debug("Can not getSubjectDN, clientCert is null"); >+ } >+ } >+ if (log.isDebugEnabled()) { >+ log.debug("getSubjectDN(X509Certificate) - end; Ret is [" + subject + "]."); >+ } >+ return subject; >+ >+ } >+} >Index: org/apache/catalina/realm/UserNameRetrieverDecorator.java >=================================================================== >--- org/apache/catalina/realm/UserNameRetrieverDecorator.java (revision 0) >+++ org/apache/catalina/realm/UserNameRetrieverDecorator.java (revision 0) >@@ -0,0 +1,118 @@ >+/* >+ * Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+ >+package org.apache.catalina.realm; >+ >+import java.security.cert.X509Certificate; >+ >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+ >+/** >+ * Implementation of <b>UserNameRetriever</b> that allows to create an implementation from the class name. >+ * >+ * If the created implementation of <b>UserNameRetriever</b> not returns the user name, >+ * the UserNameRetrieverDecorator class returns the the entire SubjectDN field by defaultUserNameRetriever. >+ * >+ * @author Michael Furman >+ * >+ */ >+public class UserNameRetrieverDecorator implements UserNameRetriever { >+ private static final Log log = LogFactory >+ .getLog(UserNameRetrieverDecorator.class); >+ >+ private UserNameRetriever userNameRetriever; >+ >+ private UserNameRetriever defaultUserNameRetriever; >+ >+ private boolean createdFromClassName = false; >+ >+ /** >+ * @param x509UserNameRetrieveConfiguration - the parameter for the configuration of UserNameRetriever. >+ * @param x509UserNameRetrieverClassName - the class that implements UserNameRetriever >+ * If the x509UserNameRetrieverClassName class implements <b>UserNameRetrieverConfiguration</b>, the userNameRetrieveConfiguration value >+ * will be passed to the UserNameRetriever during the creation. >+ * The <b>UserNameRetriever</b> is used to get the user name during the client certificate authentication >+ */ >+ public UserNameRetrieverDecorator(String x509UserNameRetrieveConfiguration, String x509UserNameRetrieverClassName) { >+ super(); >+ createdFromClassName = createUserNameRetrieverFromClassName(x509UserNameRetrieverClassName); >+ if (createdFromClassName) { >+ if (userNameRetriever instanceof UserNameRetrieverConfiguration) { >+ // set the configuration to userNameRetriever >+ ((UserNameRetrieverConfiguration) userNameRetriever).setX509UserNameRetrieveConfiguration(x509UserNameRetrieveConfiguration); >+ } >+ // the defaultUserNameRetriever will be used if the created UserNameRetriever will return an empty value. >+ defaultUserNameRetriever = new SubjectDnRetriever(); >+ } else { >+ if (x509UserNameRetrieveConfiguration == null) { >+ userNameRetriever = new SubjectDnRetriever(); >+ } else { >+ userNameRetriever = new SubjectDnRetriever(x509UserNameRetrieveConfiguration); >+ } >+ } >+ } >+ >+ public String getUserName(X509Certificate clientCert) { >+ String userName = null; >+ if (createdFromClassName) { >+ userName = userNameRetriever.getUserName(clientCert); >+ if ((userName == null) || ("".equals(userName))) { >+ if (log.isDebugEnabled()) { >+ log.debug("Created userNameRetriever returns the empty user name. Returnts the user name by defaultUserNameRetriever."); >+ } >+ userName = defaultUserNameRetriever.getUserName(clientCert); >+ } >+ } else { >+ userName = userNameRetriever.getUserName(clientCert); >+ } >+ return userName; >+ } >+ >+ @SuppressWarnings("unchecked") >+ private boolean createUserNameRetrieverFromClassName(String x509UserNameRetrieverClassName) { >+ >+ boolean created = false; >+ if ((x509UserNameRetrieverClassName != null) >+ && (x509UserNameRetrieverClassName != "")) { >+ Class<? extends UserNameRetriever> x509UserNameRetrieverClass = null; >+ try { >+ x509UserNameRetrieverClass = (Class<? extends UserNameRetriever>) Class.forName(x509UserNameRetrieverClassName); >+ userNameRetriever = x509UserNameRetrieverClass.newInstance(); >+ created = true; >+ if (log.isDebugEnabled()) { >+ log.debug("Success to create userNameRetriever [" + userNameRetriever + "]."); >+ } >+ } catch (ClassCastException e) { >+ String warnString = "Class [" + x509UserNameRetrieverClassName + "] is not instance of [" + UserNameRetriever.class.getSimpleName() + "]."; >+ log.warn(warnString); >+ } catch (ClassNotFoundException e) { >+ String warnString = "Class [" + x509UserNameRetrieverClassName + "] was not found."; >+ log.warn(warnString, e); >+ } catch (InstantiationException e) { >+ String warnString = "Cannot instantiate class [" + x509UserNameRetrieverClassName + "]."; >+ log.warn(warnString); >+ } catch (IllegalAccessException e) { >+ String warnString = "Cannot instantiate class [" + x509UserNameRetrieverClassName + "]."; >+ log.warn(warnString); >+ } >+ } >+ return created; >+ } >+ >+} >Index: org/apache/catalina/realm/RealmBase.java >=================================================================== >--- org/apache/catalina/realm/RealmBase.java (revision 1243153) >+++ org/apache/catalina/realm/RealmBase.java (working copy) >@@ -150,6 +150,26 @@ > protected boolean stripRealmForGss = true; > > >+ /** >+ * The <b>UserNameRetriever</b> is used to get the user name during the client certificate authentication >+ */ >+ private UserNameRetriever userNameRetriever = null; >+ >+ >+ /** >+ * The value indicates which part of constitutes the username. >+ * The value is a code letter based on a legend defined in the certificate itself. >+ */ >+ >+ private String x509UserNameRetrieveConfiguration = null; >+ >+ /** >+ * @param className - the class that implements <b>UserNameRetriever</b> >+ * If the value is provided a realm will create UserNameRetriever. >+ * >+ */ >+ private String x509UserNameRetrieverClassName = null; >+ > // ------------------------------------------------------------- Properties > > >@@ -1034,6 +1054,8 @@ > if (container != null) { > this.containerLog = container.getLogger(); > } >+ // Create userNameRetriever for the client certificate authentication. >+ userNameRetriever = new UserNameRetrieverDecorator(x509UserNameRetrieveConfiguration, x509UserNameRetrieverClassName); > } > > /** >@@ -1191,7 +1213,12 @@ > * Return the Principal associated with the given certificate. > */ > protected Principal getPrincipal(X509Certificate usercert) { >- return(getPrincipal(usercert.getSubjectDN().getName())); >+ // get user name using userNameRetriever >+ String userName = userNameRetriever.getUserName(usercert); >+ >+ if (log.isDebugEnabled()) >+ log.debug("Get principal for [" + userName + "]"); >+ return(getPrincipal(userName)); > } > > >@@ -1390,5 +1417,22 @@ > return name; > } > } >+ >+ /* (non-Javadoc) >+ * @see org.apache.catalina.Realm#setX509UserNameRetrieveConfiguration(java.lang.String) >+ */ >+ public void setX509UserNameRetrieveConfiguration(String userNameRetrieveConfiguration) { >+ x509UserNameRetrieveConfiguration = userNameRetrieveConfiguration; >+ } > >+ /* (non-Javadoc) >+ * @see org.apache.catalina.Realm#setX509UserNameRetrieverClassName(java.lang.String) >+ */ >+ public void setX509UserNameRetrieverClassName(String className) { >+ x509UserNameRetrieverClassName = className; >+ } >+ >+ >+ >+ > } >Index: org/apache/catalina/Realm.java >=================================================================== >--- org/apache/catalina/Realm.java (revision 1243153) >+++ org/apache/catalina/Realm.java (working copy) >@@ -191,4 +191,20 @@ > public void removePropertyChangeListener(PropertyChangeListener listener); > > >+ >+ /** >+ * @param userNameRetrieveConfiguration - the parameter indicates which part of constitutes the username. >+ * The value is a code letter based on a legend defined in the certificate itself. >+ */ >+ public void setX509UserNameRetrieveConfiguration(String userNameRetrieveConfiguration); >+ >+ /** >+ * @param className - the class that implements <b>UserNameRetriever</b> >+ * If the value is provided a realm will create UserNameRetriever. >+ * If the class implements <b>UserNameRetrieverConfiguration</b>, the userNameRetrieveConfiguration value >+ * will be passed to the UserNameRetriever during the creation. >+ * The <b>UserNameRetriever</b> is used to get the user name during the client certificate authentication >+ */ >+ public void setX509UserNameRetrieverClassName(String className); >+ > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 52500
:
28190
|
28191
|
28199
|
28200
|
28237
|
28238
|
28308
|
28309
|
28348
|
28349
|
28386
|
28387
|
28450