iterate any attribute in multi-valued RDN to find the correct one (#14283)
Closes #14280
This commit is contained in:
parent
fd28cd2d4b
commit
ba66fe84fa
4 changed files with 108 additions and 9 deletions
|
@ -21,7 +21,9 @@ package org.keycloak.authentication.x509;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.Principal;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
|
@ -40,9 +42,12 @@ public abstract class CertificateIdentityExtractorTest {
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
|
private static final String UPN_CERT_PATH = "/certs/UPN-cert.pem";
|
||||||
|
private static final String ANS_CERT_PATH = "/certs/ANS-cert.pem";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtractsCertInPemFormat() throws Exception {
|
public void testExtractsCertInPemFormat() throws Exception {
|
||||||
X509Certificate x509Certificate = getCertificate();
|
X509Certificate x509Certificate = getCertificate(UPN_CERT_PATH);
|
||||||
|
|
||||||
String certificatePem = PemUtils.encodeCertificate(x509Certificate);
|
String certificatePem = PemUtils.encodeCertificate(x509Certificate);
|
||||||
|
|
||||||
|
@ -56,7 +61,7 @@ public abstract class CertificateIdentityExtractorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtractsCertInSubjectDNFormat() throws Exception {
|
public void testExtractsCertInSubjectDNFormat() throws Exception {
|
||||||
X509Certificate x509Certificate = getCertificate();
|
X509Certificate x509Certificate = getCertificate(UPN_CERT_PATH);
|
||||||
|
|
||||||
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getX500NameExtractor("CN", certs -> {
|
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getX500NameExtractor("CN", certs -> {
|
||||||
return certs[0].getSubjectX500Principal();
|
return certs[0].getSubjectX500Principal();
|
||||||
|
@ -69,7 +74,7 @@ public abstract class CertificateIdentityExtractorTest {
|
||||||
public void testX509SubjectAltName_otherName() throws Exception {
|
public void testX509SubjectAltName_otherName() throws Exception {
|
||||||
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getSubjectAltNameExtractor(0);
|
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getSubjectAltNameExtractor(0);
|
||||||
|
|
||||||
X509Certificate cert = getCertificate();
|
X509Certificate cert = getCertificate(UPN_CERT_PATH);
|
||||||
|
|
||||||
Object upn = extractor.extractUserIdentity(new X509Certificate[] { cert});
|
Object upn = extractor.extractUserIdentity(new X509Certificate[] { cert});
|
||||||
Assert.assertEquals("test-user@some-company-domain", upn);
|
Assert.assertEquals("test-user@some-company-domain", upn);
|
||||||
|
@ -80,18 +85,34 @@ public abstract class CertificateIdentityExtractorTest {
|
||||||
public void testX509SubjectAltName_email() throws Exception {
|
public void testX509SubjectAltName_email() throws Exception {
|
||||||
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getSubjectAltNameExtractor(1);
|
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getSubjectAltNameExtractor(1);
|
||||||
|
|
||||||
X509Certificate cert = getCertificate();
|
X509Certificate cert = getCertificate(UPN_CERT_PATH);
|
||||||
|
|
||||||
Object upn = extractor.extractUserIdentity(new X509Certificate[] { cert});
|
Object upn = extractor.extractUserIdentity(new X509Certificate[] { cert});
|
||||||
Assert.assertEquals("test@somecompany.com", upn);
|
Assert.assertEquals("test@somecompany.com", upn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private X509Certificate getCertificate() throws Exception {
|
private X509Certificate getCertificate(String resourceFilename) throws Exception {
|
||||||
InputStream is = getClass().getResourceAsStream("/certs/UPN-cert.pem");
|
InputStream is = getClass().getResourceAsStream(resourceFilename);
|
||||||
|
|
||||||
String s = StreamUtil.readString(is, Charset.defaultCharset());
|
String s = StreamUtil.readString(is, Charset.defaultCharset());
|
||||||
|
|
||||||
return PemUtils.decodeCertificate(s);
|
return PemUtils.decodeCertificate(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final Function<X509Certificate[], Principal> subject = certs -> {
|
||||||
|
return certs[0].getSubjectX500Principal();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testX509SubjectCommonName() throws Exception {
|
||||||
|
UserIdentityExtractor extractor = CryptoIntegration.getProvider().getIdentityExtractorProvider().getX500NameExtractor("CN", subject);
|
||||||
|
X509Certificate cert = getCertificate(ANS_CERT_PATH);
|
||||||
|
|
||||||
|
Object cn = extractor.extractUserIdentity(new X509Certificate[] { cert });
|
||||||
|
Assert.assertEquals("899700252580", cn);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
48
core/src/test/resources/certs/ANS-cert.pem
Normal file
48
core/src/test/resources/certs/ANS-cert.pem
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIInDCCBoSgAwIBAgIQY9r/z8gDS9zqPRI2Y+5HPjANBgkqhkiG9w0BAQsFADB/
|
||||||
|
MQswCQYDVQQGEwJGUjETMBEGA1UECgwKQVNJUC1TQU5URTEXMBUGA1UECwwOMDAw
|
||||||
|
MiAxODc1MTI3NTExFzAVBgNVBAsMDklHQy1TQU5URSBURVNUMSkwJwYDVQQDDCBU
|
||||||
|
RVNUIEFDIElHQy1TQU5URSBGT1JUIFBFUlNPTk5FUzAeFw0yMDA3MDExMjQ2NTJa
|
||||||
|
Fw0yMzA3MDExMjQ2NTJaMGkxCzAJBgNVBAYTAkZSMSMwIQYDVQQMDBpNYXNzZXVy
|
||||||
|
LUtpbsOpc2l0aMOpcmFwZXV0ZTE1MA4GA1UEBAwHS0lORS1DSDAOBgNVBCoMB05P
|
||||||
|
UkJFUlQwEwYDVQQDDAw4OTk3MDAyNTI1ODAwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||||
|
DwAwggEKAoIBAQC6dR2AtgriH1JKsEIlS6hmyYnhGozlm8cJtBZ6KZzWGP5bV1Hr
|
||||||
|
f/WZGdKUk1N0xJKnLmIN8hwhq0MfgoPipkkyIAsrxm5cZLm75j3kHv4oXwepBz4R
|
||||||
|
84OO1bYoz/ya0hny9SCLcOnM7esQMb3ElGzNeXbx6WTl5Rz1zI7auV9sNJiiTY+M
|
||||||
|
O4cWs70SwNOlzU77XGEvm4065LZKsIRnsdNnFhXedl5jBFtkr4tpBhxWlUtlXdTh
|
||||||
|
RHLCsMLmSYV20sGzNkrnZQie6dG6b8T3nxNREAWHBNolnYSqB2WmSkxpYAyX2pcB
|
||||||
|
ufZdysa/Vucw6Ub7iWBnS48zezR3JJs3jsVzAgMBAAGjggQoMIIEJDAJBgNVHRME
|
||||||
|
AjAAMB0GA1UdDgQWBBRy+GBUTgi8gcauDvl+vmdpxdct6jAfBgNVHSMEGDAWgBQ6
|
||||||
|
8ef1zuvt943JybKf7dRlKdwf/TAOBgNVHQ8BAf8EBAMCB4AwUwYDVR0gBEwwSjBI
|
||||||
|
Bg0qgXoBgVUBBwIBAQEBMDcwNQYIKwYBBQUHAgEWKWh0dHA6Ly9pZ2Mtc2FudGUu
|
||||||
|
ZXNhbnRlLmdvdXYuZnIvUEMlMjBURVNUMB8GA1UdJQQYMBYGCCsGAQUFBwMCBgor
|
||||||
|
BgEEAYI3FAICMDUGA1UdEQQuMCygKgYKKwYBBAGCNxQCA6AcDBo4Ljk5NzAwMjUy
|
||||||
|
NTgwQGNhcnRlLWNwcy5mcjCCAUAGA1UdHwSCATcwggEzMDygOqA4hjZodHRwOi8v
|
||||||
|
aWdjLXNhbnRlLmVzYW50ZS5nb3V2LmZyL0NSTC9BQ0ktRk8tUFAtVEVTVC5jcmww
|
||||||
|
gfKgge+ggeyGgelsZGFwOi8vYW5udWFpcmUtaWdjLmVzYW50ZS5nb3V2LmZyL2Nu
|
||||||
|
PVRFU1QlMjBBQyUyMElHQy1TQU5URSUyMEZPUlQlMjBQRVJTT05ORVMsb3U9VEVT
|
||||||
|
VCUyMEFDJTIwUkFDSU5FJTIwSUdDLVNBTlRFJTIwRk9SVCxvdT1JR0MtU0FOVEUl
|
||||||
|
MjBURVNULG91PTAwMDIlMjAxODc1MTI3NTEsbz1BU0lQLVNBTlRFLGM9RlI/Y2Vy
|
||||||
|
dGlmaWNhdGVyZXZvY2F0aW9ubGlzdDtiaW5hcnk/YmFzZT9vYmplY3RDbGFzcz1w
|
||||||
|
a2lDQTCB+gYDVR0uBIHyMIHvMIHsoIHpoIHmhoHjbGRhcDovL2FubnVhaXJlLWln
|
||||||
|
Yy5lc2FudGUuZ291di5mci9jbj1URVNUJTIwQUMlMjBJR0MtU0FOVEUlMjBGT1JU
|
||||||
|
JTIwUEVSU09OTkVTLG91PVRFU1QlMjBBQyUyMFJBQ0lORSUyMElHQy1TQU5URSUy
|
||||||
|
MEZPUlQsb3U9SUdDLVNBTlRFJTIwVEVTVCxvdT0wMDAyJTIwMTg3NTEyNzUxLG89
|
||||||
|
QVNJUC1TQU5URSxjPUZSP2RlbHRhcmV2b2NhdGlvbmxpc3Q7YmluYXJ5P2Jhc2U/
|
||||||
|
b2JqZWN0Q2xhc3M9cGtpQ0EwgYAGCCsGAQUFBwEBBHQwcjAmBggrBgEFBQcwAYYa
|
||||||
|
aHR0cDovL29jc3AuZXNhbnRlLmdvdXYuZnIwSAYIKwYBBQUHMAKGPGh0dHA6Ly9p
|
||||||
|
Z2Mtc2FudGUuZXNhbnRlLmdvdXYuZnIvQUMlMjBURVNUL0FDSS1GTy1QUC1URVNU
|
||||||
|
LmNlcjAPBggqgXoBRwECBQQDBAGAMA8GCCqBegFHAQICBAMCAQAwIwYIKoF6AUcB
|
||||||
|
AgMEFxMVODAyNTAwMDAwMS8yODAwMzgzNjI2MA8GCCqBegFHAQIHBAMCAUYwDQYJ
|
||||||
|
KoZIhvcNAQELBQADggIBAKczdjq7BBhOhITDS3IK09hhwpqnjrCRkiwwoDq+f0hz
|
||||||
|
K2WxEh73RGYufDxhg/wY036TRmiAnlxPJe1cvmyVbtmJDBYKhRv4qzyeiHcSwgtc
|
||||||
|
gypOyJ2GpmrwEOPi3tZpBEhj86XKPab9m5WAyCR/jCy6Md2rY+YS5M73mwpUw3MH
|
||||||
|
SUKjq2Ykp+jCqkvPeMC1kLyYpgAFuIAVHuG7H5wauZ7K4w8fiAqxrbwmErQf4eZb
|
||||||
|
6INfCgMTqvnR05sMvUHhKtYiBG4mUtuO1a6ZN0/OPnkVOOSOi+FMg4oUp8VXa5GR
|
||||||
|
X49+AObu6MaRWSQ2ipeapJGtLYozuatvvewhRe1tJ2rxLJ/rUZbzIEMYVzVUsLpV
|
||||||
|
FcnxkL/pjKgOpZxuLuVx7VUGA8Z8QExNPkrz0BIb3/k4EYwkN8f4UjusA6Q341Sg
|
||||||
|
S3p9mnTO1pTiuap9bR/sFtWvGsFdLOyhGM9NDe9gT9d5XwWZLc+SEUnkiwkF5Zm8
|
||||||
|
ibfx+t5CwIXBqJn8701VkQYFX9s4M/biIjm5N7roFS41a+EAR77ubtI5QkmQUP1z
|
||||||
|
GUbbK/SeqyKlMWkbDnKX+vYLBa/GEZEeHePop85ErHyWqvBpsNnZEzd0cfzVcwMy
|
||||||
|
T+HRcNc38tqbleNJZcD1r0tiYr1MYLF7cZrck4oqx08beq9mm3nqunEKi6cWlKvu
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -24,6 +24,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
import org.bouncycastle.asn1.ASN1TaggedObject;
|
import org.bouncycastle.asn1.ASN1TaggedObject;
|
||||||
import org.bouncycastle.asn1.DERUTF8String;
|
import org.bouncycastle.asn1.DERUTF8String;
|
||||||
|
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
|
||||||
import org.bouncycastle.asn1.x500.RDN;
|
import org.bouncycastle.asn1.x500.RDN;
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||||
|
@ -36,9 +37,11 @@ import java.io.ByteArrayInputStream;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.cert.CertificateParsingException;
|
import java.security.cert.CertificateParsingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,9 +75,21 @@ public class BCUserIdentityExtractorProvider extends UserIdentityExtractorProvi
|
||||||
RDN[] rnds = name.getRDNs(x500NameStyle);
|
RDN[] rnds = name.getRDNs(x500NameStyle);
|
||||||
if (rnds != null && rnds.length > 0) {
|
if (rnds != null && rnds.length > 0) {
|
||||||
RDN cn = rnds[0];
|
RDN cn = rnds[0];
|
||||||
|
if(cn.isMultiValued()){
|
||||||
|
AttributeTypeAndValue[] attributeTypeAndValues = cn.getTypesAndValues();
|
||||||
|
Optional<AttributeTypeAndValue> optionalFirst = Arrays.stream(attributeTypeAndValues).filter(attributeTypeAndValue -> attributeTypeAndValue.getType().getId().equals(x500NameStyle.getId())).findFirst();
|
||||||
|
if(optionalFirst.isPresent()) {
|
||||||
|
return IETFUtils.valueToString(optionalFirst.get().getValue());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
return IETFUtils.valueToString(cn.getFirst().getValue());
|
return IETFUtils.valueToString(cn.getFirst().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
import org.bouncycastle.asn1.ASN1TaggedObject;
|
import org.bouncycastle.asn1.ASN1TaggedObject;
|
||||||
import org.bouncycastle.asn1.DERUTF8String;
|
import org.bouncycastle.asn1.DERUTF8String;
|
||||||
|
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
|
||||||
import org.bouncycastle.asn1.x500.RDN;
|
import org.bouncycastle.asn1.x500.RDN;
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||||
|
@ -36,9 +37,11 @@ import java.io.ByteArrayInputStream;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.cert.CertificateParsingException;
|
import java.security.cert.CertificateParsingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,9 +75,21 @@ public class BCFIPSUserIdentityExtractorProvider extends UserIdentityExtractorP
|
||||||
RDN[] rnds = name.getRDNs(x500NameStyle);
|
RDN[] rnds = name.getRDNs(x500NameStyle);
|
||||||
if (rnds != null && rnds.length > 0) {
|
if (rnds != null && rnds.length > 0) {
|
||||||
RDN cn = rnds[0];
|
RDN cn = rnds[0];
|
||||||
|
if(cn.isMultiValued()){
|
||||||
|
AttributeTypeAndValue[] attributeTypeAndValues = cn.getTypesAndValues();
|
||||||
|
Optional<AttributeTypeAndValue> optionalFirst = Arrays.stream(attributeTypeAndValues).filter(attributeTypeAndValue -> attributeTypeAndValue.getType().getId().equals(x500NameStyle.getId())).findFirst();
|
||||||
|
if(optionalFirst.isPresent()) {
|
||||||
|
return IETFUtils.valueToString(optionalFirst.get().getValue());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
return IETFUtils.valueToString(cn.getFirst().getValue());
|
return IETFUtils.valueToString(cn.getFirst().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue