首先让我说这是一个美学问题。我已经解决了自己的问题,我只是对更好的方法感到好奇。
所以,我有一个证书DN,类似这样:
CN = Jimmy Blooptoop,OU = Someplace,OU = Employees,DC = Bloopsoft-Inc
现在,我想从中获取CN。在java中,除了使用Xoun9证书中的完整DN而没有使用像bouncy castle这样的第三方库时,没有原生支持可以抓取任何东西 - 我无法使用它。所以我必须解析它,这不是什么大问题。唯一让它有点棘手的事实是CN并不总是被格式化为<first name> <last name>
。通常情况下,它实际上将是<last name>, <first name> <middle initial>
。因此,在上面的例子中,CN可以是Jimmy Blooptoop或Blooptoop,Jimmy J(当然是Joop的缩写)。
在阅读了有关正则表达式的内容之后,我写了以下内容,其效果非常好:
Matcher m = Pattern.compile("CN=[A-Za-z]*[, ]*[ A-Za-z]*").matcher(dn);
if (m.find())
cn = m.group();
我只是好奇是否有看起来不像垃圾的表情。我非常有信心,因为我在阅读了正则表达式的介绍之后就已经解决了这个问题。
答案 0 :(得分:55)
javax.naming.ldap.LdapName
怎么样?
String dn = "CN=Jimmy Blooptoop,OU=Someplace,OU=Employees,DC=Bloopsoft-Inc";
LdapName ln = new LdapName(dn);
for(Rdn rdn : ln.getRdns()) {
if(rdn.getType().equalsIgnoreCase("CN")) {
System.err.println("CN is: " + rdn.getValue());
break;
}
}
这不是最漂亮的界面,因为有LdapName#getByType(String)
之类的东西缺失,但它可以省去你不得不考虑DN可能有什么奇怪功能的麻烦。
答案 1 :(得分:5)
您可以避免使用“糟糕”的表达方式。如果您已经拥有DN,则可以拆分String,然后找到CN。例如:
String dn = "CN=Jimmy Blooptoop,OU=Someplace,OU=Employees,DC=Bloopsoft-Inc";
String[] split = dn.split(",");
for (String x : split) {
if (x.contains("CN=")) {
System.out.println(x.trim());
}
}
答案 2 :(得分:5)
您可以使用Spring Frameworks LdapUtils
以如下所示的方式提取 CN :
String cn = LdapUtils.getStringValue(new LdapName(group),"cn");
或强>
不使用如下的Spring Framework:
String cn = (String)new LdapName(group).getRdns().stream().filter(rdn -> rdn.getType().equalsIgnoreCase("CN")).findFirst().get().getValue();
答案 3 :(得分:4)
如果您使用的是Spring Framework,则可以使用DistinguishedName,如下所示:
String path = "CN=Jimmy Blooptoop,OU=Someplace,OU=Employees,DC=Bloopsoft-Inc";
DistinguishedName dn = new DistinguishedName(path);
String cn = dn.getValue("cn"); // Jimmy Blooptoop
答案 4 :(得分:1)
您不应该使用上面提供的正则表达式。这些正则表达式的问题在于您不会遵循RFC 4514并且不会忽略先前转义的符号,并且可能会松散或误解专有名称。 请按照 musiKk 的建议使用 LdapName 类来正确解析专有名称。
答案 5 :(得分:0)
我解析这样的DN。您将所有属性作为属性:
Principal principal = cert.getSubjectDN();
Properties prop = new Properties();
prop.load(new StringReader(principal.getName().replaceAll(",", "\n")));
prop.list(System.out);
String CN= props.get("CN");
虽然对于ou或dc这样的重复元素不起作用。
答案 6 :(得分:0)
正则表达式,使用起来相当昂贵。对于这样一个简单的任务,它可能是一个过度杀戮。相反,您可以使用简单的字符串拆分:
String dn = ((X509Certificate) certificate).getIssuerDN().getName();
String CN = getValByAttributeTypeFromIssuerDN(dn,"CN=");
private String getValByAttributeTypeFromIssuerDN(String dn, String attributeType)
{
String[] dnSplits = dn.split(",");
for (String dnSplit : dnSplits)
{
if (dnSplit.contains(attributeType))
{
String[] cnSplits = dnSplit.trim().split("=");
if(cnSplits[1]!= null)
{
return cnSplits[1].trim();
}
}
}
return "";
}
答案 7 :(得分:0)
看起来这样可行
CertificateFactory fact = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream ("cert.pem");
X509Certificate cert = (X509Certificate) fact.generateCertificate(is);
String cn = ((X500Name)cert.getSubjectDN()).getCommonName()
答案 8 :(得分:-1)
如果我理解正确,这应该产生相同的结果,只是看起来更具可读性。 \w
匹配任何单词字符。
"CN=[\\w]*[., ]+[\\w ]*"
如果您想要更灵活的东西,可以这样做:
Matcher m = Pattern.compile("(CN=.*?),[A-Z]{2}=").matcher(dn);
if (m.find())
cn = m.group(1);
匹配“CN =”和“,XX =”之间的任何内容,其中XX是两个大写字母。 group(1)
返回第一组(括号内的匹配)。
Regexp并不像看起来那么困难!