@Override
    public Optional<Credentials> validate(final CallContext ctx, final Credentials credentials) {
        init();

        val certificate = ((X509Credentials) credentials).getCertificate();
        if (certificate == null) {
            throw new CredentialsException("No X509 certificate");
        }

        val principal = certificate.getSubjectDN();
        if (principal == null) {
            throw new CredentialsException("No X509 principal");
        }

        val subjectDN = principal.getName();
        logger.debug("subjectDN: {}", subjectDN);

        if (subjectDN == null) {
            throw new CredentialsException("No X509 subjectDN");
        }

        val matcher = this.pattern.matcher(subjectDN);

        if (!matcher.find()) {
            throw new CredentialsException("No matching for pattern: " +  regexpPattern + " in subjectDN: " + subjectDN);
        }

        if (matcher.groupCount() != 1) {
            throw new CredentialsException("Too many matches for pattern: " +  regexpPattern + " in subjectDN: " + subjectDN);
        }

        val id = matcher.group(1);
        val profile = getProfileDefinition().newProfile();
        profile.setId(id);
        try {
            profile.addAttribute("x509-certificate", Base64.getEncoder().encodeToString(certificate.getEncoded()));
        } catch (final Exception e) {
            throw new CredentialsException("Unable to encode the certificate", e);
        }
        profile.addAttribute("x509-subjectDN", subjectDN);
        profile.addAttribute("x509-notAfter", certificate.getNotAfter());
        profile.addAttribute("x509-notBefore", certificate.getNotBefore());
        profile.addAttribute("x509-sigAlgName", certificate.getSigAlgName());
        profile.addAttribute("x509-sigAlgOid", certificate.getSigAlgOID());

        extractExtensionFromCertificate(profile, certificate, "x509-sanEmail", 1);
        extractExtensionFromCertificate(profile, certificate, "x509-sanDNS", 2);
        extractExtensionFromCertificate(profile, certificate, "x509-sanURI", 6);
        extractExtensionFromCertificate(profile, certificate, "x509-sanIP", 7);
        extractExtensionFromCertificate(profile, certificate, "x509-sanRegisteredID", 8);
        extractExtensionFromCertificate(profile, certificate, "x509-sanDirectory", 9);

        val issuerDN = certificate.getIssuerDN();
        if (issuerDN != null) {
            profile.addAttribute("x509-issuer", issuerDN.getName());
        }
        val issuerX500Principal = certificate.getIssuerX500Principal();
        if (issuerX500Principal != null) {
            profile.addAttribute("x509-issuerX500", issuerX500Principal.getName());
        }

        logger.debug("profile: {}", profile);

        credentials.setUserProfile(profile);

        return Optional.of(credentials);
    }
Authenticates {@link X509Credentials}. Like the SubjectDnX509PrincipalExtractor in Spring Security.

@author Jerome Leleu
@since 3.3.0
pac4j-http/src/main/java/org/pac4j/http/credentials/authenticator/X509Authenticator.java