KEYCLOAK-19138 nginx x509 client trusted certificate lookup
This commit is contained in:
parent
860c3fbbd3
commit
7f58c1c570
3 changed files with 104 additions and 2 deletions
|
@ -165,6 +165,9 @@ to load additional certificates from headers `CERT_CHAIN_0` to `CERT_CHAIN_9` if
|
|||
|
||||
|certificate-chain-length
|
||||
| The maximum length of the certificate chain.
|
||||
|
||||
|trust-proxy-verification
|
||||
| Enable trusting NGINX proxy certificate verification, instead of forwarding the certificate to keycloak and verifying it in keycloak.
|
||||
|===
|
||||
|
||||
==== Configuring the NGINX provider
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.services.x509;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
|
@ -13,12 +15,30 @@ import org.keycloak.models.KeycloakSession;
|
|||
|
||||
public class NginxProxySslClientCertificateLookupFactory extends AbstractClientCertificateFromHttpHeadersLookupFactory {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(NginxProxySslClientCertificateLookupFactory.class);
|
||||
|
||||
private final static String PROVIDER = "nginx";
|
||||
|
||||
protected final static String TRUST_PROXY_VERIFICATION = "trust-proxy-verification";
|
||||
|
||||
protected boolean trustProxyVerification = false;
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
super.init(config);
|
||||
trustProxyVerification = config.getBoolean(TRUST_PROXY_VERIFICATION, false);
|
||||
logger.tracev("{0}: ''{1}''", TRUST_PROXY_VERIFICATION, trustProxyVerification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509ClientCertificateLookup create(KeycloakSession session) {
|
||||
return new NginxProxySslClientCertificateLookup(sslClientCertHttpHeader,
|
||||
sslChainHttpHeaderPrefix, certificateChainLength, session);
|
||||
if (trustProxyVerification) {
|
||||
return new NginxProxyTrustedClientCertificateLookup(sslClientCertHttpHeader,
|
||||
sslChainHttpHeaderPrefix, certificateChainLength);
|
||||
} else {
|
||||
return new NginxProxySslClientCertificateLookup(sslClientCertHttpHeader,
|
||||
sslChainHttpHeaderPrefix, certificateChainLength, session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package org.keycloak.services.x509;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.common.util.PemException;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* The NGINX Trusted Provider verify extract end user X.509 certificate sent during TLS mutual authentication,
|
||||
* verifies it against provided CA the and forwarded in an HTTP header along with a new header ssl-client-verify: SUCCESS.
|
||||
*
|
||||
* NGINX configuration must have :
|
||||
* <code>
|
||||
* server {
|
||||
* ...
|
||||
* ssl_client_certificate path-to-trusted-ca.crt;
|
||||
* ssl_verify_client on|optional;
|
||||
* ssl_verify_depth 2;
|
||||
* ...
|
||||
* location / {
|
||||
* ...
|
||||
* proxy_set_header ssl-client-cert $ssl_client_escaped_cert;
|
||||
* ...
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* Note that $ssl_client_cert is deprecated, use only $ssl_client_escaped_cert with this implementation
|
||||
*
|
||||
* @author <a href="mailto:youssef.elhouti@tailosoft.com">Youssef El Houti</a>
|
||||
* @version $Revision: 1 $
|
||||
* @since 01/09/2022
|
||||
*/
|
||||
|
||||
public class NginxProxyTrustedClientCertificateLookup extends AbstractClientCertificateFromHttpHeadersLookup {
|
||||
|
||||
private static final Logger log = Logger.getLogger(NginxProxyTrustedClientCertificateLookup.class);
|
||||
|
||||
public NginxProxyTrustedClientCertificateLookup(String sslCientCertHttpHeader,
|
||||
String sslCertChainHttpHeaderPrefix,
|
||||
int certificateChainLength) {
|
||||
super(sslCientCertHttpHeader, sslCertChainHttpHeaderPrefix, certificateChainLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X509Certificate getCertificateFromHttpHeader(HttpRequest request, String httpHeader) throws GeneralSecurityException {
|
||||
X509Certificate certificate = super.getCertificateFromHttpHeader(request, httpHeader);
|
||||
if (certificate == null) {
|
||||
return null;
|
||||
}
|
||||
String validCertificateResult = getHeaderValue(request, "ssl-client-verify");
|
||||
if ("SUCCESS".equals(validCertificateResult)) {
|
||||
return certificate;
|
||||
} else {
|
||||
log.warn("nginx could not verify the certificate: ssl-client-verify: " + validCertificateResult);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X509Certificate decodeCertificateFromPem(String pem) throws PemException {
|
||||
|
||||
if (pem == null) {
|
||||
log.warn("End user TLS Certificate is NULL! ");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
pem = java.net.URLDecoder.decode(pem, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.error("Cannot URL decode the end user TLS Certificate : " + pem,e);
|
||||
}
|
||||
|
||||
return PemUtils.decodeCertificate(pem);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue