protected void validateSubject(final Subject subject, final SAML2MessageContext context,
                                   final Decrypter decrypter) {
        var samlIDFound = false;

        // Read NameID/BaseID/EncryptedID from the subject. If not present directly in the subject, try to find it in subject confirmations.
        var nameIdFromSubject = subject.getNameID();
        val baseIdFromSubject = subject.getBaseID();
        val encryptedIdFromSubject = subject.getEncryptedID();

        // Encrypted ID can overwrite the non-encrypted one, if present
        val decryptedNameIdFromSubject = decryptEncryptedId(encryptedIdFromSubject, decrypter);
        if (decryptedNameIdFromSubject != null) {
            nameIdFromSubject = decryptedNameIdFromSubject;
        }

        // If we have a Name ID or a Base ID, we are fine
        // If we don't have anything, let's go through all subject confirmations and get the IDs from them.
        // At least one should be present but we don't care at this point.
        if (nameIdFromSubject != null || baseIdFromSubject != null) {
            context.getSAMLSubjectNameIdentifierContext().setSubjectNameIdentifier(nameIdFromSubject);
            context.setBaseID(baseIdFromSubject);
            samlIDFound = true;
        }

        for (val confirmation : subject.getSubjectConfirmations()) {
            if (SubjectConfirmation.METHOD_BEARER.equals(confirmation.getMethod())
                && isValidBearerSubjectConfirmationData(confirmation.getSubjectConfirmationData(), context)) {
                validateAssertionReplay((Assertion) subject.getParent(), confirmation.getSubjectConfirmationData());
                var nameIDFromConfirmation = confirmation.getNameID();
                val baseIDFromConfirmation = confirmation.getBaseID();
                val encryptedIDFromConfirmation = confirmation.getEncryptedID();

                // Encrypted ID can overwrite the non-encrypted one, if present
                val decryptedNameIdFromConfirmation = decryptEncryptedId(encryptedIDFromConfirmation,
                    decrypter);
                if (decryptedNameIdFromConfirmation != null) {
                    nameIDFromConfirmation = decryptedNameIdFromConfirmation;
                }

                if (!samlIDFound && (nameIDFromConfirmation != null || baseIDFromConfirmation != null)) {
                    context.getSAMLSubjectNameIdentifierContext().setSubjectNameIdentifier(nameIDFromConfirmation);
                    context.setBaseID(baseIDFromConfirmation);
                    context.getSubjectConfirmations().add(confirmation);
                    samlIDFound = true;
                }
                if (!samlIDFound) {
                    logger.warn(
                        "Could not find any Subject NameID/BaseID/EncryptedID, neither directly in the Subject nor in any Subject "
                            + "Confirmation.");
                }
                return;
            }
        }

        throw new SAMLSubjectConfirmationException("Subject confirmation validation failed");
    }
Validate the given subject by finding a valid Bearer confirmation. If the subject is valid, put its nameID in the
context.
<p>
NameID / BaseID / EncryptedID is first looked up directly in the Subject. If not present there, then all relevant
SubjectConfirmations are parsed and the IDs are taken from them.

@param subject   The Subject from an assertion.
@param context   SAML message context.
@param decrypter Decrypter used to decrypt some encrypted IDs, if they are present.
                 May be {@code null}, no decryption will be possible then.
pac4j-saml/src/main/java/org/pac4j/saml/sso/impl/SAML2AuthnResponseValidator.java