Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
3 |
* contributor license agreements. See the NOTICE file distributed with |
4 |
* this work for additional information regarding copyright ownership. |
5 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
6 |
* (the "License"); you may not use this file except in compliance with |
7 |
* the License. You may obtain a copy of the License at |
8 |
* |
9 |
* http://www.apache.org/licenses/LICENSE-2.0 |
10 |
* |
11 |
* Unless required by applicable law or agreed to in writing, software |
12 |
* distributed under the License is distributed on an "AS IS" BASIS, |
13 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 |
* See the License for the specific language governing permissions and |
15 |
* limitations under the License. |
16 |
*/ |
17 |
|
18 |
|
19 |
package org.apache.catalina.realm; |
20 |
|
21 |
import java.security.cert.X509Certificate; |
22 |
import java.util.Arrays; |
23 |
import java.util.List; |
24 |
|
25 |
import javax.naming.InvalidNameException; |
26 |
import javax.naming.ldap.LdapName; |
27 |
import javax.naming.ldap.Rdn; |
28 |
|
29 |
import org.apache.juli.logging.Log; |
30 |
import org.apache.juli.logging.LogFactory; |
31 |
|
32 |
|
33 |
/** |
34 |
* Implementation of <b>X509UserNameRetriever</b> that takes a user name from the Subject Field of the X509Certificate. |
35 |
* The user name is the unique part of information from the client certificate that used to identify the identity of the user. |
36 |
* The Subject field (also called Subject Distinguish Name or SubjectDN) identifies the entity associated with the public key. |
37 |
* The Subject field contains the following relevant attributes (it can also contain other attributes). |
38 |
* |
39 |
* Subject Attribute Subject Attribute Description Example |
40 |
* CN Common Name CN=Bob BobFamily |
41 |
* emailAddress Email Address emailAddress=bob@example.com |
42 |
* C Country Name C=US |
43 |
* ST State or Province Name ST=NY |
44 |
* L Locality Name L=New York |
45 |
* O Organization Name O=Work Organization |
46 |
* OU Organizational Unit Name OU=Managers |
47 |
* |
48 |
* To retrieve the user name from the subject, you can use the entire SubjectDN field or the SubjectDN attribute. |
49 |
* To retrieve the user name from entire SubjectDN field use the default constructor |
50 |
* To retrieve the user name from the SubjectDN attribute, please provide the retrieve attribute name |
51 |
* The the retrieve attribute name is a code letter based on a legend defined in the certificate itself. |
52 |
* |
53 |
* For example, the Email attribute is used to hold the User Name. |
54 |
* Please provide "e" or "emailAddress" for the constructor. |
55 |
* |
56 |
* For example, the Common Name attribute is used to hold the User Name. |
57 |
* Please provide "CN" for the constructor. |
58 |
* |
59 |
* |
60 |
*/ |
61 |
public class X509SubjectDnRetriever implements X509UserNameRetriever { |
62 |
/** |
63 |
* Logger for this class |
64 |
*/ |
65 |
protected final Log log = LogFactory.getLog(getClass()); |
66 |
|
67 |
private static final String EMAIL_SUBJECT_ATTR = "emailAddress"; |
68 |
|
69 |
|
70 |
/** |
71 |
* The value is based on a legend defined in the certificate itself. |
72 |
* It tested with the following browsers: IE, FF and Chrome |
73 |
* For new browsers may be will required to add a new legend value to the list. |
74 |
*/ |
75 |
private static final List<String> EmailOptions = Arrays.asList(EMAIL_SUBJECT_ATTR.toLowerCase(), "e") ; |
76 |
|
77 |
|
78 |
private String subjectDnAttribute = null; |
79 |
private String subjectDnAttributeConfiguration = null; |
80 |
|
81 |
protected X509SubjectDnRetriever() { |
82 |
setSubjectDnAttribute(null); |
83 |
} |
84 |
|
85 |
protected X509SubjectDnRetriever(String retrieveAttr) { |
86 |
setSubjectDnAttribute(retrieveAttr); |
87 |
} |
88 |
|
89 |
/** |
90 |
* Set the configuration for X509UserNameRetriever. The X509UserNameRetriever uses the configuration |
91 |
* to retrieve a user name from X509Certificate. |
92 |
* |
93 |
* @param x509UserNameRetrieverConfiguration |
94 |
*/ |
95 |
public void setX509UserNameRetrieverConfiguration(String x509UserNameRetrieverConfiguration) { |
96 |
setSubjectDnAttribute(x509UserNameRetrieverConfiguration); |
97 |
|
98 |
} |
99 |
/* (non-Javadoc) |
100 |
* @see org.apache.catalina.realm.X509UserNameRetriever#getUserName(java.security.cert.X509Certificate) |
101 |
*/ |
102 |
public String getUserName(X509Certificate clientCert) { |
103 |
if (log.isDebugEnabled()) { |
104 |
log.debug("getUserName(X509Certificate) - start"); |
105 |
} |
106 |
String subject = getSubjectDN(clientCert); |
107 |
String userName = null; |
108 |
|
109 |
if (subject != null) { |
110 |
if (log.isDebugEnabled()) { |
111 |
log.debug("Subject is [" + subject + "]."); |
112 |
} |
113 |
if (subjectDnAttribute == null) { |
114 |
if (log.isDebugEnabled()) { |
115 |
log.debug("subjectDnAttribute is null, so return the whole subject."); |
116 |
} |
117 |
userName = subject; |
118 |
} else { |
119 |
boolean foundUserName = false; |
120 |
try { |
121 |
LdapName ldapName = new LdapName(subject); |
122 |
List<Rdn> list = ldapName.getRdns(); |
123 |
if (list != null) { |
124 |
for (Rdn rdn : list) { |
125 |
String type = rdn.getType(); |
126 |
if (subjectDnAttribute.equalsIgnoreCase(type.toString())) { |
127 |
Object value = rdn.getValue(); |
128 |
if (value instanceof String) { |
129 |
userName = (String) value; |
130 |
foundUserName = true; |
131 |
if (log.isDebugEnabled()) { |
132 |
log.debug("Success to retreive userName [" + userName + "]."); |
133 |
} |
134 |
break; |
135 |
} |
136 |
} |
137 |
} |
138 |
} |
139 |
} catch (InvalidNameException e) { |
140 |
log.info("subject [" + subject + "] is not valid name : [" + e.getMessage() + "]."); |
141 |
} |
142 |
if (!foundUserName) { |
143 |
log.info("subject [" + subject + "] does not contain the required attribute [" + subjectDnAttributeConfiguration + "]. Return the whole subject."); |
144 |
userName = subject; |
145 |
} |
146 |
} |
147 |
|
148 |
} |
149 |
|
150 |
if (log.isDebugEnabled()) { |
151 |
log.debug("getUserName(X509Certificate) - end; Ret is [" + userName + "]."); |
152 |
} |
153 |
return userName; |
154 |
} |
155 |
|
156 |
private void setSubjectDnAttribute(String subjectDnAttributeConfiguration) { |
157 |
this.subjectDnAttributeConfiguration = subjectDnAttributeConfiguration; |
158 |
subjectDnAttribute = mapSubjectDnAttribute(subjectDnAttributeConfiguration); |
159 |
if (log.isDebugEnabled()) { |
160 |
log.debug("setSubjectDnAttribute(String) - end; subjectDnAttribute [" + subjectDnAttribute + "]; subjectDnAttributeConfiguration [" + subjectDnAttributeConfiguration + "]"); |
161 |
} |
162 |
} |
163 |
|
164 |
|
165 |
|
166 |
private String mapSubjectDnAttribute(String subjectDnAttributeConfiguration) { |
167 |
String ret = null; |
168 |
if (subjectDnAttributeConfiguration != null) { |
169 |
if (EmailOptions.contains(subjectDnAttributeConfiguration.toLowerCase())) { |
170 |
ret = EMAIL_SUBJECT_ATTR; |
171 |
} else { |
172 |
ret = subjectDnAttributeConfiguration; |
173 |
} |
174 |
} |
175 |
return ret; |
176 |
} |
177 |
|
178 |
/** |
179 |
* @param clientCert |
180 |
* @return the whole SubjectSN of the X509Certificate |
181 |
*/ |
182 |
protected String getSubjectDN(X509Certificate clientCert) { |
183 |
String subject = null; |
184 |
if (clientCert != null) { |
185 |
if ((clientCert.getSubjectDN()!= null) |
186 |
&& (clientCert.getSubjectDN().getName() != null)) { |
187 |
subject = clientCert.getSubjectDN().getName(); |
188 |
} else { |
189 |
if (log.isDebugEnabled()) { |
190 |
log.debug("Can not getSubjectDN, SubjectDN is null"); |
191 |
} |
192 |
} |
193 |
} else { |
194 |
if (log.isDebugEnabled()) { |
195 |
log.debug("Can not getSubjectDN, clientCert is null"); |
196 |
} |
197 |
} |
198 |
if (log.isDebugEnabled()) { |
199 |
log.debug("getSubjectDN(X509Certificate) - end; Ret is [" + subject + "]."); |
200 |
} |
201 |
return subject; |
202 |
|
203 |
} |
204 |
} |