KEYCLOAK-18744 OpenBanking Brasil fix for X509 client authentication. More flexibility in Subject DN comparison.
This commit is contained in:
parent
3c00dba8ad
commit
5740e158e3
27 changed files with 542 additions and 25 deletions
|
@ -5,11 +5,13 @@ import org.keycloak.authentication.AuthenticationFlowError;
|
||||||
import org.keycloak.authentication.ClientAuthenticationFlowContext;
|
import org.keycloak.authentication.ClientAuthenticationFlowContext;
|
||||||
import org.keycloak.models.AuthenticationExecutionModel;
|
import org.keycloak.models.AuthenticationExecutionModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.x509.X509ClientCertificateLookup;
|
import org.keycloak.services.x509.X509ClientCertificateLookup;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -17,11 +19,13 @@ import java.security.GeneralSecurityException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -31,6 +35,23 @@ public class X509ClientAuthenticator extends AbstractClientAuthenticator {
|
||||||
public static final String ATTR_PREFIX = "x509";
|
public static final String ATTR_PREFIX = "x509";
|
||||||
public static final String ATTR_SUBJECT_DN = ATTR_PREFIX + ".subjectdn";
|
public static final String ATTR_SUBJECT_DN = ATTR_PREFIX + ".subjectdn";
|
||||||
|
|
||||||
|
public static final String ATTR_ALLOW_REGEX_PATTERN_COMPARISON = ATTR_PREFIX + ".allow.regex.pattern.comparison";
|
||||||
|
|
||||||
|
// Custom OIDs defined in the OpenBanking Brasil - https://openbanking-brasil.github.io/specs-seguranca/open-banking-brasil-certificate-standards-1_ID1.html#name-client-certificate
|
||||||
|
// These are not recognized by default in RFC1779 or RFC2253 and hence not read in the java by default
|
||||||
|
private static final Map<String, String> CUSTOM_OIDS = new HashMap<>();
|
||||||
|
private static final Map<String, String> CUSTOM_OIDS_REVERSED = new HashMap<>();
|
||||||
|
static {
|
||||||
|
CUSTOM_OIDS.put("2.5.4.5", "serialNumber".toUpperCase());
|
||||||
|
CUSTOM_OIDS.put("2.5.4.15", "businessCategory".toUpperCase());
|
||||||
|
CUSTOM_OIDS.put("1.3.6.1.4.1.311.60.2.1.3", "jurisdictionCountryName".toUpperCase());
|
||||||
|
|
||||||
|
// Reverse map
|
||||||
|
for (Map.Entry<String, String> entry : CUSTOM_OIDS.entrySet()) {
|
||||||
|
CUSTOM_OIDS_REVERSED.put(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static ServicesLogger logger = ServicesLogger.LOGGER;
|
protected static ServicesLogger logger = ServicesLogger.LOGGER;
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,27 +120,42 @@ public class X509ClientAuthenticator extends AbstractClientAuthenticator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OIDCAdvancedConfigWrapper clientCfg = OIDCAdvancedConfigWrapper.fromClientModel(client);
|
||||||
String subjectDNRegexp = client.getAttribute(ATTR_SUBJECT_DN);
|
String subjectDNRegexp = client.getAttribute(ATTR_SUBJECT_DN);
|
||||||
if (subjectDNRegexp == null || subjectDNRegexp.length() == 0) {
|
if (subjectDNRegexp == null || subjectDNRegexp.length() == 0) {
|
||||||
logger.errorf("[X509ClientCertificateAuthenticator:authenticate] " + ATTR_SUBJECT_DN + " is null or empty");
|
logger.errorf("[X509ClientCertificateAuthenticator:authenticate] " + ATTR_SUBJECT_DN + " is null or empty");
|
||||||
context.attempted();
|
context.attempted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Pattern subjectDNPattern = Pattern.compile(subjectDNRegexp);
|
|
||||||
|
|
||||||
Optional<String> matchedCertificate = Arrays.stream(certs)
|
Optional<String> matchedCertificate;
|
||||||
.map(certificate -> certificate.getSubjectDN().getName())
|
|
||||||
.filter(subjectdn -> subjectDNPattern.matcher(subjectdn).matches())
|
if (clientCfg.getAllowRegexPatternComparison()) {
|
||||||
.findFirst();
|
Pattern subjectDNPattern = Pattern.compile(subjectDNRegexp);
|
||||||
|
|
||||||
|
matchedCertificate = Arrays.stream(certs)
|
||||||
|
.map(certificate -> certificate.getSubjectDN().getName())
|
||||||
|
.filter(subjectdn -> subjectDNPattern.matcher(subjectdn).matches())
|
||||||
|
.findFirst();
|
||||||
|
} else {
|
||||||
|
// OIDC/OAuth2 does not use regex comparison as it expects exact DN given in the format according to RFC4514. See RFC8705 for the details.
|
||||||
|
// We allow custom OIDs attributes to be "expanded" or not expanded in the given Subject DN
|
||||||
|
X500Principal expectedDNPrincipal = new X500Principal(subjectDNRegexp, CUSTOM_OIDS_REVERSED);
|
||||||
|
|
||||||
|
matchedCertificate = Arrays.stream(certs)
|
||||||
|
.filter(certificate -> expectedDNPrincipal.getName(X500Principal.RFC2253, CUSTOM_OIDS).equals(certificate.getSubjectX500Principal().getName(X500Principal.RFC2253, CUSTOM_OIDS)))
|
||||||
|
.map(certificate -> certificate.getSubjectDN().getName())
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
if (!matchedCertificate.isPresent()) {
|
if (!matchedCertificate.isPresent()) {
|
||||||
// We do quite expensive operation here, so better check the logging level beforehand.
|
// We do quite expensive operation here, so better check the logging level beforehand.
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("[X509ClientCertificateAuthenticator:authenticate] Couldn't match any certificate for pattern " + subjectDNRegexp);
|
logger.debug("[X509ClientCertificateAuthenticator:authenticate] Couldn't match any certificate for expected Subject DN '" + subjectDNRegexp + "' with allow regex pattern '" + clientCfg.getAllowRegexPatternComparison() + "'.");
|
||||||
logger.debug("[X509ClientCertificateAuthenticator:authenticate] Available SubjectDNs: " +
|
logger.debug("[X509ClientCertificateAuthenticator:authenticate] Available SubjectDNs: " +
|
||||||
Arrays.stream(certs)
|
Arrays.stream(certs)
|
||||||
.map(cert -> cert.getSubjectDN().getName())
|
.map(cert -> cert.getSubjectDN().getName())
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
context.attempted();
|
context.attempted();
|
||||||
return;
|
return;
|
||||||
|
@ -179,4 +215,5 @@ public class X509ClientAuthenticator extends AbstractClientAuthenticator {
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,16 @@ public class OIDCAdvancedConfigWrapper {
|
||||||
setAttribute(X509ClientAuthenticator.ATTR_SUBJECT_DN, tls_client_auth_subject_dn);
|
setAttribute(X509ClientAuthenticator.ATTR_SUBJECT_DN, tls_client_auth_subject_dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getAllowRegexPatternComparison() {
|
||||||
|
String attrVal = getAttribute(X509ClientAuthenticator.ATTR_ALLOW_REGEX_PATTERN_COMPARISON);
|
||||||
|
// Allow Regex Pattern Comparison by default due the backwards compatibility
|
||||||
|
return attrVal == null || Boolean.parseBoolean(attrVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowRegexPatternComparison(boolean allowRegexPatternComparison) {
|
||||||
|
setAttribute(X509ClientAuthenticator.ATTR_ALLOW_REGEX_PATTERN_COMPARISON, String.valueOf(allowRegexPatternComparison));
|
||||||
|
}
|
||||||
|
|
||||||
public String getPkceCodeChallengeMethod() {
|
public String getPkceCodeChallengeMethod() {
|
||||||
return getAttribute(OIDCConfigAttributes.PKCE_CODE_CHALLENGE_METHOD);
|
return getAttribute(OIDCConfigAttributes.PKCE_CODE_CHALLENGE_METHOD);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.authentication.ClientAuthenticator;
|
||||||
import org.keycloak.authentication.ClientAuthenticatorFactory;
|
import org.keycloak.authentication.ClientAuthenticatorFactory;
|
||||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||||
|
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
||||||
import org.keycloak.jose.jwk.JSONWebKeySet;
|
import org.keycloak.jose.jwk.JSONWebKeySet;
|
||||||
import org.keycloak.jose.jwk.JWK;
|
import org.keycloak.jose.jwk.JWK;
|
||||||
import org.keycloak.jose.jwk.JWKParser;
|
import org.keycloak.jose.jwk.JWKParser;
|
||||||
|
@ -150,6 +151,9 @@ public class DescriptionConverter {
|
||||||
|
|
||||||
if (clientOIDC.getTlsClientAuthSubjectDn() != null) {
|
if (clientOIDC.getTlsClientAuthSubjectDn() != null) {
|
||||||
configWrapper.setTlsClientAuthSubjectDn(clientOIDC.getTlsClientAuthSubjectDn());
|
configWrapper.setTlsClientAuthSubjectDn(clientOIDC.getTlsClientAuthSubjectDn());
|
||||||
|
|
||||||
|
// According to specification, attribute tls_client_auth_subject_dn has subject DN in the exact expected format. There is no reason for support regex comparisons
|
||||||
|
configWrapper.setAllowRegexPatternComparison(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientOIDC.getIdTokenSignedResponseAlg() != null) {
|
if (clientOIDC.getIdTokenSignedResponseAlg() != null) {
|
||||||
|
|
Binary file not shown.
|
@ -8,33 +8,37 @@ Passwords for any key file is `password`.
|
||||||
|
|
||||||
## Steps to create a client certificate
|
## Steps to create a client certificate
|
||||||
|
|
||||||
|
In the instructions below, you may usually need to create your own files for private key, CSR request, certificate , p12 and
|
||||||
|
also possibly custom openssl configuration. For the instructions below, replace the file names according your needs (For example
|
||||||
|
replace `test-user@localhost.key.pem` with something like `test-user-some@localhost.key.pem` )
|
||||||
|
|
||||||
### Create a private key for the client
|
### Create a private key for the client
|
||||||
|
|
||||||
openssl genrsa -aes256 -out signed/clients/test-user@localhost.key.pem 4096
|
openssl genrsa -aes256 -out certs/clients/test-user@localhost.key.pem 4096
|
||||||
chmod 400 signed/clients/test-user@localhost.key.pem
|
chmod 400 certs/clients/test-user@localhost.key.pem
|
||||||
|
|
||||||
### Create a CSR for the client
|
### Create a CSR for the client
|
||||||
|
|
||||||
openssl req -config intermediate/openssl.cnf -key signed/clients/test-user@localhost.key.pem -new -sha256 -out signed/clients/test-user@localhost.csr.pem
|
openssl req -config intermediate/openssl.cnf -key certs/clients/test-user@localhost.key.pem -new -sha256 -out certs/clients/test-user@localhost.csr.pem
|
||||||
|
|
||||||
If you want to generate a CSR with extensions you can use a command similar to the following:
|
If you want to generate a CSR with extensions you can use a command similar to the following:
|
||||||
|
|
||||||
openssl req -config intermediate/openssl-san.cnf -key signed/clients/test-user@localhost.key.pem -new -sha256 -out signed/clients/test-user@localhost.csr.pem
|
openssl req -config intermediate/openssl-san.cnf -key certs/clients/test-user@localhost.key.pem -new -sha256 -out certs/clients/test-user@localhost.csr.pem
|
||||||
|
|
||||||
### Create a certificate using the CSR
|
### Create a certificate using the CSR
|
||||||
|
|
||||||
openssl ca -config intermediate/openssl.cnf -extensions usr_cert -days 375 -notext -md sha256 -in signed/clients/test-user@localhost.csr.pem -out signed/clients/test-user@localhost.cert.pem
|
openssl ca -config intermediate/openssl.cnf -extensions usr_cert -days 375 -notext -md sha256 -in certs/clients/test-user@localhost.csr.pem -out certs/clients/test-user@localhost.cert.pem
|
||||||
|
|
||||||
chmod 444 signed/clients/test-user@localhost.cert.pem
|
chmod 444 certs/clients/test-user@localhost.cert.pem
|
||||||
|
|
||||||
### Verify the certificate
|
### Verify the certificate
|
||||||
|
|
||||||
openssl x509 -noout -text -in signed/clients/test-user@localhost.cert.pem
|
openssl x509 -noout -text -in certs/clients/test-user@localhost.cert.pem
|
||||||
|
|
||||||
### Check if certificate has a valid chain of trust
|
### Check if certificate has a valid chain of trust
|
||||||
|
|
||||||
openssl verify -CAfile intermediate/certs/ca-chain.cert.pem signed/clients/test-user@localhost.cert.pem
|
openssl verify -CAfile intermediate/certs/ca-chain.cert.pem certs/clients/test-user@localhost.cert.pem
|
||||||
|
|
||||||
### Transform both certificate and private key to PKCS12 format
|
### Transform both certificate and private key to PKCS12 format
|
||||||
|
|
||||||
openssl pkcs12 -export -in signed/clients/test-user@localhost.cert.pem -inkey signed/clients/test-user@localhost.key.pem -out signed/clients/test-user@localhost.p12 -name test-user -CAfile intermediate/certs/ca-chain.cert.pem
|
openssl pkcs12 -export -in certs/clients/test-user@localhost.cert.pem -inkey certs/clients/test-user@localhost.key.pem -out certs/clients/test-user@localhost.p12 -name test-user -CAfile intermediate/certs/ca-chain.cert.pem
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
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
|
||||||
|
QwCq8V8K9V83ofNQlCh/
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
|
@ -0,0 +1,54 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: AES-256-CBC,48734C0265B7958D548AA8791226C442
|
||||||
|
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
Binary file not shown.
|
@ -1,2 +1,4 @@
|
||||||
V 450708200730Z 1000 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
|
V 450708200730Z 1000 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
|
||||||
R 460730105428Z 190314110930Z 1009 unknown /C=US/ST=MA/L=Westford/O=Red Hat/OU=Keycloak/CN=test-user@localhost/emailAddress=test-user@localhost
|
R 460730105428Z 190314110930Z 1009 unknown /C=US/ST=MA/L=Westford/O=Red Hat/OU=Keycloak/CN=test-user@localhost/emailAddress=test-user@localhost
|
||||||
|
V 300222160951Z 2009 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=My Org Unit/CN=Foo
|
||||||
|
V 300222161112Z 200A unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=My Org Unit/serialNumber=2009/businessCategory=Business Entity/jurisdictionC=BR/CN=Foo
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
V 450708200730Z 1000 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
|
V 450708200730Z 1000 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
|
||||||
|
R 460730105428Z 190314110930Z 1009 unknown /C=US/ST=MA/L=Westford/O=Red Hat/OU=Keycloak/CN=test-user@localhost/emailAddress=test-user@localhost
|
||||||
|
V 300222160951Z 2009 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=My Org Unit/CN=Foo
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
+MrwBbQohE/rNgFgEyLsyO6DTyE6OxQ22zXr
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,39 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,151 @@
|
||||||
|
# OpenSSL intermediate CA configuration file.
|
||||||
|
|
||||||
|
[ ca ]
|
||||||
|
# `man ca`
|
||||||
|
default_ca = KeycloakICA
|
||||||
|
|
||||||
|
[ KeycloakICA ]
|
||||||
|
# Directory and file locations.
|
||||||
|
dir = ./intermediate
|
||||||
|
certs = $dir/certs
|
||||||
|
crl_dir = $dir/crl
|
||||||
|
new_certs_dir = $dir/newcerts
|
||||||
|
database = $dir/index.txt
|
||||||
|
serial = $dir/serial
|
||||||
|
RANDFILE = $dir/private/.rand
|
||||||
|
|
||||||
|
# The root key and root certificate.
|
||||||
|
private_key = $dir/private/intermediate.key.pem
|
||||||
|
certificate = $dir/certs/intermediate.cert.pem
|
||||||
|
|
||||||
|
# For certificate revocation lists.
|
||||||
|
crlnumber = $dir/crlnumber
|
||||||
|
crl = $dir/crl/intermediate.crl.pem
|
||||||
|
crl_extensions = crl_ext
|
||||||
|
default_crl_days = 30
|
||||||
|
|
||||||
|
# SHA-1 is deprecated, so use SHA-2 instead.
|
||||||
|
default_md = sha256
|
||||||
|
|
||||||
|
name_opt = ca_default
|
||||||
|
cert_opt = ca_default
|
||||||
|
default_days = 375
|
||||||
|
preserve = no
|
||||||
|
policy = policy_loose
|
||||||
|
|
||||||
|
[ policy_strict ]
|
||||||
|
# The root CA should only sign intermediate certificates that match.
|
||||||
|
# See the POLICY FORMAT section of `man ca`.
|
||||||
|
countryName = match
|
||||||
|
stateOrProvinceName = match
|
||||||
|
organizationName = match
|
||||||
|
organizationalUnitName = optional
|
||||||
|
serialNumber = optional
|
||||||
|
businessCategory = optional
|
||||||
|
jurisdictionCountryName = optional
|
||||||
|
commonName = optional
|
||||||
|
|
||||||
|
[ policy_loose ]
|
||||||
|
# Allow the intermediate CA to sign a more diverse range of certificates.
|
||||||
|
# See the POLICY FORMAT section of the `ca` man page.
|
||||||
|
countryName = optional
|
||||||
|
stateOrProvinceName = optional
|
||||||
|
localityName = optional
|
||||||
|
organizationName = optional
|
||||||
|
organizationalUnitName = optional
|
||||||
|
serialNumber = optional
|
||||||
|
businessCategory = optional
|
||||||
|
jurisdictionCountryName = optional
|
||||||
|
commonName = optional
|
||||||
|
|
||||||
|
[ req ]
|
||||||
|
# Options for the `req` tool (`man req`).
|
||||||
|
default_bits = 2048
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
string_mask = utf8only
|
||||||
|
|
||||||
|
# SHA-1 is deprecated, so use SHA-2 instead.
|
||||||
|
default_md = sha256
|
||||||
|
|
||||||
|
# Extension to add when the -x509 option is used.
|
||||||
|
x509_extensions = v3_ca
|
||||||
|
|
||||||
|
[ req_distinguished_name ]
|
||||||
|
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
|
||||||
|
countryName = Country Name (2 letter code)
|
||||||
|
stateOrProvinceName = State or Province Name
|
||||||
|
localityName = Locality Name
|
||||||
|
0.organizationName = Organization Name
|
||||||
|
organizationalUnitName = Organizational Unit Name
|
||||||
|
commonName = Common Name
|
||||||
|
serialNumber = Serial Number
|
||||||
|
businessCategory = Business Category
|
||||||
|
jurisdictionCountryName = Jurisdiction Country Name
|
||||||
|
UID = User ID
|
||||||
|
|
||||||
|
# Optionally, specify some defaults.
|
||||||
|
countryName_default = US
|
||||||
|
stateOrProvinceName_default = MA
|
||||||
|
localityName_default = Boston
|
||||||
|
0.organizationName_default = Red Hat
|
||||||
|
organizationalUnitName_default = My Org Unit
|
||||||
|
commonName_default = Foo
|
||||||
|
serialNumber_default = 2009
|
||||||
|
businessCategory_default = Business Entity
|
||||||
|
jurisdictionCountryName_default = BR
|
||||||
|
UID_default = c99b02be-a7d5-5984-96cb-5676d91cbfea
|
||||||
|
|
||||||
|
|
||||||
|
[ v3_ca ]
|
||||||
|
# Extensions for a typical CA (`man x509v3_config`).
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid:always,issuer
|
||||||
|
basicConstraints = critical, CA:true
|
||||||
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||||
|
|
||||||
|
[ v3_intermediate_ca ]
|
||||||
|
# Extensions for a typical intermediate CA (`man x509v3_config`).
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid:always,issuer
|
||||||
|
basicConstraints = critical, CA:true, pathlen:0
|
||||||
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||||
|
|
||||||
|
[ usr_cert ]
|
||||||
|
# Extensions for client certificates (`man x509v3_config`).
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
nsCertType = client, email
|
||||||
|
nsComment = "OpenSSL Generated Client Certificate"
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
#authorityKeyIdentifier = keyid,issuer
|
||||||
|
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
|
||||||
|
extendedKeyUsage = clientAuth, emailProtection
|
||||||
|
crlDistributionPoints=@crl_section
|
||||||
|
authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
|
||||||
|
|
||||||
|
[crl_section]
|
||||||
|
URI.1 = http://localhost:8889/empty.crl
|
||||||
|
URI.2 = http://localhost:8889/intermediate-ca.crl
|
||||||
|
|
||||||
|
[ server_cert ]
|
||||||
|
# Extensions for server certificates (`man x509v3_config`).
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
nsCertType = server
|
||||||
|
nsComment = "OpenSSL Generated Server Certificate"
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
keyUsage = critical, digitalSignature, keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
crlDistributionPoints = URI:http://localhost:8888/crl
|
||||||
|
authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
|
||||||
|
|
||||||
|
[ crl_ext ]
|
||||||
|
# Extension for CRLs (`man x509v3_config`).
|
||||||
|
authorityKeyIdentifier=keyid:always
|
||||||
|
|
||||||
|
[ ocsp ]
|
||||||
|
# Extension for OCSP signing certificates (`man ocsp`).
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer
|
||||||
|
keyUsage = critical, digitalSignature
|
||||||
|
extendedKeyUsage = critical, OCSPSigning
|
|
@ -1 +1 @@
|
||||||
1009
|
200B
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
1000
|
200A
|
||||||
|
|
|
@ -213,8 +213,8 @@
|
||||||
<include>client.crt</include>
|
<include>client.crt</include>
|
||||||
<include>client.key</include>
|
<include>client.key</include>
|
||||||
<include>*.crl</include>
|
<include>*.crl</include>
|
||||||
<!-- KEYCLOAK-6771 Certificate Bound Token -->
|
|
||||||
<include>other_client.jks</include>
|
<include>other_client.jks</include>
|
||||||
|
<include>test-user-obb.jks</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
<resource>
|
<resource>
|
||||||
|
|
|
@ -105,8 +105,8 @@
|
||||||
<include>client.crt</include>
|
<include>client.crt</include>
|
||||||
<include>client.key</include>
|
<include>client.key</include>
|
||||||
<include>*.crl</include>
|
<include>*.crl</include>
|
||||||
<!-- KEYCLOAK-6771 Certificate Bound Token -->
|
|
||||||
<include>other_client.jks</include>
|
<include>other_client.jks</include>
|
||||||
|
<include>test-user-obb.jks</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -428,8 +428,8 @@
|
||||||
<include>client.crt</include>
|
<include>client.crt</include>
|
||||||
<include>client.key</include>
|
<include>client.key</include>
|
||||||
<include>*.crl</include>
|
<include>*.crl</include>
|
||||||
<!-- KEYCLOAK-6771 Certificate Bound Token -->
|
|
||||||
<include>other_client.jks</include>
|
<include>other_client.jks</include>
|
||||||
|
<include>test-user-obb.jks</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
<resource>
|
<resource>
|
||||||
|
|
|
@ -34,6 +34,11 @@ public class MutualTLSUtils {
|
||||||
public static final String OTHER_KEYSTOREPATH = System.getProperty("hok.client.certificate.keystore");
|
public static final String OTHER_KEYSTOREPATH = System.getProperty("hok.client.certificate.keystore");
|
||||||
public static final String OTHER_KEYSTOREPASSWORD = System.getProperty("hok.client.certificate.keystore.passphrase");
|
public static final String OTHER_KEYSTOREPASSWORD = System.getProperty("hok.client.certificate.keystore.passphrase");
|
||||||
|
|
||||||
|
// Client certificate with tricky Subject, which contains RDNs with non-very known OID names
|
||||||
|
// like "jurisdictionCountryName", "businessCategory", "serialNumber" . These OIDs are used by OpenBanking Brasil
|
||||||
|
public static final String OBB_KEYSTOREPATH = System.getProperty("obb.client.certificate.keystore");
|
||||||
|
public static final String OBB_KEYSTOREPASSWORD = System.getProperty("obb.client.certificate.keystore.passphrase");
|
||||||
|
|
||||||
public static CloseableHttpClient newCloseableHttpClientWithDefaultKeyStoreAndTrustStore() {
|
public static CloseableHttpClient newCloseableHttpClientWithDefaultKeyStoreAndTrustStore() {
|
||||||
return newCloseableHttpClient(DEFAULT_KEYSTOREPATH, DEFAULT_KEYSTOREPASSWORD, DEFAULT_TRUSTSTOREPATH, DEFAULT_TRUSTSTOREPASSWORD);
|
return newCloseableHttpClient(DEFAULT_KEYSTOREPATH, DEFAULT_KEYSTOREPASSWORD, DEFAULT_TRUSTSTOREPATH, DEFAULT_TRUSTSTOREPASSWORD);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +47,10 @@ public class MutualTLSUtils {
|
||||||
return newCloseableHttpClient(OTHER_KEYSTOREPATH, OTHER_KEYSTOREPASSWORD, DEFAULT_TRUSTSTOREPATH, DEFAULT_TRUSTSTOREPASSWORD);
|
return newCloseableHttpClient(OTHER_KEYSTOREPATH, OTHER_KEYSTOREPASSWORD, DEFAULT_TRUSTSTOREPATH, DEFAULT_TRUSTSTOREPASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CloseableHttpClient newCloseableHttpClientWithOBBKeyStoreAndTrustStore() {
|
||||||
|
return newCloseableHttpClient(OBB_KEYSTOREPATH, OBB_KEYSTOREPASSWORD, DEFAULT_TRUSTSTOREPATH, DEFAULT_TRUSTSTOREPASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
public static CloseableHttpClient newCloseableHttpClientWithoutKeyStoreAndTrustStore() {
|
public static CloseableHttpClient newCloseableHttpClientWithoutKeyStoreAndTrustStore() {
|
||||||
return newCloseableHttpClient(null, null, null, null);
|
return newCloseableHttpClient(null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,11 @@ import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||||
import org.keycloak.testsuite.util.MutualTLSUtils;
|
import org.keycloak.testsuite.util.MutualTLSUtils;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
|
@ -41,6 +43,7 @@ public class MutualTLSClientTest extends AbstractTestRealmKeycloakTest {
|
||||||
private static final String CLIENT_ID = "confidential-x509";
|
private static final String CLIENT_ID = "confidential-x509";
|
||||||
private static final String DISABLED_CLIENT_ID = "confidential-disabled-x509";
|
private static final String DISABLED_CLIENT_ID = "confidential-disabled-x509";
|
||||||
private static final String EXACT_SUBJECT_DN_CLIENT_ID = "confidential-subjectdn-x509";
|
private static final String EXACT_SUBJECT_DN_CLIENT_ID = "confidential-subjectdn-x509";
|
||||||
|
private static final String OBB_SUBJECT_DN_CLIENT_ID = "obb-subjectdn-x509";
|
||||||
private static final String USER = "keycloak-user@localhost";
|
private static final String USER = "keycloak-user@localhost";
|
||||||
private static final String PASSWORD = "password";
|
private static final String PASSWORD = "password";
|
||||||
private static final String REALM = "test";
|
private static final String REALM = "test";
|
||||||
|
@ -65,6 +68,12 @@ public class MutualTLSClientTest extends AbstractTestRealmKeycloakTest {
|
||||||
exactSubjectDNConfiguration.setRedirectUris(Arrays.asList("https://localhost:8543/auth/realms/master/app/auth"));
|
exactSubjectDNConfiguration.setRedirectUris(Arrays.asList("https://localhost:8543/auth/realms/master/app/auth"));
|
||||||
exactSubjectDNConfiguration.setClientAuthenticatorType(X509ClientAuthenticator.PROVIDER_ID);
|
exactSubjectDNConfiguration.setClientAuthenticatorType(X509ClientAuthenticator.PROVIDER_ID);
|
||||||
exactSubjectDNConfiguration.setAttributes(Collections.singletonMap(X509ClientAuthenticator.ATTR_SUBJECT_DN, EXACT_CERTIFICATE_SUBJECT_DN));
|
exactSubjectDNConfiguration.setAttributes(Collections.singletonMap(X509ClientAuthenticator.ATTR_SUBJECT_DN, EXACT_CERTIFICATE_SUBJECT_DN));
|
||||||
|
|
||||||
|
ClientRepresentation obbSubjectDNConfiguration = KeycloakModelUtils.createClient(testRealm, OBB_SUBJECT_DN_CLIENT_ID);
|
||||||
|
obbSubjectDNConfiguration.setServiceAccountsEnabled(Boolean.TRUE);
|
||||||
|
obbSubjectDNConfiguration.setRedirectUris(Arrays.asList("https://localhost:8543/auth/realms/master/app/auth"));
|
||||||
|
obbSubjectDNConfiguration.setClientAuthenticatorType(X509ClientAuthenticator.PROVIDER_ID);
|
||||||
|
// ATTR_SUBJECT_DN will be set in the individual tests based on the requested Subject DN Format
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
|
@ -149,6 +158,53 @@ public class MutualTLSClientTest extends AbstractTestRealmKeycloakTest {
|
||||||
assertTokenNotObtained(token);
|
assertTokenNotObtained(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientInvocationWithOBBClient_rfc2553_resolvedAttributes() throws Exception {
|
||||||
|
// Attributes like "JURISDICTIONCOUNTRYNAME", "BUSINESSCATEGORY" and SERIALNUMBER" are resolved (expanded) in the expected Subject DN
|
||||||
|
testClientInvocationWithOBBClient("CN=Foo,JURISDICTIONCOUNTRYNAME=BR,BUSINESSCATEGORY=Business Entity,SERIALNUMBER=2009,OU=My Org Unit,O=Red Hat,L=Boston,ST=MA,C=US",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientInvocationWithOBBClient_rfc2553_unresolvedAttributes() throws Exception {
|
||||||
|
// Format like this is used by OpenBanking Brasil testsuite. Attributes like "JURISDICTIONCOUNTRYNAME", "BUSINESSCATEGORY" and SERIALNUMBER" are NOT resolved (expanded) in the expected Subject DN
|
||||||
|
testClientInvocationWithOBBClient("CN=Foo,1.3.6.1.4.1.311.60.2.1.3=#13024252,2.5.4.15=#130f427573696e65737320456e74697479,2.5.4.5=#130432303039,OU=My Org Unit,O=Red Hat,L=Boston,ST=MA,C=US",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientInvocationWithOBBClient_rfc2553_invalidSubjectDN() throws Exception {
|
||||||
|
// Test that authentication fails when certificate does not contain expected DN
|
||||||
|
testClientInvocationWithOBBClient("CN=Foo,1.3.6.1.4.1.311.60.2.1.3=#13024252,2.5.4.15=#130f427573696e65737320456e74697479,2.5.4.5=#130e3037323337333733303030313230,OU=My Org Unit,O=Red Hat,L=Boston,ST=MA,C=US",
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientInvocationWithOBBClient_rfc1779() throws Exception {
|
||||||
|
testClientInvocationWithOBBClient("CN=Foo, JURISDICTIONCOUNTRYNAME=BR, BUSINESSCATEGORY=Business Entity, SERIALNUMBER=2009, OU=My Org Unit, O=Red Hat, L=Boston, ST=MA, C=US",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testClientInvocationWithOBBClient(String expectedSubjectDN, boolean expectSuccess) throws Exception {
|
||||||
|
//given
|
||||||
|
Supplier<CloseableHttpClient> clientWithProperCertificate = MutualTLSUtils::newCloseableHttpClientWithOBBKeyStoreAndTrustStore;
|
||||||
|
|
||||||
|
// Canonical
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(testRealm(), OBB_SUBJECT_DN_CLIENT_ID);
|
||||||
|
ClientRepresentation clientRep = client.toRepresentation();
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep);
|
||||||
|
config.setAllowRegexPatternComparison(false);
|
||||||
|
config.setTlsClientAuthSubjectDn(expectedSubjectDN);
|
||||||
|
client.update(clientRep);
|
||||||
|
|
||||||
|
OAuthClient.AccessTokenResponse token = loginAndGetAccessTokenResponse(OBB_SUBJECT_DN_CLIENT_ID, clientWithProperCertificate);
|
||||||
|
if (expectSuccess) {
|
||||||
|
assertTokenObtained(token);
|
||||||
|
} else {
|
||||||
|
assertTokenNotObtained(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private OAuthClient.AccessTokenResponse loginAndGetAccessTokenResponse(String clientId, Supplier<CloseableHttpClient> client) throws IOException{
|
private OAuthClient.AccessTokenResponse loginAndGetAccessTokenResponse(String clientId, Supplier<CloseableHttpClient> client) throws IOException{
|
||||||
try (CloseableHttpClient closeableHttpClient = client.get()) {
|
try (CloseableHttpClient closeableHttpClient = client.get()) {
|
||||||
login(clientId);
|
login(clientId);
|
||||||
|
|
|
@ -576,6 +576,7 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient);
|
||||||
Assert.assertEquals(X509ClientAuthenticator.PROVIDER_ID, kcClient.getClientAuthenticatorType());
|
Assert.assertEquals(X509ClientAuthenticator.PROVIDER_ID, kcClient.getClientAuthenticatorType());
|
||||||
Assert.assertEquals("Ein", config.getTlsClientAuthSubjectDn());
|
Assert.assertEquals("Ein", config.getTlsClientAuthSubjectDn());
|
||||||
|
Assert.assertFalse(config.getAllowRegexPatternComparison());
|
||||||
|
|
||||||
// update
|
// update
|
||||||
reg.auth(Auth.token(response));
|
reg.auth(Auth.token(response));
|
||||||
|
|
|
@ -155,8 +155,8 @@
|
||||||
<include>client.crt</include>
|
<include>client.crt</include>
|
||||||
<include>client.key</include>
|
<include>client.key</include>
|
||||||
<include>*.crl</include>
|
<include>*.crl</include>
|
||||||
<!-- KEYCLOAK-6771 Certificate Bound Token -->
|
|
||||||
<include>other_client.jks</include>
|
<include>other_client.jks</include>
|
||||||
|
<include>test-user-obb.jks</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
<resource>
|
<resource>
|
||||||
|
|
|
@ -252,6 +252,10 @@
|
||||||
<hok.client.certificate.keystore>${auth.server.config.dir}/other_client.jks</hok.client.certificate.keystore>
|
<hok.client.certificate.keystore>${auth.server.config.dir}/other_client.jks</hok.client.certificate.keystore>
|
||||||
<hok.client.certificate.keystore.passphrase>secret</hok.client.certificate.keystore.passphrase>
|
<hok.client.certificate.keystore.passphrase>secret</hok.client.certificate.keystore.passphrase>
|
||||||
|
|
||||||
|
<!-- Client certificate with the format suitable for OpenBanking Brasil -->
|
||||||
|
<obb.client.certificate.keystore>${auth.server.config.dir}/test-user-obb.jks</obb.client.certificate.keystore>
|
||||||
|
<obb.client.certificate.keystore.passphrase>password</obb.client.certificate.keystore.passphrase>
|
||||||
|
|
||||||
<auth.server.ocsp.responder.enabled>false</auth.server.ocsp.responder.enabled>
|
<auth.server.ocsp.responder.enabled>false</auth.server.ocsp.responder.enabled>
|
||||||
<keycloak.x509cert.lookup.provider>default</keycloak.x509cert.lookup.provider>
|
<keycloak.x509cert.lookup.provider>default</keycloak.x509cert.lookup.provider>
|
||||||
<auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config>
|
<auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config>
|
||||||
|
@ -642,6 +646,10 @@
|
||||||
<hok.client.certificate.keystore>${hok.client.certificate.keystore}</hok.client.certificate.keystore>
|
<hok.client.certificate.keystore>${hok.client.certificate.keystore}</hok.client.certificate.keystore>
|
||||||
<hok.client.certificate.keystore.passphrase>${hok.client.certificate.keystore.passphrase}</hok.client.certificate.keystore.passphrase>
|
<hok.client.certificate.keystore.passphrase>${hok.client.certificate.keystore.passphrase}</hok.client.certificate.keystore.passphrase>
|
||||||
|
|
||||||
|
<!-- Client certificate with the format suitable for OpenBanking Brasil -->
|
||||||
|
<obb.client.certificate.keystore>${obb.client.certificate.keystore}</obb.client.certificate.keystore>
|
||||||
|
<obb.client.certificate.keystore.passphrase>${obb.client.certificate.keystore.passphrase}</obb.client.certificate.keystore.passphrase>
|
||||||
|
|
||||||
<auth.server.ocsp.responder.enabled>${auth.server.ocsp.responder.enabled}</auth.server.ocsp.responder.enabled>
|
<auth.server.ocsp.responder.enabled>${auth.server.ocsp.responder.enabled}</auth.server.ocsp.responder.enabled>
|
||||||
|
|
||||||
<!-- cluster properties -->
|
<!-- cluster properties -->
|
||||||
|
|
|
@ -1905,7 +1905,9 @@ request-uri-lifespan=Lifetime of the Request URI for Pushed Authorization Reques
|
||||||
request-uri-lifespan.tooltip=Number that represents the lifetime of the request URI in minutes or hours, the default value is 1 minute.
|
request-uri-lifespan.tooltip=Number that represents the lifetime of the request URI in minutes or hours, the default value is 1 minute.
|
||||||
|
|
||||||
subjectdn=Subject DN
|
subjectdn=Subject DN
|
||||||
subjectdn-tooltip=A regular expression for validating Subject DN in the Client Certificate. Use "(.*?)(?:$)" to match all kind of expressions.
|
subjectdn-tooltip=The expected Subject DN, which should match DN from client certificate. In case that 'Allow Regex Pattern Comparison' allowed, this can contain regular expression for validating Subject DN in the Client Certificate. Use "(.*?)(?:$)" to match all kind of expressions.
|
||||||
|
allow-regex-pattern-comparison=Allow Regex Pattern Comparison
|
||||||
|
allow-regex-pattern-comparison.tooltip=If OFF, then the Subject DN from given client certificate must exactly match the given DN from the 'Subject DN' property as described in the RFC8705 specification. The Subject DN can be in the RFC2553 or RFC1779 format. If ON, then the Subject DN from given client certificate should match regex specified by 'Subject DN' property.
|
||||||
|
|
||||||
pkce-code-challenge-method=Proof Key for Code Exchange Code Challenge Method
|
pkce-code-challenge-method=Proof Key for Code Exchange Code Challenge Method
|
||||||
pkce-code-challenge-method.tooltip=Choose which code challenge method for PKCE is used. If not specified, keycloak does not applies PKCE to a client unless the client sends an authorization request with appropriate code challenge and code exchange method.
|
pkce-code-challenge-method.tooltip=Choose which code challenge method for PKCE is used. If not specified, keycloak does not applies PKCE to a client unless the client sends an authorization request with appropriate code challenge and code exchange method.
|
||||||
|
|
|
@ -198,7 +198,29 @@ module.controller('ClientX509Ctrl', function($scope, $location, Client, Notifica
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
function updateProperties() {
|
||||||
|
if ($scope.client.attributes["x509.allow.regex.pattern.comparison"]) {
|
||||||
|
if ($scope.client.attributes["x509.allow.regex.pattern.comparison"] == "true") {
|
||||||
|
$scope.allowRegexPatternComparison = true;
|
||||||
|
} else {
|
||||||
|
$scope.allowRegexPatternComparison = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProperties();
|
||||||
|
|
||||||
|
$scope.switchChange = function() {
|
||||||
|
$scope.changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
|
if ($scope.allowRegexPatternComparison == true) {
|
||||||
|
$scope.client.attributes["x509.allow.regex.pattern.comparison"] = "true";
|
||||||
|
} else {
|
||||||
|
$scope.client.attributes["x509.allow.regex.pattern.comparison"] = "false";
|
||||||
|
}
|
||||||
|
|
||||||
if (!$scope.client.attributes["x509.subjectdn"]) {
|
if (!$scope.client.attributes["x509.subjectdn"]) {
|
||||||
Notifications.error("The SubjectDN must not be empty.");
|
Notifications.error("The SubjectDN must not be empty.");
|
||||||
} else {
|
} else {
|
||||||
|
@ -224,6 +246,8 @@ module.controller('ClientX509Ctrl', function($scope, $location, Client, Notifica
|
||||||
|
|
||||||
$scope.reset = function() {
|
$scope.reset = function() {
|
||||||
$scope.client.attributes["x509.subjectdn"] = $scope.clientCopy.attributes["x509.subjectdn"];
|
$scope.client.attributes["x509.subjectdn"] = $scope.clientCopy.attributes["x509.subjectdn"];
|
||||||
|
$scope.client.attributes["x509.allow.regex.pattern.comparison"] = $scope.clientCopy.attributes["x509.allow.regex.pattern.comparison"];
|
||||||
|
updateProperties();
|
||||||
$location.url("/realms/" + $scope.realm.realm + "/clients/" + $scope.client.id + "/credentials");
|
$location.url("/realms/" + $scope.realm.realm + "/clients/" + $scope.client.id + "/credentials");
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="allowRegexPatternComparison">{{:: 'allow-regex-pattern-comparison' | translate}}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input ng-model="allowRegexPatternComparison" name="allowRegexPatternComparison" id="allowRegexPatternComparison" ng-click="switchChange()" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'allow-regex-pattern-comparison.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
|
<div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
|
||||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||||
|
|
Loading…
Reference in a new issue