[java-identity-provider] 01/02: Javadoc

Rod Widdowson rdw at steadingsoftware.com
Fri Feb 24 08:32:53 UTC 2023


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=b4519d5ef698362c28c642635b3ff059f7fdef8c

commit b4519d5ef698362c28c642635b3ff059f7fdef8c
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Feb 23 11:24:00 2023 +0000

    Javadoc
---
 .../impl/AbstractAuditingValidationAction.java     | 10 ++-
 .../AttributeSourcedSubjectCanonicalization.java   | 18 ++--
 .../DefaultAuthenticationResultSerializer.java     | 18 ++--
 .../DefaultPrincipalDeterminationStrategy.java     |  9 +-
 .../idp/authn/impl/DoLockoutManagerOperation.java  | 26 +++---
 .../idp/authn/impl/ExternalAuthenticationImpl.java |  7 +-
 .../idp/authn/impl/ExtractRemoteUser.java          | 15 ++--
 .../idp/authn/impl/ExtractUserAgentAddress.java    |  2 +-
 .../idp/authn/impl/ExtractUserAgentIdentifier.java |  2 +-
 .../impl/ExtractUsernamePasswordFromBasicAuth.java |  2 +-
 .../ExtractUsernamePasswordFromFormRequest.java    |  2 +-
 .../impl/ExtractUsernamePasswordFromWSSToken.java  |  7 +-
 .../idp/authn/impl/FinalizeAuthentication.java     | 40 +++++----
 .../impl/FinalizeMultiFactorAuthentication.java    | 15 ++--
 .../authn/impl/HTPasswdCredentialValidator.java    | 22 +++--
 .../impl/InitializeRequestedPrincipalContext.java  |  3 +-
 .../idp/authn/impl/JAASCredentialValidator.java    | 34 +++++---
 .../authn/impl/KerberosCredentialValidator.java    |  4 +-
 .../idp/authn/impl/LDAPCredentialValidator.java    | 17 ++--
 .../authn/impl/PopulateAuthenticationContext.java  |  8 +-
 .../PopulateMultiFactorAuthenticationContext.java  | 20 +++--
 .../PopulateSubjectCanonicalizationContext.java    |  7 +-
 .../impl/PreserveAuthenticationFlowState.java      | 11 ++-
 .../RelyingPartyMapJAASLoginConfigStrategy.java    | 13 +--
 .../idp/authn/impl/RemoteUserAuthServlet.java      | 26 +++---
 .../idp/authn/impl/SelectAuthenticationFlow.java   | 84 ++++++++++--------
 .../impl/SelectSubjectCanonicalizationFlow.java    | 18 ++--
 .../authn/impl/SimpleSubjectCanonicalization.java  | 25 +++---
 .../impl/StorageBackedAccountLockoutManager.java   | 55 +++++++++---
 .../impl/TransitionMultiFactorAuthentication.java  | 42 ++++++---
 .../idp/authn/impl/ValidateCredentials.java        | 15 ++--
 .../authn/impl/ValidateExternalAuthentication.java | 99 ++++++++++++++--------
 .../idp/authn/impl/ValidateFunctionResult.java     | 18 ++--
 .../idp/authn/impl/ValidateRemoteUser.java         | 39 ++++++---
 .../idp/authn/impl/ValidateUserAgentAddress.java   | 30 ++++---
 .../authn/impl/X500SubjectCanonicalization.java    | 45 +++++-----
 .../shibboleth/idp/authn/impl/X509AuthServlet.java |  9 +-
 .../impl/X509CertificateCredentialValidator.java   | 14 +--
 .../AuthenticationResultPrincipalSerializer.java   | 39 ++-------
 .../impl/IdPAttributePrincipalSerializer.java      | 31 +++++--
 .../impl/InexactPrincipalEvalPredicateFactory.java |  9 +-
 .../principal/impl/LDAPPrincipalSerializer.java    | 20 +++--
 .../ProxyAuthenticationPrincipalSerializer.java    | 50 +++++------
 .../principal/impl/X500PrincipalSerializer.java    | 54 +++---------
 .../impl/DiscoveryProfileRequestFunction.java      | 29 ++++---
 .../impl/AttributeRevocationCondition.java         | 15 ++--
 .../impl/DoRevocationCacheOperation.java           | 44 +++++++---
 .../revocation/impl/RevocationCacheCondition.java  | 10 ++-
 .../authn/spnego/impl/GSSAcceptorLoginModule.java  | 26 +++---
 .../idp/authn/spnego/impl/GSSContextAcceptor.java  | 22 +++--
 .../idp/authn/spnego/impl/KerberosSettings.java    | 12 ++-
 .../authn/spnego/impl/SPNEGOAuthnController.java   | 22 +++--
 52 files changed, 706 insertions(+), 508 deletions(-)

diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AbstractAuditingValidationAction.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AbstractAuditingValidationAction.java
index 796463269..7592bbe57 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AbstractAuditingValidationAction.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AbstractAuditingValidationAction.java
@@ -142,10 +142,12 @@ public abstract class AbstractAuditingValidationAction extends AbstractValidatio
      * @param profileRequestContext profile request context
      */
     protected void doAudit(@Nonnull final ProfileRequestContext profileRequestContext) {
+
         if (populateAuditContextAction != null && writeAuditLogAction != null) {
             final EventContext existingEvent = profileRequestContext.getSubcontext(EventContext.class);
             
             try {
+                assert populateAuditContextAction != null;
                 populateAuditContextAction.execute(requestContext);
                 
                 final Map<String,String> fields = getAuditFields(profileRequestContext);
@@ -153,7 +155,9 @@ public abstract class AbstractAuditingValidationAction extends AbstractValidatio
                     final AuditContext ac = getAuditContext(profileRequestContext);
                     if (ac != null) {
                         for (final Map.Entry<String,String> field : fields.entrySet()) {
-                            ac.getFieldValues(field.getKey()).add(field.getValue());
+                            final String key = field.getKey();
+                            assert key != null;
+                            ac.getFieldValues(key).add(field.getValue());
                         }
                     }
                 }
@@ -164,6 +168,7 @@ public abstract class AbstractAuditingValidationAction extends AbstractValidatio
             }
             
             try {
+                assert writeAuditLogAction != null;
                 writeAuditLogAction.execute(requestContext);
             } finally {
                 if (existingEvent != null) {
@@ -183,5 +188,4 @@ public abstract class AbstractAuditingValidationAction extends AbstractValidatio
             @Nonnull final ProfileRequestContext profileRequestContext) {
         return null;
     }
-    
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AttributeSourcedSubjectCanonicalization.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AttributeSourcedSubjectCanonicalization.java
index 1aa4c268f..2ce0cab24 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AttributeSourcedSubjectCanonicalization.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/AttributeSourcedSubjectCanonicalization.java
@@ -18,7 +18,6 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -45,6 +44,7 @@ import net.shibboleth.idp.authn.SubjectCanonicalizationException;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -92,8 +92,8 @@ public class AttributeSourcedSubjectCanonicalization extends AbstractSubjectCano
     /** Constructor. */
     public AttributeSourcedSubjectCanonicalization() {
         delimiter = '@';
-        attributeSourceIds = Collections.emptyList();
-        subjectSourcedAttributes = Collections.emptyMap();
+        attributeSourceIds = CollectionSupport.emptyList();
+        subjectSourcedAttributes = CollectionSupport.emptyMap();
         
         attributeContextLookupStrategy =
                 new ChildContextLookup<>(AttributeContext.class).compose(
@@ -165,16 +165,16 @@ public class AttributeSourcedSubjectCanonicalization extends AbstractSubjectCano
         }
         
         if (resolveFromSubject) {
-            final Set<IdPAttributePrincipal> subjectSourced =
-                    c14nContext.getSubject().getPrincipals(IdPAttributePrincipal.class);
+            @Nonnull final Subject subject = Constraint.isNotNull(c14nContext.getSubject(), "Expected a non-null Subject");
+            final Set<IdPAttributePrincipal> subjectSourced = subject.getPrincipals(IdPAttributePrincipal.class);
             if (subjectSourced != null && !subjectSourced.isEmpty()) {
                 subjectSourcedAttributes = new HashMap<>(subjectSourced.size());
                 subjectSourced.forEach(a -> subjectSourcedAttributes.put(a.getAttribute().getId(), a.getAttribute()));
             }
         }
         
-        attributeCtx = attributeContextLookupStrategy.apply(profileRequestContext);
-        if (subjectSourcedAttributes.isEmpty() && (attributeCtx == null || attributeCtx.getIdPAttributes().isEmpty())) {
+        final AttributeContext aCtx = attributeCtx = attributeContextLookupStrategy.apply(profileRequestContext);
+        if (subjectSourcedAttributes.isEmpty() && (aCtx == null || aCtx.getIdPAttributes().isEmpty())) {
             log.warn("{} No attributes found, canonicalization not possible", getLogPrefix());
             c14nContext.setException(new SubjectCanonicalizationException("No attributes were found"));
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
@@ -244,8 +244,6 @@ public class AttributeSourcedSubjectCanonicalization extends AbstractSubjectCano
                 log.warn("{} Unsupported attribute value type: {}", getLogPrefix(), val.getClass().getName());
             }
         }
-        
         return null;
     }
-    
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
index e53ccaf5a..3be8f8442 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
@@ -27,7 +27,6 @@ import java.security.cert.X509Certificate;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -133,7 +132,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
         generatorFactory = Json.createGeneratorFactory(null);
         readerFactory = Json.createReaderFactory(null);
         
-        principalSerializers = Collections.emptyList();
+        principalSerializers = CollectionSupport.emptyList();
         authnResultPrincipalSerializer = new AuthenticationResultPrincipalSerializer(this);
         principalServiceManager = new PrincipalServiceManager(null);
         genericSerializer = new GenericPrincipalSerializer();
@@ -153,7 +152,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
         generatorFactory = Json.createGeneratorFactory(null);
         readerFactory = Json.createReaderFactory(null);
         
-        principalSerializers = Collections.emptyList();
+        principalSerializers = CollectionSupport.emptyList();
         authnResultPrincipalSerializer = new AuthenticationResultPrincipalSerializer(this);
         principalServiceManager = Constraint.isNotNull(manager, "PrincipalServiceManager cannot be null");
         genericSerializer = Constraint.isNotNull(defaultSerializer, "Default serializer cannot be null");
@@ -210,6 +209,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             
             gen.writeStartArray(PRINCIPAL_ARRAY_FIELD);
             for (final Principal p : instance.getSubject().getPrincipals()) {
+                assert p != null;
                 serializePrincipal(gen, p);
             }
             gen.writeEnd();
@@ -218,6 +218,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             if (publicCreds != null && !publicCreds.isEmpty()) {
                 gen.writeStartArray(PUB_CREDS_ARRAY_FIELD);
                 for (final Principal p : publicCreds) {
+                    assert p != null;
                     serializePrincipal(gen, p);
                 }
                 gen.writeEnd();
@@ -227,6 +228,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             if (privateCreds != null && !privateCreds.isEmpty()) {
                 gen.writeStartArray(PRIV_CREDS_ARRAY_FIELD);
                 for (final Principal p : privateCreds) {
+                    assert p != null;
                     serializePrincipal(gen, p);
                 }
                 gen.writeEnd();
@@ -291,6 +293,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             final JsonArray principals = obj.getJsonArray(PRINCIPAL_ARRAY_FIELD);
             if (principals != null) {
                 for (final JsonValue val : principals) {
+                    assert val != null;
                     final Principal principal = deserializePrincipal(val);
                     if (principal != null) {
                         result.getSubject().getPrincipals().add(principal);
@@ -301,6 +304,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             final JsonArray publicCreds = obj.getJsonArray(PUB_CREDS_ARRAY_FIELD);
             if (publicCreds != null) {
                 for (final JsonValue val : publicCreds) {
+                    assert val != null;
                     final Principal principal = deserializePrincipal(val);
                     if (principal != null) {
                         result.getSubject().getPublicCredentials().add(principal);
@@ -311,6 +315,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             final JsonArray privateCreds = obj.getJsonArray(PRIV_CREDS_ARRAY_FIELD);
             if (privateCreds != null) {
                 for (final JsonValue val : privateCreds) {
+                    assert val != null;
                     final Principal principal = deserializePrincipal(val);
                     if (principal != null) {
                         result.getSubject().getPrivateCredentials().add(principal);
@@ -323,7 +328,9 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
                 for (final JsonValue val : x509Creds) {
                     if (val.getValueType() == ValueType.STRING) {
                         try {
-                            final X509Certificate cert = X509Support.decodeCertificate(val.toString());
+                            final String valStr = val.toString();
+                            assert valStr != null;
+                            final X509Certificate cert = X509Support.decodeCertificate(valStr);
                             result.getSubject().getPublicCredentials().add(cert);
                         } catch (final CertificateException e) {
                             log.warn("Unable to parse certificate", e);
@@ -388,6 +395,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
     @Nullable private Principal deserializePrincipal(@Nonnull final JsonValue jsonValue) throws IOException {
         if (jsonValue instanceof JsonObject) {
             final String json = ((JsonObject) jsonValue).toString();
+            assert json != null;
             for (final PrincipalSerializer<? super String> serializer : principalSerializers) {
                 if (serializer.supports(json)) {
                     return serializer.deserialize(json);
@@ -401,4 +409,4 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
         return null;
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultPrincipalDeterminationStrategy.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultPrincipalDeterminationStrategy.java
index ff98afb21..8060a98ff 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultPrincipalDeterminationStrategy.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultPrincipalDeterminationStrategy.java
@@ -25,6 +25,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
+import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.shared.annotation.ParameterName;
 import net.shibboleth.shared.logic.Constraint;
@@ -87,14 +88,14 @@ public class DefaultPrincipalDeterminationStrategy<T extends Principal> implemen
         if (ac == null || ac.getAuthenticationResult() == null) {
             return defaultPrincipal;
         }
-        
-        final AuthenticationFlowDescriptor descriptor = ac.getAvailableFlows().get(
-                ac.getAuthenticationResult().getAuthenticationFlowId());
+        final AuthenticationResult ar = ac.getAuthenticationResult();
+        assert ar != null;
+        final AuthenticationFlowDescriptor descriptor = ac.getAvailableFlows().get(ar.getAuthenticationFlowId());
         if (descriptor == null) {
             return defaultPrincipal;
         }
 
-        final Set<T> principals = ac.getAuthenticationResult().getSupportedPrincipals(principalType);
+        final Set<T> principals = ar.getSupportedPrincipals(principalType);
         if (principals.isEmpty()) {
             return defaultPrincipal;
         }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java
index bd00b94f8..f85896589 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java
@@ -114,7 +114,7 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
 
     /** {@inheritDoc} */
     @Override
-    protected boolean doPreExecute(final ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
         
         if (!super.doPreExecute(profileRequestContext)) {
             return false;
@@ -166,20 +166,22 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
     }
 
     /** {@inheritDoc} */
-    @Override protected void doExecute(final ProfileRequestContext profileRequestContext) {
+    @Override protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
 
-        profileRequestContext.getSubcontext(LockoutManagerContext.class, true).setKey(key);
+        profileRequestContext.getOrCreateSubcontext(LockoutManagerContext.class).setKey(key);
         
         try {
             final HttpServletRequest request = getHttpServletRequest();
             final HttpServletResponse response = getHttpServletResponse();
-            
+            assert response != null && request != null;
+            final AccountLockoutManager lckManager = this.lockoutManager;
+            assert lckManager != null;
             response.setContentType("application/json");
             response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
             
             if ("GET".equals(request.getMethod())) {
                 try {
-                    final boolean lockout = lockoutManager.check(profileRequestContext);
+                    final boolean lockout = lckManager.check(profileRequestContext);
                     response.setStatus(HttpServletResponse.SC_OK);
                     final JsonFactory jsonFactory = new JsonFactory();
                     try (final JsonGenerator g = jsonFactory.createGenerator(
@@ -199,7 +201,7 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
                 
             } else if ("POST".equals(request.getMethod())) {
                 try {
-                    if (lockoutManager.increment(profileRequestContext)) {
+                    if (lckManager.increment(profileRequestContext)) {
                         response.setStatus(HttpServletResponse.SC_NO_CONTENT);
                     } else {
                         throw new IOException();
@@ -211,7 +213,7 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
                 
             } else if ("DELETE".equals(request.getMethod())) {
                 try {
-                    if (lockoutManager.clear(profileRequestContext)) {
+                    if (lckManager.clear(profileRequestContext)) {
                         response.setStatus(HttpServletResponse.SC_NO_CONTENT);
                     } else {
                         throw new IOException();
@@ -242,14 +244,15 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
      */
     @Nullable private AccountLockoutManager getLockoutManager(@Nonnull final RequestContext requestContext) {
         
-        managerId = (String) requestContext.getFlowScope().get(MANAGER_ID);
-        if (managerId == null) {
+        final String mgrId = this.managerId = (String) requestContext.getFlowScope().get(MANAGER_ID);
+        if (mgrId == null) {
             log.warn("{} No {} flow variable found in request", getLogPrefix(), MANAGER_ID);
             return null;
         }
         
         try {
-            final Object bean = requestContext.getActiveFlow().getApplicationContext().getBean(managerId);
+            assert mgrId != null;
+            final Object bean = requestContext.getActiveFlow().getApplicationContext().getBean(mgrId);
             if (bean != null && bean instanceof AccountLockoutManager) {
                 return (AccountLockoutManager) bean;
             }
@@ -257,7 +260,7 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
             
         }
         
-        log.warn("{} No bean of the correct type found named {}", getLogPrefix(), managerId);
+        log.warn("{} No bean of the correct type found named {}", getLogPrefix(), mgrId);
         return null;
     }
 
@@ -274,6 +277,7 @@ public class DoLockoutManagerOperation extends AbstractProfileAction {
             @Nonnull @NotEmpty final String detail) throws IOException {
         
         final HttpServletResponse response = getHttpServletResponse();
+        assert response != null;
         response.setContentType("application/json");
         response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
         response.setStatus(status);
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
index a292735bb..930e53e9d 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
@@ -145,9 +145,10 @@ public class ExternalAuthenticationImpl extends ExternalAuthentication {
         
         attr = request.getAttribute(ATTRIBUTES_KEY);
         if (attr != null && attr instanceof Collection<?>) {
-            extContext.getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
+            final AttributeContext ac = extContext.getOrCreateSubcontext(AttributeContext.class);
+            ac.setUnfilteredIdPAttributes(
                     (Collection<IdPAttribute>) attr);
-            extContext.getSubcontext(AttributeContext.class).setIdPAttributes(
+            ac.setIdPAttributes(
                     (Collection<IdPAttribute>) attr);
         }
         
@@ -174,7 +175,7 @@ public class ExternalAuthenticationImpl extends ExternalAuthentication {
         attr = request.getAttribute(REVOKECONSENT_KEY);
         if (attr != null && attr instanceof Boolean && ((Boolean) attr).booleanValue()) {
             final ConsentManagementContext consentCtx =
-                    profileRequestContext.getSubcontext(ConsentManagementContext.class, true);
+                    profileRequestContext.getOrCreateSubcontext(ConsentManagementContext.class);
             consentCtx.setRevokeConsent(true);
         }
         
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractRemoteUser.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractRemoteUser.java
index 300d94688..a332cfded 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractRemoteUser.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractRemoteUser.java
@@ -18,7 +18,6 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.util.Collection;
-import java.util.Collections;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -27,17 +26,17 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
+import jakarta.servlet.http.HttpServletRequest;
 import net.shibboleth.idp.authn.AbstractExtractionAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UsernameContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 /**
  * An action that extracts an asserted user identity from the incoming request, creates a
  * {@link UsernameContext}, and attaches it to the {@link AuthenticationContext}.
@@ -65,8 +64,8 @@ public class ExtractRemoteUser extends AbstractExtractionAction {
     /** Constructor. */
     public ExtractRemoteUser() {
         checkRemoteUser = true;
-        checkAttributes = Collections.emptyList();
-        checkHeaders = Collections.emptyList();
+        checkAttributes = CollectionSupport.emptyList();
+        checkHeaders = CollectionSupport.emptyList();
     }
     
     /**
@@ -129,7 +128,7 @@ public class ExtractRemoteUser extends AbstractExtractionAction {
             username = request.getRemoteUser();
             if (username != null && !username.isEmpty()) {
                 log.debug("{} User identity extracted from REMOTE_USER: {}", getLogPrefix(), username);
-                authenticationContext.getSubcontext(UsernameContext.class, true).setUsername(
+                authenticationContext.getOrCreateSubcontext(UsernameContext.class).setUsername(
                         applyTransforms(username));
                 return;
             }
@@ -139,7 +138,7 @@ public class ExtractRemoteUser extends AbstractExtractionAction {
             final Object attr = request.getAttribute(s);
             if (attr != null && !attr.toString().isEmpty()) {
                 log.debug("{} User identity extracted from attribute {}: {}", getLogPrefix(), s, attr);
-                authenticationContext.getSubcontext(UsernameContext.class, true).setUsername(
+                authenticationContext.getOrCreateSubcontext(UsernameContext.class).setUsername(
                         applyTransforms(attr.toString()));
                 return;
             }
@@ -149,7 +148,7 @@ public class ExtractRemoteUser extends AbstractExtractionAction {
             username = request.getHeader(s);
             if (username != null && !username.isEmpty()) {
                 log.debug("{} User identity extracted from header {}: {}", getLogPrefix(), s, username);
-                authenticationContext.getSubcontext(UsernameContext.class, true).setUsername(
+                authenticationContext.getOrCreateSubcontext(UsernameContext.class).setUsername(
                         applyTransforms(username));
                 return;
             }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentAddress.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentAddress.java
index 3c13ac813..56ae57571 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentAddress.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentAddress.java
@@ -69,7 +69,7 @@ public class ExtractUserAgentAddress extends AbstractExtractionAction {
             return;
         }
 
-        authenticationContext.getSubcontext(UserAgentContext.class, true).setAddress(
+        authenticationContext.getOrCreateSubcontext(UserAgentContext.class).setAddress(
                 InetAddresses.forString(addressString));
     }
     
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentIdentifier.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentIdentifier.java
index c3abe6099..a83365b70 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentIdentifier.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUserAgentIdentifier.java
@@ -68,7 +68,7 @@ public class ExtractUserAgentIdentifier extends AbstractExtractionAction {
             return;
         }
 
-        authenticationContext.getSubcontext(UserAgentContext.class, true).setIdentifier(applyTransforms(agent));
+        authenticationContext.getOrCreateSubcontext(UserAgentContext.class).setIdentifier(applyTransforms(agent));
     }
     // CheckStyle: ReturnCount ON
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromBasicAuth.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromBasicAuth.java
index 61e4151af..eeb013a57 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromBasicAuth.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromBasicAuth.java
@@ -65,7 +65,7 @@ public class ExtractUsernamePasswordFromBasicAuth extends AbstractExtractionActi
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        final UsernamePasswordContext upCtx = authenticationContext.getSubcontext(UsernamePasswordContext.class, true);
+        final UsernamePasswordContext upCtx = authenticationContext.getOrCreateSubcontext(UsernamePasswordContext.class);
         upCtx.setUsername(null);
         upCtx.setPassword(null);
         
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromFormRequest.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromFormRequest.java
index fa405f4e7..3963decd4 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromFormRequest.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromFormRequest.java
@@ -104,7 +104,7 @@ public class ExtractUsernamePasswordFromFormRequest extends AbstractExtractionAc
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        final UsernamePasswordContext upCtx = authenticationContext.getSubcontext(UsernamePasswordContext.class, true);
+        final UsernamePasswordContext upCtx = authenticationContext.getOrCreateSubcontext(UsernamePasswordContext.class);
         upCtx.setUsername(null);
         upCtx.setPassword(null);
         
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromWSSToken.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromWSSToken.java
index a7895984a..8b0c8a9eb 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromWSSToken.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExtractUsernamePasswordFromWSSToken.java
@@ -41,6 +41,7 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UsernamePasswordContext;
 import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 
@@ -78,7 +79,7 @@ public class ExtractUsernamePasswordFromWSSToken extends AbstractExtractionActio
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
-        
+        assert inboundMessage != null;
         final Pair<String, String> usernamePassword = extractUsernamePassword(inboundMessage);
         if (usernamePassword == null) {
             log.debug("{} inbound message does not contain a username and password", getLogPrefix());
@@ -86,7 +87,7 @@ public class ExtractUsernamePasswordFromWSSToken extends AbstractExtractionActio
             return;
         }
 
-        authenticationContext.getSubcontext(UsernamePasswordContext.class, true)
+        authenticationContext.getOrCreateSubcontext(UsernamePasswordContext.class)
                 .setUsername(usernamePassword.getFirst()).setPassword(usernamePassword.getSecond());
     }
 
@@ -140,7 +141,7 @@ public class ExtractUsernamePasswordFromWSSToken extends AbstractExtractionActio
      * @return the extracted token
      */
     @Nullable private UsernameToken getUsernameToken(@Nonnull final Envelope message) {
-        final Header header = message.getHeader();
+        final Header header = Constraint.isNotNull(message.getHeader(), "Expected a Header");
 
         final List<XMLObject> securityHeaders = header.getUnknownXMLObjects(Security.ELEMENT_NAME);
         if (securityHeaders == null || securityHeaders.size() == 0) {
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
index 4b4274cf3..199e8ce2b 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.authn.impl;
 
 import java.security.Principal;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
@@ -43,8 +42,10 @@ import net.shibboleth.idp.authn.principal.PrincipalEvalPredicate;
 import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
 import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
 import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
+import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
@@ -116,8 +117,14 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
             log.debug("{} Canonical principal name was established as '{}'", getLogPrefix(), canonicalPrincipalName);
         } else if (canonicalPrincipalName == null) {
             final SessionContext sessionCtx = profileRequestContext.getSubcontext(SessionContext.class);
-            if (sessionCtx != null && sessionCtx.getIdPSession() != null) {
-                canonicalPrincipalName = sessionCtx.getIdPSession().getPrincipalName();
+            final IdPSession idpSession;
+            if (sessionCtx != null) {
+                idpSession = sessionCtx.getIdPSession();
+            } else {
+                idpSession = null;
+            }
+            if (idpSession!= null) {
+                canonicalPrincipalName = idpSession.getPrincipalName();
                 log.debug("{} Canonical principal name established from session as '{}'", getLogPrefix(),
                         canonicalPrincipalName);
             }
@@ -181,6 +188,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
     
+        final String canonicalPrincipalName = this.canonicalPrincipalName;
         if (canonicalPrincipalName != null) {
             if (authenticationContext.getRequiredName() != null &&
                     !canonicalPrincipalName.equals(authenticationContext.getRequiredName())) {
@@ -190,7 +198,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
                 return;
             }
             
-            final SubjectContext sc = profileRequestContext.getSubcontext(SubjectContext.class, true);
+            final SubjectContext sc = profileRequestContext.getOrCreateSubcontext(SubjectContext.class);
             sc.setPrincipalName(canonicalPrincipalName);
             
             log.info("{} Principal {} authenticated", getLogPrefix(), canonicalPrincipalName);
@@ -224,13 +232,16 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
                 
         // Maintain a list of each Principal that matches the request.
         final ArrayList<Principal> matches = new ArrayList<>();
-        
+        final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
+        assert ar != null;
         for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
+            final String op = requestedPrincipalCtx.getOperator();
+            assert op != null;
             log.debug("{} Checking result for compatibility with operator '{}' and principal '{}'",
-                    getLogPrefix(), requestedPrincipalCtx.getOperator(), p.getName());
+                    getLogPrefix(), op, p.getName());
             final PrincipalEvalPredicateFactory factory =
-                    requestedPrincipalCtx.getPrincipalEvalPredicateFactoryRegistry().lookup(
-                            p.getClass(), requestedPrincipalCtx.getOperator());
+                    requestedPrincipalCtx.getPrincipalEvalPredicateFactoryRegistry().lookup(p.getClass(), op);
+
             if (factory != null) {
                 final PrincipalEvalPredicate predicate = factory.getPredicate(p);
     
@@ -239,12 +250,12 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
                 // at a time, wrap it to apply the predicate, and then record it if it succeeds.
                 
                 matches.clear();
-                for (final Principal candidate
-                        : authenticationContext.getAuthenticationResult().getSupportedPrincipals(p.getClass())) {
+                for (final Principal candidate : ar.getSupportedPrincipals(p.getClass())) {
+                    assert candidate != null;
                     if (predicate.test(new PrincipalSupportingComponent() {
                         @SuppressWarnings("unchecked")
-                        public <T extends Principal> Set<T> getSupportedPrincipals(final Class<T> c) {
-                            return Collections.<T>singleton((T) candidate);
+                        public @Nonnull <T extends Principal> Set<T> getSupportedPrincipals(@Nonnull final Class<T> c) {
+                            return CollectionSupport.<T>singleton((T) candidate);
                         }
                     })) {
                         log.debug("{} Principal '{}' in authentication result satisfies request for principal '{}'",
@@ -269,8 +280,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
             return null;
         }
         
-        final AuthenticationFlowDescriptor flowDescriptor = authenticationContext.getAvailableFlows().get(
-                authenticationContext.getAuthenticationResult().getAuthenticationFlowId());
+        final AuthenticationFlowDescriptor flowDescriptor = authenticationContext.getAvailableFlows().get(ar.getAuthenticationFlowId());
         return flowDescriptor.getHighestWeighted(matches);
     }
 
@@ -301,4 +311,4 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
         return true;
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthentication.java
index 3db5587c9..e0cb99d19 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthentication.java
@@ -34,6 +34,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
+import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
@@ -193,9 +194,9 @@ public class FinalizeMultiFactorAuthentication extends AbstractAuthenticationAct
         }
         
         authenticationContext.setAuthenticationResult(result);
+        final AuthenticationFlowDescriptor flow = Constraint.isNotNull(authenticationContext.getAttemptedFlow(), "Expected an attempted flow");
         
-        final BiConsumer<ProfileRequestContext,Subject> decorator =
-                authenticationContext.getAttemptedFlow().getSubjectDecorator();
+        final BiConsumer<ProfileRequestContext,Subject> decorator = flow.getSubjectDecorator();
         if (decorator != null) {
             decorator.accept(profileRequestContext, result.getSubject());
         }
@@ -249,6 +250,7 @@ public class FinalizeMultiFactorAuthentication extends AbstractAuthenticationAct
                             
                             final Subject subject = new Subject();
                             for (final AuthenticationResult result : results) {
+                                assert result != null;
                                 subject.getPrincipals().add(new AuthenticationResultPrincipal(result));
                                 subject.getPrincipals().addAll(result.getSubject().getPrincipals());
                                 subject.getPublicCredentials().addAll(result.getSubject().getPublicCredentials());
@@ -256,8 +258,11 @@ public class FinalizeMultiFactorAuthentication extends AbstractAuthenticationAct
                                 allPreviousResults = allPreviousResults && result.isPreviousResult();
                             }
                             
-                            final AuthenticationResult merged = new AuthenticationResult(
-                                    mfaContext.getAuthenticationFlowDescriptor().getId(), subject);
+                            final AuthenticationFlowDescriptor afd = mfaContext.getAuthenticationFlowDescriptor();
+                            assert afd != null;
+                            final String afdId = afd.getId();
+                            assert afdId != null;
+                            final AuthenticationResult merged = new AuthenticationResult(afdId, subject);
                             merged.setPreviousResult(allPreviousResults);
                             return merged;
                         }
@@ -270,4 +275,4 @@ public class FinalizeMultiFactorAuthentication extends AbstractAuthenticationAct
         
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/HTPasswdCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/HTPasswdCredentialValidator.java
index 423b0d5d4..55f05eba9 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/HTPasswdCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/HTPasswdCredentialValidator.java
@@ -99,18 +99,19 @@ public class HTPasswdCredentialValidator extends AbstractUsernamePasswordCredent
         super.doInitialize();
 
         try {
-            if (htPasswdResource == null) {
+            final Resource resource = htPasswdResource;
+            if (resource == null) {
                 throw new ComponentInitializationException("Resource cannot be null");
             }
 
             digester = new StringDigester("SHA1", OutputFormat.BASE64);
             
-            try (final InputStream is = htPasswdResource.getInputStream()) {
+            try (final InputStream is = resource.getInputStream()) {
                 credentialMap.putAll(readCredentials(is));
             }
 
-            if (htPasswdResource.isFile()) {
-                lastModified = htPasswdResource.lastModified();
+            if (resource.isFile()) {
+                lastModified = resource.lastModified();
             } else {
                 htPasswdResource = null;
             }
@@ -195,15 +196,17 @@ public class HTPasswdCredentialValidator extends AbstractUsernamePasswordCredent
      * Check for file refresh.
      */
     private void refreshCredentials() {
-        if (htPasswdResource == null) {
+        final Resource resource = htPasswdResource;
+
+        if (resource == null) {
             // Nothing to do.
             return;
         }
         
         try {
-            if (htPasswdResource.isFile() && htPasswdResource.exists()
-                    && (htPasswdResource.lastModified() > lastModified)) {
-                try (final InputStream is = htPasswdResource.getInputStream()) {
+            if (resource.isFile() && resource.exists()
+                    && (resource.lastModified() > lastModified)) {
+                try (final InputStream is = resource.getInputStream()) {
                     credentialMap.clear();
                     credentialMap.putAll(readCredentials(is));
                 }
@@ -253,4 +256,5 @@ public class HTPasswdCredentialValidator extends AbstractUsernamePasswordCredent
         return credentials;
     }
     
-}
\ No newline at end of file
+}
+
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
index 8a0c06f81..fefa5e322 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
@@ -143,6 +143,7 @@ public class InitializeRequestedPrincipalContext extends AbstractAuthenticationA
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
+        assert authenticationProfileConfig != null;
         final List<Principal> principals =
                 authenticationProfileConfig.getDefaultAuthenticationMethods(profileRequestContext);
         if (principals.isEmpty()) {
@@ -161,4 +162,4 @@ public class InitializeRequestedPrincipalContext extends AbstractAuthenticationA
                 principalCtx.getRequestedPrincipals().size());
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
index 07761375e..3241be0d5 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
@@ -24,7 +24,6 @@ import java.security.Principal;
 import java.security.URIParameter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -51,6 +50,7 @@ import net.shibboleth.idp.authn.context.UsernamePasswordContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -80,7 +80,7 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
     @Nullable private Configuration.Parameters loginConfigParameters;
     
     /** Holder for simple configurations defined by name. */
-    @Nullable @NonnullElements private Collection<String> loginConfigNames;
+    @Nonnull @NonnullElements private Collection<String> loginConfigNames;
     
     /** Application name(s) in JAAS configuration to use. */
     @Nonnull @NonnullElements private Collection<Pair<String,Subject>> loginConfigurations;
@@ -91,8 +91,8 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
     /** Constructor. */
     public JAASCredentialValidator() {
         // For compatibility with V2.
-        loginConfigNames = Collections.singletonList("ShibUserPassAuth");
-        loginConfigurations = Collections.emptyList();
+        loginConfigNames = CollectionSupport.singletonList("ShibUserPassAuth");
+        loginConfigurations = CollectionSupport.emptyList();
     }
     
     /**
@@ -162,11 +162,12 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
             for (final Pair<String,Collection<Principal>> config : configs) {
                 final String trimmed = StringSupport.trimOrNull(config.getFirst());
                 if (trimmed != null) {
-                    if (config.getSecond() == null || config.getSecond().isEmpty()) {
+                    final Collection<Principal> second = config.getSecond();
+                    if (second == null || second.isEmpty()) {
                         loginConfigurations.add(new Pair<>(trimmed, null));
                     } else {
                         final Subject subject = new Subject();
-                        subject.getPrincipals().addAll(config.getSecond());
+                        subject.getPrincipals().addAll(second);
                         loginConfigurations.add(new Pair<>(trimmed, subject));
                     }
                 }
@@ -244,11 +245,12 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
         
         for (final Pair<String,Subject> loginConfig : configs) {
             
-            if (!isAcceptable(requestedPrincipalCtx, loginConfig.getSecond(), loginConfig.getFirst())) {
+            final String currentLoginConfigName = loginConfig.getFirst();
+            assert currentLoginConfigName != null;
+            if (!isAcceptable(requestedPrincipalCtx, loginConfig.getSecond(), currentLoginConfigName)) {
                 continue;
             }
 
-            final String currentLoginConfigName = loginConfig.getFirst();
 
             try {
                 log.debug("{} Attempting to authenticate user '{}' via '{}'", getLogPrefix(),
@@ -302,10 +304,12 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
         final javax.security.auth.login.LoginContext jaasLoginCtx;
         
         if (getLoginConfigType() != null) {
+            final Configuration.Parameters params = getLoginConfigParameters();
+            assert params != null;
             log.debug("{} Using custom JAAS configuration type {} with parameters of type {}", getLogPrefix(),
-                    getLoginConfigType(), getLoginConfigParameters().getClass().getName());
+                    getLoginConfigType(), params.getClass().getName());
             final Configuration loginConfig =
-                    Configuration.getInstance(getLoginConfigType(), getLoginConfigParameters());
+                    Configuration.getInstance(getLoginConfigType(), params);
             jaasLoginCtx = new javax.security.auth.login.LoginContext(loginConfigName, null,
                     new SimpleCallbackHandler(usernamePasswordContext), loginConfig);
         } else {
@@ -316,7 +320,9 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
 
         jaasLoginCtx.login();
         
-        return jaasLoginCtx.getSubject();
+        final Subject result = jaasLoginCtx.getSubject();
+        assert result != null;
+        return result;
     }
 
     /**
@@ -377,10 +383,12 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
                     ncb.setName(context.getTransformedUsername());
                 } else if (cb instanceof PasswordCallback) {
                     final PasswordCallback pcb = (PasswordCallback) cb;
-                    pcb.setPassword(context.getPassword().toCharArray());
+                    final String password = context.getPassword();
+                    assert password != null;
+                    pcb.setPassword(password.toCharArray());
                 }
             }
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/KerberosCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/KerberosCredentialValidator.java
index 253c131c7..8da8a6b47 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/KerberosCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/KerberosCredentialValidator.java
@@ -355,7 +355,9 @@ public class KerberosCredentialValidator extends AbstractUsernamePasswordCredent
                     ncb.setName(context.getTransformedUsername());
                 } else if (cb instanceof PasswordCallback) {
                     final PasswordCallback pcb = (PasswordCallback) cb;
-                    pcb.setPassword(context.getPassword().toCharArray());
+                    final String password = context.getPassword();
+                    assert password != null;
+                    pcb.setPassword(password.toCharArray());
                 }
             }
         }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidator.java
index 2023948d3..d48f9f17b 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidator.java
@@ -60,7 +60,7 @@ public class LDAPCredentialValidator extends AbstractUsernamePasswordCredentialV
     @Nonnull private final Logger log = LoggerFactory.getLogger(LDAPCredentialValidator.class);
 
     /** LDAP authenticator. */
-    @Nonnull private Authenticator authenticator;
+    @NonnullAfterInit private Authenticator authenticator;
 
     /** Attributes to return from authentication. */
     @Nullable private String[] returnAttributes;
@@ -148,9 +148,14 @@ public class LDAPCredentialValidator extends AbstractUsernamePasswordCredentialV
         log.debug("{} Attempting to authenticate user {}", getLogPrefix(), username);
         final VelocityContext context = new VelocityContext();
         context.put("usernamePasswordContext", usernamePasswordContext);
-        final char[] password = passwordLookupStrategy != null ?
-          passwordLookupStrategy.apply(profileRequestContext) :
-          usernamePasswordContext.getPassword().toCharArray();
+        final char[] password;
+        if (passwordLookupStrategy != null) {
+            password = passwordLookupStrategy.apply(profileRequestContext);
+        } else {
+            final String ctxPassword = usernamePasswordContext.getPassword();
+            assert ctxPassword != null;
+            password = ctxPassword.toCharArray();
+        }
         final AuthenticationRequest request = new AuthenticationRequest(
           new User(username, context), new Credential(password), returnAttributes);
         final AuthenticationResponse response;
@@ -167,7 +172,7 @@ public class LDAPCredentialValidator extends AbstractUsernamePasswordCredentialV
         }
 
         log.debug("{} Authentication response {}", getLogPrefix(), response);
-        authenticationContext.getSubcontext(LDAPResponseContext.class, true).setAuthenticationResponse(response);
+        authenticationContext.getOrCreateSubcontext(LDAPResponseContext.class).setAuthenticationResponse(response);
         if (response.isSuccess()) {
             log.info("{} Login by '{}' succeeded", getLogPrefix(), username);
             if (response.getAccountState() != null) {
@@ -229,4 +234,4 @@ public class LDAPCredentialValidator extends AbstractUsernamePasswordCredentialV
         return super.populateSubject(subject, usernamePasswordContext);
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateAuthenticationContext.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateAuthenticationContext.java
index 10fc254ff..5202498a7 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateAuthenticationContext.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateAuthenticationContext.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.authn.impl;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -35,6 +34,7 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
 import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactoryRegistry;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -75,7 +75,7 @@ public class PopulateAuthenticationContext extends AbstractAuthenticationAction
     
     /** Constructor. */
     public PopulateAuthenticationContext() {
-        availableFlows = Collections.emptyList();
+        availableFlows = CollectionSupport.emptyList();
         potentialFlowsLookupStrategy = FunctionSupport.constant(Collections.emptyList());
         activeFlowsLookupStrategy = new AuthenticationFlowsLookupFunction();
     }
@@ -87,7 +87,7 @@ public class PopulateAuthenticationContext extends AbstractAuthenticationAction
      */
     public void setAvailableFlows(@Nonnull @NonnullElements final Collection<AuthenticationFlowDescriptor> flows) {
         checkSetterPreconditions();
-        availableFlows = List.copyOf(Constraint.isNotNull(flows, "Flow collection cannot be null"));
+        availableFlows = CollectionSupport.copyToList(Constraint.isNotNull(flows, "Flow collection cannot be null"));
     }
 
     /**
@@ -119,7 +119,7 @@ public class PopulateAuthenticationContext extends AbstractAuthenticationAction
      * 
      * @return predicate factory registry
      */
-    @Nonnull public PrincipalEvalPredicateFactoryRegistry getPrincipalPredicateFactoryEvalRegistry() {
+    @Nullable public PrincipalEvalPredicateFactoryRegistry getPrincipalPredicateFactoryEvalRegistry() {
         return evalRegistry;
     }
     
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContext.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContext.java
index 107abb40b..8497de567 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContext.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContext.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.BiPredicate;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -182,8 +183,16 @@ public class PopulateMultiFactorAuthenticationContext extends AbstractAuthentica
             
             if (input != null) {
                 final AuthenticationContext ac = input.getSubcontext(AuthenticationContext.class);
-                if (ac != null && ac.getAttemptedFlow() != null) {
-                    final AuthenticationResult mfaResult = ac.getActiveResults().get(ac.getAttemptedFlow().getId());
+                final AuthenticationFlowDescriptor acf;
+                if (ac != null) {
+                    acf = ac.getAttemptedFlow();
+                }
+                else {
+                    acf = null;
+                }
+                if (acf != null) {
+                    assert ac != null;
+                    final AuthenticationResult mfaResult = ac.getActiveResults().get(acf.getId());
                     if (mfaResult != null) {
                         if (ac.isForceAuthn()) {
                             log.debug("{} Ignoring active result due to forced authentication requirement",
@@ -231,13 +240,14 @@ public class PopulateMultiFactorAuthenticationContext extends AbstractAuthentica
             if (descriptor != null) {
                 if (descriptor.test(profileRequestContext)) {
                     if (descriptor.isResultActive(candidate)) {
+                        final BiPredicate<ProfileRequestContext, AuthenticationResult> revocationCondition = descriptor.getRevocationCondition();
                         if (authenticationContext.getMaxAge() != null
                                 && candidate.getAuthenticationInstant().plus(
                                         authenticationContext.getMaxAge()).isBefore(Instant.now())) {
                             log.debug("{} Ignoring active result from login flow {} due to maxAge on request",
                                     getLogPrefix(), candidate.getAuthenticationFlowId());
-                        } else if (descriptor.getRevocationCondition() != null &&
-                                descriptor.getRevocationCondition().test(profileRequestContext, candidate)) {
+                        } else if (revocationCondition != null &&
+                                revocationCondition.test(profileRequestContext, candidate)) {
                             log.debug("{} Ignoring active but revoked result from login flow {}", getLogPrefix(),
                                     candidate.getAuthenticationFlowId());
                         } else {
@@ -258,4 +268,4 @@ public class PopulateMultiFactorAuthenticationContext extends AbstractAuthentica
         }
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateSubjectCanonicalizationContext.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateSubjectCanonicalizationContext.java
index 0eeab9970..511bf6b33 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateSubjectCanonicalizationContext.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PopulateSubjectCanonicalizationContext.java
@@ -18,8 +18,6 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
 
 import javax.annotation.Nonnull;
 
@@ -30,6 +28,7 @@ import net.shibboleth.idp.authn.AbstractSubjectCanonicalizationAction;
 import net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -51,7 +50,7 @@ public class PopulateSubjectCanonicalizationContext extends AbstractSubjectCanon
 
     /** Constructor. */
     PopulateSubjectCanonicalizationContext() {
-        availableFlows = Collections.emptyList();
+        availableFlows = CollectionSupport.emptyList();
     }
     
     /**
@@ -62,7 +61,7 @@ public class PopulateSubjectCanonicalizationContext extends AbstractSubjectCanon
     public void setAvailableFlows(
             @Nonnull @NonnullElements final Collection<SubjectCanonicalizationFlowDescriptor> flows) {
         checkSetterPreconditions();
-        availableFlows = List.copyOf(Constraint.isNotNull(flows, "Flow collection cannot be null"));
+        availableFlows = CollectionSupport.copyToList(Constraint.isNotNull(flows, "Flow collection cannot be null"));
     }
         
     /** {@inheritDoc} */
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PreserveAuthenticationFlowState.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PreserveAuthenticationFlowState.java
index 854b3271e..233b31024 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PreserveAuthenticationFlowState.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PreserveAuthenticationFlowState.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.authn.impl;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
@@ -29,9 +28,11 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
+import jakarta.servlet.http.HttpServletRequest;
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -56,7 +57,7 @@ public class PreserveAuthenticationFlowState extends AbstractAuthenticationActio
     
     /** Constructor. */
     PreserveAuthenticationFlowState() {
-        parameterNames = Collections.emptyList();
+        parameterNames = CollectionSupport.emptyList();
     }
     
     /**
@@ -67,7 +68,7 @@ public class PreserveAuthenticationFlowState extends AbstractAuthenticationActio
     public void setParameterNames(@Nullable @NonnullElements final Collection<String> names) {
         checkSetterPreconditions();
         if (names == null) {
-            parameterNames = Collections.emptyList();
+            parameterNames = CollectionSupport.emptyList();
         } else {
             parameterNames = new ArrayList<>(StringSupport.normalizeStringCollection(names));
         }
@@ -96,8 +97,10 @@ public class PreserveAuthenticationFlowState extends AbstractAuthenticationActio
 
         final Map<String,Object> state = authenticationContext.getAuthenticationStateMap();
         state.clear();
+        final HttpServletRequest request = getHttpServletRequest();
+        assert request != null;
 
-        final Map<String,String[]> params = getHttpServletRequest().getParameterMap();
+        final Map<String,String[]> params = request.getParameterMap();
         for (final String name : parameterNames) {
             final String[] values = params.get(name);
             if (values != null) {
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RelyingPartyMapJAASLoginConfigStrategy.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RelyingPartyMapJAASLoginConfigStrategy.java
index 1a91847f1..1df06af79 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RelyingPartyMapJAASLoginConfigStrategy.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RelyingPartyMapJAASLoginConfigStrategy.java
@@ -18,10 +18,10 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.security.auth.Subject;
 
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -31,6 +31,7 @@ import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.profile.context.navigate.AbstractRelyingPartyLookupFunction;
 import net.shibboleth.shared.annotation.ParameterName;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -84,28 +85,28 @@ public class RelyingPartyMapJAASLoginConfigStrategy
 
     /** {@inheritDoc} */
     @Nonnull public Collection<Pair<String, Subject>> apply(
-            @Nonnull final ProfileRequestContext profileRequestContext) {
+            final @Nullable ProfileRequestContext profileRequestContext) {
 
         final RelyingPartyContext relyingPartyContext =
                 getRelyingPartyContextLookupStrategy().apply(profileRequestContext);
         if (relyingPartyContext == null) {
             log.warn("No RelyingPartyContext was available, using default config name");
-            return Collections.singleton(new Pair<>(defaultConfigName, (Subject)null));
+            return CollectionSupport.singleton(new Pair<>(defaultConfigName, (Subject)null));
         }
 
         final String relyingPartyId = relyingPartyContext.getRelyingPartyId();
         if (relyingPartyId == null) {
             log.warn("No relying party ID was available, using default config name");
-            return Collections.singleton(new Pair<>(defaultConfigName, (Subject)null));
+            return CollectionSupport.singleton(new Pair<>(defaultConfigName, (Subject)null));
         }
 
         final String config = StringSupport.trimOrNull(relyingPartyMap.get(relyingPartyId));
         if (config != null) {
             log.debug("For relying party ID '{}' resolved JAAS config name '{}'", relyingPartyId, config);
-            return Collections.singleton(new Pair<>(config, (Subject)null));
+            return CollectionSupport.singleton(new Pair<>(config, (Subject)null));
         }
         log.debug("For relying party ID '{}' resolved no JAAS config name, returning default", relyingPartyId);
-        return Collections.singleton(new Pair<>(defaultConfigName, (Subject)null));
+        return CollectionSupport.singleton(new Pair<>(defaultConfigName, (Subject)null));
     }
 
 }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
index 4a39701aa..5f4b2fec2 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
@@ -22,9 +22,7 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Enumeration;
-import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -35,6 +33,11 @@ import org.slf4j.Logger;
 
 import com.google.common.base.Strings;
 
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.ExternalAuthentication;
 import net.shibboleth.idp.authn.ExternalAuthenticationException;
@@ -42,15 +45,10 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
-import jakarta.servlet.ServletConfig;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServlet;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
 /**
  * Extracts authentication information from the request and returns it via the IdP's external authentication
  * interface.
@@ -110,8 +108,8 @@ public class RemoteUserAuthServlet extends HttpServlet {
     /** Constructor. */
     public RemoteUserAuthServlet() {
         checkRemoteUser = true;
-        checkAttributes = Collections.emptyList();
-        checkHeaders = Collections.emptyList();
+        checkAttributes = CollectionSupport.emptyList();
+        checkHeaders = CollectionSupport.emptyList();
     }
 
     /**
@@ -129,7 +127,7 @@ public class RemoteUserAuthServlet extends HttpServlet {
      * @param attributes    list of request attributes to check
      */
     public void setCheckAttributes(@Nonnull @NonnullElements final Collection<String> attributes) {
-        checkAttributes = List.copyOf(attributes);
+        checkAttributes = CollectionSupport.copyToList(attributes);
     }
 
     /**
@@ -138,7 +136,7 @@ public class RemoteUserAuthServlet extends HttpServlet {
      * @param headers list of request headers to check
      */
     public void setCheckHeaders(@Nonnull @NonnullElements final Collection<String> headers) {
-        checkHeaders = List.copyOf(headers);
+        checkHeaders = CollectionSupport.copyToList(headers);
     }
     
     /**
@@ -234,6 +232,7 @@ public class RemoteUserAuthServlet extends HttpServlet {
     protected void service(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse)
             throws ServletException, IOException {
         
+        assert httpRequest != null && httpResponse != null;
         try {
             final String key = ExternalAuthentication.startExternalAuthentication(httpRequest);
 
@@ -314,6 +313,7 @@ public class RemoteUserAuthServlet extends HttpServlet {
                         while (methods.hasMoreElements()) {
                             final String method = methods.nextElement();
                             if (!Strings.isNullOrEmpty(method)) {
+                                assert method != null;
                                 final Principal p = getPrincipal(authnFlow, method);
                                 if (p != null) {
                                     log.debug("{}: Successfully processed authentication method from header {}: {}",
@@ -385,4 +385,4 @@ public class RemoteUserAuthServlet extends HttpServlet {
         return null;
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectAuthenticationFlow.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectAuthenticationFlow.java
index 73b8c50c4..4b18104a9 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectAuthenticationFlow.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectAuthenticationFlow.java
@@ -120,10 +120,9 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
         
         noProxying = authenticationContext.getProxyCount() != null && authenticationContext.getProxyCount() == 0;
         
-        requestedPrincipalCtx = authenticationContext.getSubcontext(RequestedPrincipalContext.class);
-        if (requestedPrincipalCtx != null) {
-            if (requestedPrincipalCtx.getOperator() == null
-                    || requestedPrincipalCtx.getRequestedPrincipals().isEmpty()) {
+        final RequestedPrincipalContext rpc = requestedPrincipalCtx = authenticationContext.getSubcontext(RequestedPrincipalContext.class);
+        if (rpc != null) {
+            if (rpc.getOperator() == null || rpc.getRequestedPrincipals().isEmpty()) {
                 requestedPrincipalCtx = null;
             }
         }
@@ -135,12 +134,11 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
         
         // Detect a previous attempted flow, and move it to the intermediate collection.
         // This will prevent re-selecting the same (probably failed) flow again as part of
-        // general flow selection. A flow might signal to explicitly re-run another flow anyway.
-        if (authenticationContext.getAttemptedFlow() != null) {
-            log.info("{} Moving incomplete flow {} to intermediate set", getLogPrefix(),
-                    authenticationContext.getAttemptedFlow().getId());
-            authenticationContext.getIntermediateFlows().put(
-                    authenticationContext.getAttemptedFlow().getId(), authenticationContext.getAttemptedFlow());
+        // general flow selection. A flow might signal to explicitly re-run another flow anyway
+        final AuthenticationFlowDescriptor flow = authenticationContext.getAttemptedFlow();
+        if (flow != null) {
+            log.info("{} Moving incomplete flow {} to intermediate set", getLogPrefix(), flow.getId());
+            authenticationContext.getIntermediateFlows().put(flow.getId(), authenticationContext.getAttemptedFlow());
         }
         
         return true;
@@ -206,10 +204,12 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
             }
         }
         
+        final RequestedPrincipalContext rpc = requestedPrincipalCtx;
         if (activeResult != null) {
-            if (requestedPrincipalCtx != null) {
-                for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
-                    final PrincipalEvalPredicate predicate = requestedPrincipalCtx.getPredicate(p);
+            if (rpc != null) {
+                for (final Principal p : rpc.getRequestedPrincipals()) {
+                    assert p!= null;
+                    final PrincipalEvalPredicate predicate = rpc.getPredicate(p);
                     if (predicate != null) {
                         if (predicate.test(activeResult)) {
                             selectActiveResult(profileRequestContext, authenticationContext, activeResult);
@@ -218,7 +218,7 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                     } else {
                         log.warn("{} Configuration does not support requested principal evaluation with "
                                 + "operator '{}' and type '{}'", getLogPrefix(),
-                                requestedPrincipalCtx.getOperator(), p.getClass());
+                                rpc.getOperator(), p.getClass());
                     }
                 }
             } else {
@@ -234,9 +234,10 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
             log.error("{} Signaled flow {} does not support passive authentication", getLogPrefix(), flow.getId());
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_PASSIVE);
             return;
-        } else if (requestedPrincipalCtx != null) {
-            for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
-                final PrincipalEvalPredicate predicate = requestedPrincipalCtx.getPredicate(p);
+        } else if (rpc != null) {
+            for (final Principal p : rpc.getRequestedPrincipals()) {
+                assert p != null;
+                final PrincipalEvalPredicate predicate = rpc.getPredicate(p);
                 if (predicate != null) {
                     if (predicate.test(flow) && flow.test(profileRequestContext)) {
                         selectInactiveFlow(profileRequestContext, authenticationContext, flow);
@@ -244,7 +245,7 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                     }
                 } else {
                     log.warn("{} Configuration does not support requested principal evaluation with "
-                            + "operator '{}' and type '{}'", getLogPrefix(), requestedPrincipalCtx.getOperator(),
+                            + "operator '{}' and type '{}'", getLogPrefix(), rpc.getOperator(),
                             p.getClass());
                 }
             }
@@ -293,7 +294,8 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
         for (final AuthenticationResult activeResult : authenticationContext.getActiveResults().values()) {
             if (activeResult.test(profileRequestContext)) {
                 resultToSelect = activeResult;
-                if (preferredPrincipalCtx == null || preferredPrincipalCtx.isAcceptable(activeResult)) {
+                final PreferredPrincipalContext ppCtx = preferredPrincipalCtx;
+                if (ppCtx == null || ppCtx.isAcceptable(activeResult)) {
                     break;
                 }
             } else {
@@ -341,7 +343,8 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                     if (!noProxying || !flow.isProxyScopingEnforced()) {
                         if (flow.test(profileRequestContext)) {
                             selectedFlow = flow;
-                            if (preferredPrincipalCtx == null || preferredPrincipalCtx.isAcceptable(flow)) {
+                            final PreferredPrincipalContext ppCtx = preferredPrincipalCtx;
+                            if (ppCtx == null || ppCtx.isAcceptable(flow)) {
                                 break;
                             }
                         }
@@ -364,9 +367,11 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
             @Nonnull final AuthenticationContext authenticationContext,
             @Nonnull final AuthenticationFlowDescriptor descriptor) {
 
-        log.debug("{} Selecting inactive authentication flow {}", getLogPrefix(), descriptor.getId());
+        final String id = descriptor.getId();
+        assert id != null;
+        log.debug("{} Selecting inactive authentication flow {}", getLogPrefix(), id);
         authenticationContext.setAttemptedFlow(descriptor);
-        ActionSupport.buildEvent(profileRequestContext, descriptor.getId());
+        ActionSupport.buildEvent(profileRequestContext, id);
     }    
     
     /**
@@ -396,8 +401,10 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
     private void doSelectRequestedPrincipals(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
         
+        final RequestedPrincipalContext rpCtx = requestedPrincipalCtx;
+        assert rpCtx != null;
         log.debug("{} Specific principals requested with '{}' operator: {}", getLogPrefix(),
-                requestedPrincipalCtx.getOperator(), requestedPrincipalCtx.getRequestedPrincipals());
+                rpCtx.getOperator(), rpCtx.getRequestedPrincipals());
 
         
         if (authenticationContext.isForceAuthn()) {
@@ -422,13 +429,15 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
             @Nonnull final AuthenticationContext authenticationContext) {
 
         final Map<String,AuthenticationFlowDescriptor> potentialFlows = authenticationContext.getPotentialFlows();
+        final RequestedPrincipalContext rpCtx = requestedPrincipalCtx;
+        assert rpCtx != null;
         
         // Check each flow for compatibility with request. Don't check for an active result also.
         // Also omit anything in the intermediates collection already.
-        for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
+        for (final Principal p : rpCtx.getRequestedPrincipals()) {
             log.debug("{} Checking for inactive flow compatible with operator '{}' and principal '{}'",
-                    getLogPrefix(), requestedPrincipalCtx.getOperator(), p.getName());
-            final PrincipalEvalPredicate predicate = requestedPrincipalCtx.getPredicate(p);
+                    getLogPrefix(), rpCtx.getOperator(), p.getName());
+            final PrincipalEvalPredicate predicate = rpCtx.getPredicate(p);
             if (predicate != null) {
                 for (final AuthenticationFlowDescriptor descriptor : potentialFlows.values()) {
                     if (!authenticationContext.getIntermediateFlows().containsKey(descriptor.getId())
@@ -445,7 +454,7 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                 }
             } else {
                 log.warn("{} Configuration does not support requested principal evaluation with "
-                        + "operator '{}' and type '{}'", getLogPrefix(), requestedPrincipalCtx.getOperator(),
+                        + "operator '{}' and type '{}'", getLogPrefix(), rpCtx.getOperator(),
                         p.getClass());
             }
         }
@@ -470,14 +479,17 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
             @Nonnull final AuthenticationContext authenticationContext,
             @Nonnull @NonnullElements final Map<String,AuthenticationResult> activeResults) {
 
+        final RequestedPrincipalContext rpCtx = requestedPrincipalCtx;
+        assert rpCtx != null;
+
         if (favorSSO) {
             log.debug("{} Giving priority to active results that meet request requirements");
             
             // Check each active result for compatibility with request.
-            for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
+            for (final Principal p : rpCtx.getRequestedPrincipals()) {
                 log.debug("{} Checking for an active result compatible with operator '{}' and principal '{}'",
-                        getLogPrefix(), requestedPrincipalCtx.getOperator(), p.getName());
-                final PrincipalEvalPredicate predicate = requestedPrincipalCtx.getPredicate(p);
+                        getLogPrefix(), rpCtx.getOperator(), p.getName());
+                final PrincipalEvalPredicate predicate = rpCtx.getPredicate(p);
                 if (predicate != null) {
                     for (final AuthenticationResult result : activeResults.values()) {
                         if (result.test(profileRequestContext) &&
@@ -490,7 +502,7 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                     }
                 } else {
                     log.warn("{} Configuration does not support requested principal evaluation with "
-                            + "operator '{}' and type '{}'", getLogPrefix(), requestedPrincipalCtx.getOperator(),
+                            + "operator '{}' and type '{}'", getLogPrefix(), rpCtx.getOperator(),
                             p.getClass());
                 }
             }
@@ -506,11 +518,11 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
         // In this branch, we check each flow for compatibility *and* then double check to see if an active
         // result from that flow also exists and is compatible. This favors a matching inactive flow that is
         // higher in request precedence than an active result.
-        for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
+        for (final Principal p : rpCtx.getRequestedPrincipals()) {
             log.debug("{} Checking for an inactive flow or active result compatible with "
-                    + "operator '{}' and principal '{}'", getLogPrefix(), requestedPrincipalCtx.getOperator(),
+                    + "operator '{}' and principal '{}'", getLogPrefix(), rpCtx.getOperator(),
                     p.getName());
-            final PrincipalEvalPredicate predicate = requestedPrincipalCtx.getPredicate(p);
+            final PrincipalEvalPredicate predicate = rpCtx.getPredicate(p);
             if (predicate != null) {
                 for (final AuthenticationFlowDescriptor descriptor : potentialFlows.values()) {
                     if (!authenticationContext.getIntermediateFlows().containsKey(descriptor.getId())
@@ -541,7 +553,7 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
                 }
             } else {
                 log.warn("{} Configuration does not support requested principal evaluation with "
-                        + "operator '{}' and type '{}'", getLogPrefix(), requestedPrincipalCtx.getOperator(),
+                        + "operator '{}' and type '{}'", getLogPrefix(), rpCtx.getOperator(),
                         p.getClass());
             }
         }
@@ -553,4 +565,4 @@ public class SelectAuthenticationFlow extends AbstractAuthenticationAction {
     }
 // Checkstyle: MethodLength|CyclomaticComplexity|ReturnCount ON
         
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
index 9073d30af..b56b3949a 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
@@ -58,11 +58,12 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
         
         // Detect a previous attempted flow, and move it to the intermediate collection.
         // This will prevent re-selecting the same (probably failed) flow again.
-        if (c14nContext.getAttemptedFlow() != null) {
+        final SubjectCanonicalizationFlowDescriptor flow = c14nContext.getAttemptedFlow(); 
+        if (flow != null) {
             log.info("{} Moving incomplete flow {} to intermediate set, reselecting a different one", getLogPrefix(),
-                    c14nContext.getAttemptedFlow().getId());
+                    flow.getId());
             c14nContext.getIntermediateFlows().put(
-                    c14nContext.getAttemptedFlow().getId(), c14nContext.getAttemptedFlow());
+                    flow.getId(), c14nContext.getAttemptedFlow());
         }
         
         return super.doPreExecute(profileRequestContext, c14nContext);
@@ -79,9 +80,11 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_POTENTIAL_FLOW);
             return;
         }
+        final String flowId = flow.getId();
+        assert flowId != null;
 
-        log.debug("{} Selecting canonicalization flow {}", getLogPrefix(), flow.getId());
-        ActionSupport.buildEvent(profileRequestContext, flow.getId());
+        log.debug("{} Selecting canonicalization flow {}", getLogPrefix(), flowId);
+        ActionSupport.buildEvent(profileRequestContext, flowId);
     }
 
     /**
@@ -103,8 +106,9 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
                 if (flow.test(profileRequestContext)) {
                     return flow;
                 }
+                final Exception ctxException = c14nContext.getException();
                 log.debug("{} Canonicalization flow {} was not applicable: {}", getLogPrefix(), flow.getId(),
-                        c14nContext.getException() != null ? c14nContext.getException().getMessage()
+                        ctxException!= null ? ctxException.getMessage()
                                 : "reason unknown");
                 c14nContext.setException(null);
                 
@@ -116,4 +120,4 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
         return null;
     }
         
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
index e85af0290..b9add1757 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
@@ -22,6 +22,10 @@ import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.security.auth.Subject;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.authn.AbstractSubjectCanonicalizationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
@@ -29,12 +33,6 @@ import net.shibboleth.idp.authn.SubjectCanonicalizationException;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import net.shibboleth.shared.primitive.LoggerFactory;
-
 /**
  * An action that operates on a {@link SubjectCanonicalizationContext} child of the current
  * {@link ProfileRequestContext}, and transforms the input {@link javax.security.auth.Subject}
@@ -49,7 +47,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizationAction {
 
     /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(SelectAuthenticationFlow.class);
+   // @Nonnull private final Logger log = LoggerFactory.getLogger(SelectAuthenticationFlow.class);
 
     /** Supplies logic for pre-execute test. */
     @Nonnull private final ActivationCondition embeddedPredicate;
@@ -68,7 +66,9 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizati
             @Nonnull final SubjectCanonicalizationContext c14nContext) {
 
         if (embeddedPredicate.apply(profileRequestContext, c14nContext, true)) {
-            usernamePrincipal = c14nContext.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
+            final Subject c14CtxSubject = c14nContext.getSubject();
+            assert c14CtxSubject != null;
+            usernamePrincipal = c14CtxSubject.getPrincipals(UsernamePrincipal.class).iterator().next();
             return super.doPreExecute(profileRequestContext, c14nContext);
         }
         
@@ -79,7 +79,7 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizati
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext, 
             @Nonnull final SubjectCanonicalizationContext c14nContext) {
-        
+        assert usernamePrincipal != null;
         c14nContext.setPrincipalName(applyTransforms(usernamePrincipal.getName()));
     }
      
@@ -114,8 +114,9 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizati
                 @Nonnull final SubjectCanonicalizationContext c14nContext, final boolean duringAction) {
 
             final Set<UsernamePrincipal> usernames;
-            if (c14nContext.getSubject() != null) {
-                usernames = c14nContext.getSubject().getPrincipals(UsernamePrincipal.class);
+            final Subject c14CtxSubject = c14nContext.getSubject();
+            if (c14CtxSubject  != null) {
+                usernames = c14CtxSubject .getPrincipals(UsernamePrincipal.class);
             } else {
                 usernames = null;
             }
@@ -141,4 +142,4 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizati
         
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
index eb622eefc..850f25cb2 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
@@ -71,7 +71,7 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
     @Nonnull private Function<ProfileRequestContext,Duration> counterIntervalLookupStrategy;
 
     /** Lookup function for duration of lockout. */
-    @Nonnull private Function<ProfileRequestContext,Duration> lockoutDurationLookupStrategy;
+    @NonnullAfterInit private Function<ProfileRequestContext,Duration> lockoutDurationLookupStrategy;
     
     /** Controls whether attempts against locked accounts extend duration. */
     private boolean extendLockoutDuration;
@@ -79,8 +79,15 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
     /** Constructor. */
     public StorageBackedAccountLockoutManager() {
         setMaxAttempts(5);
+        // this paradigm proves to the null checkee that these fields are non null
+        assert maxAttemptsLookupStrategy != null;
+        maxAttemptsLookupStrategy = maxAttemptsLookupStrategy;
         setCounterInterval(Duration.ofMinutes(5));
+        assert counterIntervalLookupStrategy != null;
+        counterIntervalLookupStrategy = counterIntervalLookupStrategy;
         setLockoutDuration(Duration.ofMinutes(5));
+        assert lockoutDurationLookupStrategy != null;
+        lockoutDurationLookupStrategy = lockoutDurationLookupStrategy;
     }
 
     /**
@@ -208,19 +215,32 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
         }
     }
     
+    /** Guaranteed non null value for {@link #lockoutKeyStrategy} .
+     * We check for non-nullness in {@link #doInitialize()} so it suffices to check
+     * Component state.
+     * @return
+     */
+    @Nonnull private Function<ProfileRequestContext, String> getLockoutKeyStrategy() {
+        checkComponentActive();
+        assert lockoutKeyStrategy != null;
+        return lockoutKeyStrategy;
+    }
+
     /** {@inheritDoc} */
     public boolean check(@Nonnull final ProfileRequestContext profileRequestContext) {
-        final String key = lockoutKeyStrategy.apply(profileRequestContext);
+        final String key = getLockoutKeyStrategy().apply(profileRequestContext);
         if (key == null) {
             log.warn("No lockout key returned for request");
             return false;
         }
+        final String id = getId();
+        assert id != null;
 
         // Read back account state. No state obviously means no lockout, but in the case of errors
         // that does fail open. Of course, in-memory won't fail...
         StorageRecord<?> sr = null;
         try {
-            sr = storageService.read(getId(), key);
+            sr = storageService.read(id, key);
         } catch (final IOException e) {
             sr = null;
             log.error("Error reading back account lockout state for '{}'", key, e);
@@ -238,7 +258,8 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
                 // If that's under the lockout duration, we're locked out.
                 final long lockoutDuration = lockoutDurationLookupStrategy.apply(profileRequestContext).toMillis();
                 final long counterInterval = counterIntervalLookupStrategy.apply(profileRequestContext).toMillis();
-                final long lastAttempt = sr.getExpiration() - Math.max(lockoutDuration, counterInterval);
+                final Long exp = Constraint.isNotNull(sr.getExpiration(), "Stored expiration canot be null");
+                final long lastAttempt = exp - Math.max(lockoutDuration, counterInterval);
                 final long timeDifference = System.currentTimeMillis() - lastAttempt;
                 if (timeDifference <= lockoutDuration) {
                     log.info("Lockout threshold reached for '{}', invalid count is {}", key, counter);
@@ -261,7 +282,7 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
     /** {@inheritDoc} */
     public boolean increment(@Nonnull final ProfileRequestContext profileRequestContext) {
         // Work is done by helper method to track storage retries.
-        final String key = lockoutKeyStrategy.apply(profileRequestContext);
+        final String key = getLockoutKeyStrategy().apply(profileRequestContext);
         if (key == null) {
             log.warn("No lockout key returned for request");
             return false;
@@ -273,10 +294,12 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
     /** {@inheritDoc} */
     public boolean clear(@Nonnull final ProfileRequestContext profileRequestContext) {
         try {
-            final String key = lockoutKeyStrategy.apply(profileRequestContext);
+            final String key = getLockoutKeyStrategy().apply(profileRequestContext);
             if (key != null) {
+                final String id = getId();
+                assert id != null;
                 log.debug("Clearing lockout state for '{}'", key);
-                storageService.delete(getId(), key);
+                storageService.delete(id, key);
                 return true;
             }
             log.warn("No lockout key returned for request");
@@ -310,7 +333,9 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
         int counter = 0;
         StorageRecord<?> sr = null;
         try {
-            sr = storageService.read(getId(), key);
+            final String id = getId();
+            assert id != null;
+            sr = storageService.read(id, key);
             if (sr != null) {
                 counter = Integer.parseInt(sr.getValue());
             }
@@ -331,7 +356,8 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
         // Compute last access time by backing off from record expiration.
         long lastAccess = now;
         if (sr != null) {
-            lastAccess = sr.getExpiration() - Math.max(lockoutDuration, counterInterval);
+            final Long exp = Constraint.isNotNull(sr.getExpiration(), "Stored expiration canot be null");
+            lastAccess = exp - Math.max(lockoutDuration, counterInterval);
         }
         
         // If difference between now and last access exceeds the counter interval, zero it.
@@ -346,10 +372,12 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
         log.debug("Invalid login count for '{}' will be {}, expiring at {}", key, counter,
                 Instant.ofEpochMilli(expiration));
 
+        final String id = getId();
+        assert id != null;
         // Create or update as required. Retry on errors.
         if (sr == null) {
             try {
-                if (storageService.create(getId(), key, Integer.toString(counter), expiration)) {
+                if (storageService.create(id, key, Integer.toString(counter), expiration)) {
                     return true;
                 }
             } catch (final IOException e) {
@@ -357,7 +385,7 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
             }
         } else {
             try {
-                if (storageService.update(getId(), key, Integer.toString(counter), expiration)) {
+                if (storageService.update(id, key, Integer.toString(counter), expiration)) {
                     return true;
                 }
             } catch (final IOException e) {
@@ -398,6 +426,7 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
             if (httpRequestSupplier == null) {
                 return null;
             }
+            assert httpRequestSupplier != null;
             return httpRequestSupplier.get();
         }
 
@@ -430,7 +459,9 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
             }
             
             final String username = upContext.getUsername();
-            final String ipAddr = HttpServletSupport.getRemoteAddr(getHttpServletRequest());
+            final HttpServletRequest request = getHttpServletRequest();
+            assert request !=  null;
+            final String ipAddr = HttpServletSupport.getRemoteAddr(request);
             if (username == null || username.isEmpty() || ipAddr == null || ipAddr.isEmpty()) {
                 return null;
             }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/TransitionMultiFactorAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/TransitionMultiFactorAuthentication.java
index d07f817fa..2c62a68b7 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/TransitionMultiFactorAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/TransitionMultiFactorAuthentication.java
@@ -175,15 +175,23 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
         
+        final MultiFactorAuthenticationContext mfaCtxt = mfaContext;
+        assert mfaCtxt != null;
+        
         // Swap MFA flow back into top-level context so that other components see only MFA flow.
-        authenticationContext.setAttemptedFlow(mfaContext.getAuthenticationFlowDescriptor());
+        authenticationContext.setAttemptedFlow(mfaCtxt.getAuthenticationFlowDescriptor());
 
         // If the holding variable is already set, this is a recursive invocation.
         if (previousEvent == null) {
             // Event transitions require normalizing empty/null events into "proceed".
             final EventContext eventCtx = eventContextLookupStrategy.apply(profileRequestContext);
-            previousEvent = eventCtx != null && eventCtx.getEvent() != null
-                    ? eventCtx.getEvent().toString() : EventIds.PROCEED_EVENT_ID;
+            final Object event;
+            if (eventCtx != null) {
+                event = eventCtx.getEvent();
+            } else {
+                event = null;
+            }
+            previousEvent = event != null ? event.toString() : EventIds.PROCEED_EVENT_ID;
         }
 
         // Check for an authentication result and move it into the MFA context.
@@ -192,7 +200,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
             if (EventIds.PROCEED_EVENT_ID.equals(previousEvent)) {                
                 log.debug("{} Preserving authentication result from '{}' flow", getLogPrefix(),
                         result.getAuthenticationFlowId());
-                mfaContext.getActiveResults().put(result.getAuthenticationFlowId(), result);
+                mfaCtxt.getActiveResults().put(result.getAuthenticationFlowId(), result);
             } else {
                 log.debug("{} Discarding incomplete authentication result from '{}' flow", getLogPrefix(),
                         result.getAuthenticationFlowId());
@@ -202,8 +210,8 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
 
         // The "next" flow here is the "previous" flow run by the system that we're branching from.
         // This value can be null (on the first entry) and a rule should be defined for the null value.
-        final String prevFlowId = mfaContext.getNextFlowId();
-        mfaContext.setNextFlowId(null);        
+        final String prevFlowId = mfaCtxt.getNextFlowId();
+        mfaCtxt.setNextFlowId(null);
         if (prevFlowId == null) {
             log.debug("{} Applying MFA transition rule to determine initial state", getLogPrefix());
         } else {
@@ -211,8 +219,9 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         }
 
         String flowId = null;
-        final MultiFactorAuthenticationTransition transition = mfaContext.getTransitionMap().get(prevFlowId);
+        final MultiFactorAuthenticationTransition transition = mfaCtxt.getTransitionMap().get(prevFlowId);
         if (transition != null) {
+            assert previousEvent != null;
             flowId = transition.getNextFlowStrategy(previousEvent).apply(profileRequestContext);
             if (flowId == null) {
                 flowId = transition.getNextFlowStrategy("*").apply(profileRequestContext);
@@ -220,10 +229,12 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         }
         if (flowId != null) {
             log.debug("{} MFA flow transition after '{}' event to '{}' flow", getLogPrefix(), previousEvent, flowId);
-            mfaContext.setNextFlowId(flowId);
+            mfaCtxt.setNextFlowId(flowId);
+            assert transition != null;
             doTransition(profileRequestContext, authenticationContext, transition);
         } else {
-            final String event = mfaContext.getEvent() != null ? mfaContext.getEvent() : previousEvent;
+            final String event = mfaCtxt.getEvent() != null ? mfaCtxt.getEvent() : previousEvent;
+            assert event != null;
             log.debug("{} MFA flow completing with event '{}'", getLogPrefix(), event);
             if (EventIds.PROCEED_EVENT_ID.equals(event)) {
                 ActionSupport.buildProceedEvent(profileRequestContext);
@@ -245,9 +256,12 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
     private void doTransition(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext,
             @Nonnull final MultiFactorAuthenticationTransition transition) {
-        
+
+        MultiFactorAuthenticationContext mfaCtxt = mfaContext;
+        assert mfaCtxt != null;
+
         // Non-authentication flows can just be executed (via a "proceed" event).
-        final String flowId = mfaContext.getNextFlowId();
+        final String flowId = Constraint.isNotNull(mfaCtxt.getNextFlowId(), "No previous flow");
         if (!flowId.startsWith("authn/")) {
             ActionSupport.buildProceedEvent(profileRequestContext);
             return;
@@ -266,7 +280,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         // constraint is assumed to be enforced by limiting which active results are made available.
         // To bypass, we just call ourselves again, implicitly looping back. The protection against
         // infinite recursion is the configuration of transitions supplied by the deployer.
-        final AuthenticationResult activeResult = mfaContext.getActiveResults().get(flowId);
+        final AuthenticationResult activeResult = mfaCtxt.getActiveResults().get(flowId);
         if (activeResult != null) {
             if (activeResult.test(profileRequestContext)) {
                 log.debug("{} Reusing active result for flow {}", getLogPrefix(), flowId);
@@ -277,7 +291,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
                 return;
             }
             log.debug("{} Active result for flow {} not reusable, ignoring", getLogPrefix(), flowId);
-            mfaContext.getActiveResults().remove(flowId);
+            mfaCtxt.getActiveResults().remove(flowId);
         }
      
         if (validateLoginTransitions) {
@@ -313,4 +327,4 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
     }
 // Checkstyle: CyclomaticComplexity ON
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
index 419dc4974..ff3807ed4 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.authn.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -44,6 +43,7 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UsernamePasswordContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
@@ -87,7 +87,7 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
     /** Constructor. */
     public ValidateCredentials() {
         setMetricName(DEFAULT_METRIC_NAME);
-        credentialValidators = Collections.emptyList();
+        credentialValidators = CollectionSupport.emptyList();
         results = new ArrayList<>(1);
     }
     
@@ -109,9 +109,9 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
     public void setValidators(@Nullable @NonnullElements final List<CredentialValidator> validators) {
         checkSetterPreconditions();
         if (validators != null) {
-            credentialValidators = List.copyOf(validators);
+            credentialValidators = CollectionSupport.copyToList(validators);
         } else {
-            credentialValidators = Collections.emptyList();
+            credentialValidators = CollectionSupport.emptyList();
         }
     }
     
@@ -129,7 +129,10 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
     /** {@inheritDoc} */
     @Override
     @Nonnull @NotEmpty public String getMetricName() {
-        return super.getMetricName() + '.' + currentValidator.getId();
+        // only called in execute when we know the field is non-null
+        assert currentValidator != null;
+        final String cvId = currentValidator.getId();
+        return super.getMetricName() + '.' + cvId;
     }
        
     /** {@inheritDoc} */
@@ -269,6 +272,8 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
     @Override
     @Nullable @NonnullElements protected Map<String,String> getAuditFields(
             @Nonnull final ProfileRequestContext profileRequestContext) {
+        // only called in execute when we know the field is non-null
+        assert currentValidator!=null;
         return Map.of(AuthnAuditFields.CREDENTIAL_VALIDATOR, currentValidator.getId());
     }
     
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
index e7626dac8..8d5402822 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.idp.authn.impl;
 
+import java.time.Instant;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
@@ -28,6 +29,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.security.auth.Subject;
 
+import org.opensaml.messaging.context.BaseContext;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -41,6 +43,7 @@ import net.shibboleth.idp.attribute.filter.AttributeFilterException;
 import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext;
 import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext.Direction;
 import net.shibboleth.idp.authn.AbstractValidationAction;
+import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.CertificateContext;
@@ -50,6 +53,7 @@ import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.profile.IdPAuditFields;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.service.ReloadableService;
@@ -165,9 +169,11 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
             @Nonnull final AuthenticationContext authenticationContext) {
 
         @Nonnull ExternalAuthenticationContext localExtContext = Constraint.isNotNull(extContext, "external Authn Context cannot be null");
-        if (localExtContext.getAuthnException() != null) {
+        final Exception authnExp = localExtContext.getAuthnException();
+        final String principalName = localExtContext.getPrincipalName();
+        if (authnExp != null) {
             log.info("{} External authentication produced exception", getLogPrefix(), localExtContext.getAuthnException());
-            handleError(profileRequestContext, authenticationContext, localExtContext.getAuthnException(),
+            handleError(profileRequestContext, authenticationContext, authnExp,
                     AuthnEventIds.AUTHN_EXCEPTION);
             recordFailure(profileRequestContext);
             return;
@@ -186,11 +192,10 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
                     localExtContext.getPrincipal());
             localExtContext.setSubject(new Subject(false, Collections.singleton(localExtContext.getPrincipal()),
                     Collections.emptySet(), Collections.emptySet()));
-        } else if (localExtContext.getPrincipalName() != null) {
-            log.info("{} External authentication succeeded for user: {}", getLogPrefix(),
-                    localExtContext.getPrincipalName());
+        } else if (principalName!= null) {
+            log.info("{} External authentication succeeded for user: {}", getLogPrefix(), principalName);
             localExtContext.setSubject(new Subject(false,
-                    Collections.singleton(new UsernamePrincipal(localExtContext.getPrincipalName())),
+                    Collections.singleton(new UsernamePrincipal(principalName)),
                     Collections.emptySet(), Collections.emptySet()));
         } else {
             log.info("{} External authentication failed, no user identity or error information returned",
@@ -199,8 +204,10 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
                     AuthnEventIds.NO_CREDENTIALS);
             return;
         }
+        final Subject subject = localExtContext.getSubject();
+        assert subject != null;
         
-        if (!checkUsername(localExtContext.getSubject())) {
+        if (!checkUsername(subject)) {
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
                     AuthnEventIds.INVALID_CREDENTIALS);
             recordFailure(profileRequestContext);
@@ -212,7 +219,7 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
         if (!localExtContext.getAuthenticatingAuthorities().isEmpty()) {
             final ProxyAuthenticationPrincipal proxied =
                     new ProxyAuthenticationPrincipal(localExtContext.getAuthenticatingAuthorities());
-            localExtContext.getSubject().getPrincipals().add(proxied);
+            subject.getPrincipals().add(proxied);
         }
         
         if (localExtContext.doNotCache()) {
@@ -220,16 +227,18 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
             authenticationContext.setResultCacheable(false);
         }
         
-        filterAttributes();
+        filterAttributes(localExtContext);
         
         buildAuthenticationResult(profileRequestContext, authenticationContext);
         
-        if (authenticationContext.getAuthenticationResult() != null) {
-            if (localExtContext.getAuthnInstant() != null) {
-                authenticationContext.getAuthenticationResult().setAuthenticationInstant(localExtContext.getAuthnInstant());
+        final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
+        if (ar != null) {
+            final Instant ai = localExtContext.getAuthnInstant();
+            if (ai != null) {
+                ar.setAuthenticationInstant(ai);
             }
             if (localExtContext.isPreviousResult()) {
-                authenticationContext.getAuthenticationResult().setPreviousResult(true);
+                ar.setPreviousResult(true);
             }
         }
     }
@@ -241,16 +250,21 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
         // Override supplied Subject with our own, after transferring over any custom Principals
         // and adding any filtered inbound attributes.
         @Nonnull ExternalAuthenticationContext localExtContext = Constraint.isNotNull(extContext, "external Authn Context cannot be null");
-        localExtContext.getSubject().getPrincipals().addAll(subject.getPrincipals());
-        
-        if (attributeContext != null && !attributeContext.getIdPAttributes().isEmpty()) {
+        final Subject localSubject = Constraint.isNotNull(localExtContext.getSubject(), "external Authn Subject cannot be null");
+        localSubject.getPrincipals().addAll(subject.getPrincipals());
+
+        final AttributeContext ac= attributeContext;
+        if (ac != null && !ac.getIdPAttributes().isEmpty()) {
             log.debug("{} Adding filtered inbound attributes to Subject", getLogPrefix());
-            localExtContext.getSubject().getPrincipals().addAll(
-                attributeContext.getIdPAttributes().values().stream().map(
-                        (IdPAttribute a) -> new IdPAttributePrincipal(a)).collect(Collectors.toList()));
+            localSubject.getPrincipals().addAll(
+                ac.getIdPAttributes().
+                values().
+                stream().
+                map((IdPAttribute a) -> {assert a != null;return new IdPAttributePrincipal(a);}).
+                collect(CollectionSupport.nonnullCollector(Collectors.toList())).get());
         }
         
-        return localExtContext.getSubject();
+        return localSubject;
     }
     
     /**
@@ -265,6 +279,7 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
         if (matchExpression != null) {
             final String name = getUsername(subject);
             if (name != null) {
+                assert matchExpression != null;
                 if (matchExpression.matcher(name).matches()) {
                     return true;
                 }
@@ -300,9 +315,14 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
     /** {@inheritDoc} */
     @Override
     @Nullable protected Map<String,String> getAuditFields(@Nonnull final ProfileRequestContext profileRequestContext) {
-        
-        if (extContext != null && extContext.getSubject() != null) {
-            final String name = getUsername(extContext.getSubject());
+        final Subject subject;
+        if (extContext != null) {
+            subject = extContext.getSubject();
+        } else {
+            subject = null;
+        }
+        if (subject != null) {
+            final String name = getUsername(subject);
             if (name != null) {
                 return Collections.singletonMap(IdPAuditFields.USERNAME, name);
             }
@@ -313,40 +333,44 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
     
     /**
      * Check for inbound attributes and apply filtering.
+     * @param localExtContext nonnull value of {@link #extContext}
      */
-    private void filterAttributes() {
+    private void filterAttributes(@Nonnull final ExternalAuthenticationContext localExtContext) {
         
-        attributeContext = extContext.getSubcontext(AttributeContext.class);
-        if (attributeContext == null) {
+        final AttributeContext ac = attributeContext = localExtContext.getSubcontext(AttributeContext.class);
+        if (ac == null) {
             log.debug("{} No attribute context, no attributes to filter", getLogPrefix());
             return;
         }
 
-        if (attributeContext.getIdPAttributes().isEmpty()) {
+        if (ac.getIdPAttributes().isEmpty()) {
             log.debug("{} No attributes to filter", getLogPrefix());
             return;
         }
 
         if (attributeFilterService == null) {
             log.warn("{} No AttributeFilter service provided, clearing inbound attributes", getLogPrefix());
-            attributeContext.setIdPAttributes(null);
+            ac.setIdPAttributes(null);
             return;
         }
-        final AttributeFilterContext filterContext = extContext.getSubcontext(AttributeFilterContext.class, true);
+        final AttributeFilterContext filterContext = localExtContext.getOrCreateSubcontext(AttributeFilterContext.class);
         
         populateFilterContext(filterContext);
         
+        assert attributeFilterService != null;
         try (final ServiceableComponent<AttributeFilter> component = attributeFilterService.getServiceableComponent()) {
             final AttributeFilter filter = component.getComponent();
             filter.filterAttributes(filterContext);
-            filterContext.getParent().removeSubcontext(filterContext);
-            attributeContext.setIdPAttributes(filterContext.getFilteredIdPAttributes().values());
+            final BaseContext parent = filterContext.getParent();
+            assert parent != null;
+            parent.removeSubcontext(filterContext);
+            ac.setIdPAttributes(filterContext.getFilteredIdPAttributes().values());
         } catch (final AttributeFilterException e) {
             log.error("{} Error while filtering inbound attributes", getLogPrefix(), e);
-            attributeContext.setIdPAttributes(null);
+            ac.setIdPAttributes(null);
         } catch (final ServiceException e) {
             log.error("{} Invalid AttributeFilter configuration", getLogPrefix(), e);
-            attributeContext.setIdPAttributes(null);
+            ac.setIdPAttributes(null);
         }
     }
     
@@ -360,14 +384,17 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
      */
     private void populateFilterContext(@Nonnull final AttributeFilterContext filterContext) {
         
+        final AttributeContext ac = attributeContext;
+        final ExternalAuthenticationContext ec = extContext;
+        assert ac != null && ec != null;
         filterContext.setDirection(Direction.INBOUND)
-            .setPrefilteredIdPAttributes(attributeContext.getIdPAttributes().values())
+            .setPrefilteredIdPAttributes(ac.getIdPAttributes().values())
             .setMetadataResolver(metadataResolver)
             .setRequesterMetadataContextLookupStrategy(null)
             .setProxiedRequesterContextLookupStrategy(null);
         
-        if (!extContext.getAuthenticatingAuthorities().isEmpty()) {
-            filterContext.setAttributeIssuerID(extContext.getAuthenticatingAuthorities().iterator().next());
+        if (!ec.getAuthenticatingAuthorities().isEmpty()) {
+            filterContext.setAttributeIssuerID(ec.getAuthenticatingAuthorities().iterator().next());
         }
     }
 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateFunctionResult.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateFunctionResult.java
index 5d9e81298..bbf9b45c8 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateFunctionResult.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateFunctionResult.java
@@ -139,16 +139,18 @@ public class ValidateFunctionResult extends AbstractAuditingValidationAction {
     @Override
     @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
         
-        if (result instanceof String) {
-            subject.getPrincipals().add(new UsernamePrincipal((String) result));
+        final Object res = result;
+        assert res != null;
+        if (res instanceof String) {
+            subject.getPrincipals().add(new UsernamePrincipal((String) res));
             return subject;
-        } else if (result instanceof Principal) {
-            subject.getPrincipals().add((Principal) result);
+        } else if (res instanceof Principal) {
+            subject.getPrincipals().add((Principal) res);
             return subject;
-        } else if (result instanceof Subject) {
+        } else if (res instanceof Subject) {
             // Override supplied Subject with our own, after transferring over any custom Principals.
-            ((Subject) result).getPrincipals().addAll(subject.getPrincipals());
-            return (Subject) result;
+            ((Subject) res).getPrincipals().addAll(subject.getPrincipals());
+            return (Subject) res;
         }
         
         // Save my walrus!
@@ -190,4 +192,4 @@ public class ValidateFunctionResult extends AbstractAuditingValidationAction {
         return null;
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateRemoteUser.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateRemoteUser.java
index 128db2e6f..d69edb125 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateRemoteUser.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateRemoteUser.java
@@ -18,7 +18,6 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -36,6 +35,7 @@ import net.shibboleth.idp.authn.context.UsernameContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -74,8 +74,8 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
     
     /** Constructor. */
     public ValidateRemoteUser() {
-        allowedUsernames = Collections.emptySet();
-        deniedUsernames = Collections.emptySet();
+        allowedUsernames = CollectionSupport.emptySet();
+        deniedUsernames = CollectionSupport.emptySet();
         setMetricName(DEFAULT_METRIC_NAME);
     }
     
@@ -86,7 +86,7 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
      */
     public void setAllowedUsernames(@Nullable @NonnullElements final Collection<String> allowed) {
         checkSetterPreconditions();
-        allowedUsernames = Set.copyOf(StringSupport.normalizeStringCollection(allowed));
+        allowedUsernames = CollectionSupport.copyToSet(StringSupport.normalizeStringCollection(allowed));
     }
 
     /**
@@ -96,7 +96,7 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
      */
     public void setDeniedUsernames(@Nullable @NonnullElements final Collection<String> denied) {
         checkSetterPreconditions();
-        deniedUsernames = Set.copyOf(StringSupport.normalizeStringCollection(denied));
+        deniedUsernames = CollectionSupport.copyToSet(StringSupport.normalizeStringCollection(denied));
     }
 
     /**
@@ -130,6 +130,7 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
             return false;
         }
 
+        assert usernameContext != null;
         if (usernameContext.getUsername() == null) {
             log.debug("{} No username available within UsernameContext", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
@@ -144,16 +145,20 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
-                
-        if (!isAuthenticated(usernameContext.getUsername())) {
-            log.info("{} User '{}' was not valid", getLogPrefix(), usernameContext.getUsername());
+
+        final UsernameContext uCtxt = usernameContext;
+        assert uCtxt != null;
+        final String userName = uCtxt.getUsername();
+        assert userName != null;
+        if (!isAuthenticated(userName)) {
+            log.info("{} User '{}' was not valid", getLogPrefix(), userName);
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
                     AuthnEventIds.INVALID_CREDENTIALS);
             recordFailure(profileRequestContext);
             return;
         }
 
-        log.info("{} Validated user '{}'", getLogPrefix(), usernameContext.getUsername());
+        log.info("{} Validated user '{}'", getLogPrefix(), userName);
         recordSuccess(profileRequestContext);
         buildAuthenticationResult(profileRequestContext, authenticationContext);
     }
@@ -165,24 +170,30 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
      * @return  true iff the username is acceptable
      */
     private boolean isAuthenticated(@Nonnull @NotEmpty final String username) {
-        
+
+        final Pattern mc = matchExpression;
         if (!allowedUsernames.isEmpty() && !allowedUsernames.contains(username)) {
             // Not in allowed set. Only accept if a regexp applies.
-            if (matchExpression == null) {
+            if (mc == null) {
                 return false;
             }
-            return matchExpression.matcher(username).matches();
+            return mc.matcher(username).matches();
         }
         
         // In allowed set (or none). Check deny set, and if necessary a regexp.
         return !deniedUsernames.contains(username)
-                && (matchExpression == null || matchExpression.matcher(username).matches());
+                && (mc == null || mc.matcher(username).matches());
     }
 
     /** {@inheritDoc} */
     @Override
     @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
-        subject.getPrincipals().add(new UsernamePrincipal(usernameContext.getUsername()));
+        final UsernameContext usernameContext = this.usernameContext;
+        assert usernameContext != null;
+        final String userName = usernameContext.getUsername();
+        assert userName != null;
+
+        subject.getPrincipals().add(new UsernamePrincipal(userName));
         return subject;
     }
     
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateUserAgentAddress.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateUserAgentAddress.java
index c236c8b2b..3d6252e40 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateUserAgentAddress.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateUserAgentAddress.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.authn.impl;
 
 import java.net.InetAddress;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,6 +40,7 @@ import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.profile.IdPAuditFields;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.net.IPRange;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -76,7 +76,7 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
     /** Constructor. */
     public ValidateUserAgentAddress() {
         setMetricName(DEFAULT_METRIC_NAME);
-        mappings = Collections.emptyMap();
+        mappings = CollectionSupport.emptyMap();
     }
     
     /**
@@ -94,7 +94,7 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
                 }
             }
         } else {
-            mappings = Collections.emptyMap();
+            mappings = CollectionSupport.emptyMap();
         }
     }
     
@@ -107,15 +107,15 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
             return false;
         }
 
-        uaContext = authenticationContext.getSubcontext(UserAgentContext.class, false);
-        if (uaContext == null) {
+        final UserAgentContext uaCtx = uaContext = authenticationContext.getSubcontext(UserAgentContext.class, false);
+        if (uaCtx == null) {
             log.debug("{} No UserAgentContext available within authentication context", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                     AuthnEventIds.NO_CREDENTIALS);
             return false;
         }
 
-        if (uaContext.getAddress() == null) {
+        if (uaCtx.getAddress() == null) {
             log.debug("{} No address available within UserAgentContext", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                     AuthnEventIds.NO_CREDENTIALS);
@@ -130,11 +130,17 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
+        final UserAgentContext uaCtx = uaContext;
+        assert uaCtx != null;
+        final InetAddress addr = uaCtx.getAddress();
+        assert addr != null;
         for (final Map.Entry<String,Collection<IPRange>> e : mappings.entrySet()) {
-            if (isAuthenticated(uaContext.getAddress(), e.getValue())) {
+            final Collection<IPRange> ranges = e.getValue();
+            assert ranges != null;
+            if (isAuthenticated(addr, ranges)) {
                 principalName = e.getKey();
                 log.info("{} Authenticated user agent with address {} as {}",
-                        getLogPrefix(), uaContext.getAddress().getHostAddress(), principalName);
+                        getLogPrefix(), addr.getHostAddress(), principalName);
                 recordSuccess(profileRequestContext);
                 buildAuthenticationResult(profileRequestContext, authenticationContext);
                 return;
@@ -142,7 +148,7 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
         }
 
         log.debug("{} User agent with address {} was not authenticated", getLogPrefix(),
-                uaContext.getAddress().getHostAddress());
+                addr.getHostAddress());
         handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
                 AuthnEventIds.INVALID_CREDENTIALS);
         recordFailure(profileRequestContext);
@@ -159,7 +165,7 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
     private boolean isAuthenticated(@Nonnull final InetAddress address,
             @Nonnull @NonnullElements final Collection<IPRange> ranges) {
         final byte[] resolvedAddress = address.getAddress();
-
+        assert resolvedAddress != null;
         for (final IPRange range : ranges) {
             if (range.contains(resolvedAddress)) {
                 return true;
@@ -172,7 +178,9 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
     /** {@inheritDoc} */
     @Override
     @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
-        subject.getPrincipals().add(new UsernamePrincipal(principalName));
+        assert principalName != null;
+        final UsernamePrincipal principal = new UsernamePrincipal(principalName);
+        subject.getPrincipals().add(principal);
         return subject;
     }
 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
index bbde60f1f..56576a3c2 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
@@ -18,13 +18,13 @@
 package net.shibboleth.idp.authn.impl;
 
 import java.security.cert.X509Certificate;
-import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
 
 import org.cryptacular.x509.dn.Attribute;
@@ -42,6 +42,7 @@ import net.shibboleth.idp.authn.SubjectCanonicalizationException;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -72,9 +73,6 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(X500SubjectCanonicalization.class);
     
-    /** Supplies logic for pre-execute test. */
-    @Nonnull private final ActivationCondition embeddedPredicate;
-    
     /** subjectAltName types to search for. */
     @Nonnull @NonnullElements private List<Integer> subjectAltNameTypes;
     
@@ -89,9 +87,8 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
     
     /** Constructor. */
     public X500SubjectCanonicalization() {
-        embeddedPredicate = new ActivationCondition();
-        subjectAltNameTypes = Collections.emptyList();
-        objectIds = Collections.singletonList(CN_OID);
+        subjectAltNameTypes = CollectionSupport.emptyList();
+        objectIds = CollectionSupport.singletonList(CN_OID);
     }
 
     /**
@@ -102,9 +99,9 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
     public void setSubjectAltNameTypes(@Nullable @NonnullElements final List<Integer> types) {
         checkSetterPreconditions();
         if (types != null) {
-            subjectAltNameTypes = List.copyOf(types);
+            subjectAltNameTypes = CollectionSupport.copyToList(types);
         } else {
-            subjectAltNameTypes = Collections.emptyList();
+            subjectAltNameTypes = CollectionSupport.emptyList();
         }
     }
 
@@ -115,7 +112,7 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
      */
     public void setObjectIds(@Nullable @NonnullElements final List<String> ids) {
         checkSetterPreconditions();
-        objectIds = List.copyOf(StringSupport.normalizeStringCollection(ids));
+        objectIds = CollectionSupport.copyToList(StringSupport.normalizeStringCollection(ids));
     }
     
     /** {@inheritDoc} */
@@ -123,13 +120,16 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext, 
             @Nonnull final SubjectCanonicalizationContext c14nContext) {
 
+        final Subject subject = c14nContext.getSubject();
+        assert subject != null;
         final Set<X509Certificate> certificates =
-                c14nContext.getSubject().getPublicCredentials(X509Certificate.class);
+                subject.getPublicCredentials(X509Certificate.class);
         if (certificates != null && certificates.size() == 1) {
             certificate = certificates.iterator().next();
+            assert certificate != null;
             x500Principal = certificate.getSubjectX500Principal();
         } else {
-            final Set<X500Principal> principals = c14nContext.getSubject().getPrincipals(X500Principal.class);
+            final Set<X500Principal> principals = subject.getPrincipals(X500Principal.class);
             if (principals != null && principals.size() == 1) {
                 x500Principal = principals.iterator().next();
             }
@@ -154,6 +154,7 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
         if (certificate != null && !subjectAltNameTypes.isEmpty()) {
             log.debug("{} Searching for subjectAltName types ({})", getLogPrefix(), subjectAltNameTypes);
             final List<?> altnames = X509Support.getAltNames(certificate, subjectAltNameTypes.toArray(new Integer[0]));
+            assert altnames != null;
             for (final Object altname : altnames) {
                 if (altname instanceof String) {
                     log.debug("{} Extracted String-valued subjectAltName: {}", getLogPrefix(), altname);
@@ -163,12 +164,15 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
             }
             log.debug("{} No suitable subjectAltName extension");
         }
-        
-        log.debug("{} Searching for RDN to extract from DN: {}", getLogPrefix(), x500Principal.getName());
+        assert x500Principal != null;
+        final String x509PrincipalName =x500Principal.getName();
+        log.debug("{} Searching for RDN to extract from DN: {}", getLogPrefix(), x509PrincipalName);
         
         try {
             final RDNSequence dnAttrs = NameReader.readX500Principal(x500Principal);
+            assert dnAttrs != null;
             for (final String oid : objectIds) {
+                assert oid != null;
                 final String rdn = findRDN(dnAttrs, oid);
                 if (rdn != null) {
                     log.debug("{} Extracted RDN with OID {}: {}", getLogPrefix(), oid, rdn);
@@ -177,11 +181,11 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
                 }
             }
             
-            log.warn("{} Unable to extract a suitable RDN from DN: {}", getLogPrefix(), x500Principal.getName());
+            log.warn("{} Unable to extract a suitable RDN from DN: {}", getLogPrefix(), x509PrincipalName);
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
             
         } catch (final IllegalArgumentException e) {
-            log.warn("{} Unable to parse subject DN: {}", getLogPrefix(),  x500Principal.getName(), e);
+            log.warn("{} Unable to parse subject DN: {}", getLogPrefix(),  x509PrincipalName, e);
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
             return;
         }
@@ -240,14 +244,15 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
         public boolean apply(@Nonnull final ProfileRequestContext profileRequestContext,
                 @Nonnull final SubjectCanonicalizationContext c14nContext, final boolean duringAction) {
 
-            if (c14nContext.getSubject() != null) {
+            final Subject subject = c14nContext.getSubject();
+            if (subject != null) {
                 final Set<X509Certificate> certificates =
-                        c14nContext.getSubject().getPublicCredentials(X509Certificate.class);
+                        subject.getPublicCredentials(X509Certificate.class);
                 if (certificates != null && certificates.size() == 1) {
                     return true;
                 }
                 
-                final Set<X500Principal> principals = c14nContext.getSubject().getPrincipals(X500Principal.class);
+                final Set<X500Principal> principals = subject.getPrincipals(X500Principal.class);
                 if (principals != null && principals.size() == 1) {
                     return true;
                 }
@@ -264,4 +269,4 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalization
         
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509AuthServlet.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509AuthServlet.java
index c5ccbd7c3..cd05b49e7 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509AuthServlet.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509AuthServlet.java
@@ -44,6 +44,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
 
 import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletContext;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.Cookie;
 import jakarta.servlet.http.HttpServlet;
@@ -110,8 +111,10 @@ public class X509AuthServlet extends HttpServlet {
     public void init(final ServletConfig config) throws ServletException {
         super.init(config);
 
+        final ServletContext servletContext = getServletContext();
+        assert servletContext != null;
         final WebApplicationContext springContext =
-                WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+                WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
         
         String param = config.getInitParameter(TRUST_ENGINE_PARAM);
         if (param != null) {
@@ -136,6 +139,7 @@ public class X509AuthServlet extends HttpServlet {
     protected void service(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse)
             throws ServletException, IOException {
         
+        assert httpRequest != null && httpResponse != null;
         try {
             final String key = ExternalAuthentication.startExternalAuthentication(httpRequest);
             
@@ -162,7 +166,7 @@ public class X509AuthServlet extends HttpServlet {
             final ProfileRequestContext prc = ExternalAuthentication.getProfileRequestContext(key, httpRequest);
             final AuthenticationContext authnCtx = prc.getSubcontext(AuthenticationContext.class);
             if (authnCtx != null) {
-                final CertificateContext cc = authnCtx.getSubcontext(CertificateContext.class, true);
+                final CertificateContext cc = authnCtx.getOrCreateSubcontext(CertificateContext.class);
                 cc.setCertificate(cert);
                 if (certs.length > 1) {
                     for (int i = 1; i < certs.length; i++) {
@@ -175,6 +179,7 @@ public class X509AuthServlet extends HttpServlet {
                 try {
                     final BasicX509Credential cred = new BasicX509Credential(cert);
                     cred.setEntityCertificateChain(Arrays.asList(certs));
+                    assert trustEngine != null;
                     if (trustEngine.validate(cred, new CriteriaSet())) {
                         log.debug("Trust engine validated X.509 certificate");
                     } else {
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509CertificateCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509CertificateCredentialValidator.java
index 7d5fa5499..ffeaee668 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509CertificateCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X509CertificateCredentialValidator.java
@@ -115,7 +115,9 @@ public class X509CertificateCredentialValidator extends AbstractCredentialValida
         if (certContext == null) {
             log.debug("{} No CertificateContext available within authentication context", getLogPrefix());
             return null;
-        } else if (certContext.getCertificate() == null || !(certContext.getCertificate() instanceof X509Certificate)) {
+        }
+        final Certificate cert = certContext.getCertificate();
+        if (cert == null || !(cert instanceof X509Certificate)) {
             log.debug("{} No X.509 certificate available within CertificateContext", getLogPrefix());
             return null;
         }
@@ -123,8 +125,7 @@ public class X509CertificateCredentialValidator extends AbstractCredentialValida
         if (trustEngine != null) {
             log.debug("{} Attempting to validate certificate using trust engine", getLogPrefix());
             try {
-                final BasicX509Credential cred =
-                        new BasicX509Credential((X509Certificate) certContext.getCertificate());
+                final BasicX509Credential cred = new BasicX509Credential((X509Certificate) cert);
                 if (!certContext.getIntermediates().isEmpty()) {
                     cred.getEntityCertificateChain().add((X509Certificate) certContext.getCertificate());
                     for (final Certificate extra : certContext.getIntermediates()) {
@@ -133,6 +134,7 @@ public class X509CertificateCredentialValidator extends AbstractCredentialValida
                         }
                     }
                 }
+                assert trustEngine != null;
                 if (trustEngine.validate(cred, new CriteriaSet())) {
                     log.debug("{} Trust engine validated X.509 certificate", getLogPrefix());
                 } else {
@@ -157,9 +159,9 @@ public class X509CertificateCredentialValidator extends AbstractCredentialValida
         }
 
         log.info("{} Login by '{}' succeeded", getLogPrefix(),
-                ((X509Certificate) certContext.getCertificate()).getSubjectX500Principal().getName());
+                ((X509Certificate) cert).getSubjectX500Principal().getName());
         
-        return populateSubject((X509Certificate) certContext.getCertificate());
+        return populateSubject((X509Certificate) cert);
     }
 // Checkstyle: CyclomaticComplexity ON
     
@@ -182,4 +184,4 @@ public class X509CertificateCredentialValidator extends AbstractCredentialValida
         return super.populateSubject(subject);
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/AuthenticationResultPrincipalSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/AuthenticationResultPrincipalSerializer.java
index 87a86519c..3d720bcf1 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/AuthenticationResultPrincipalSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/AuthenticationResultPrincipalSerializer.java
@@ -26,12 +26,8 @@ import java.util.regex.Pattern;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
-import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonBuilderFactory;
 import javax.json.JsonException;
 import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 import javax.json.JsonReader;
 import javax.json.JsonString;
 import javax.json.JsonStructure;
@@ -66,9 +62,6 @@ public class AuthenticationResultPrincipalSerializer extends AbstractPrincipalSe
     /** Circular reference back to the parent serializer. */
     @Nonnull private final StorageSerializer<AuthenticationResult> resultSerializer;
     
-    /** JSON object bulder factory. */
-    @Nonnull private final JsonBuilderFactory objectBuilderFactory;
-
     /**
      * Constructor.
      * 
@@ -77,7 +70,6 @@ public class AuthenticationResultPrincipalSerializer extends AbstractPrincipalSe
     public AuthenticationResultPrincipalSerializer(
             @Nonnull final StorageSerializer<AuthenticationResult> serializer) {
         resultSerializer = Constraint.isNotNull(serializer, "AuthenticationResult serializer cannot be null");
-        objectBuilderFactory = Json.createBuilderFactory(null);
     }
     
     /** {@inheritDoc} */
@@ -97,7 +89,9 @@ public class AuthenticationResultPrincipalSerializer extends AbstractPrincipalSe
             
             gen.writeEnd();
         }
-        return sink.toString();
+        final String result = sink.toString();
+        assert result != null;
+        return result;
     }
         
     /** {@inheritDoc} */
@@ -117,8 +111,10 @@ public class AuthenticationResultPrincipalSerializer extends AbstractPrincipalSe
             final JsonObject obj = (JsonObject) st;
             final JsonValue str = obj.get(PRINCIPAL_NAME_FIELD);
             if (str != null && str instanceof JsonString) {
+                final String nativeString = ((JsonString) str).getString();
+                assert nativeString != null;
                 return new AuthenticationResultPrincipal(
-                        resultSerializer.deserialize(1, "context", "key", ((JsonString) str).getString(), null));
+                        resultSerializer.deserialize(1, "context", "key", nativeString, null));
             }
             log.warn("Skipping non-string principal value");
             
@@ -126,24 +122,5 @@ public class AuthenticationResultPrincipalSerializer extends AbstractPrincipalSe
         } catch (final JsonException e) {
             throw new IOException("Found invalid data structure while parsing AuthenticationResultPrincipal", e);
         }
-    }
-
-    /**
-     * Get a {@link JsonObjectBuilder} in a thread-safe manner.
-     * 
-     * @return  an object builder
-     */
-    @Nonnull private synchronized JsonObjectBuilder getJsonObjectBuilder() {
-        return objectBuilderFactory.createObjectBuilder();
-    }
-
-    /**
-     * Get a {@link JsonArrayBuilder} in a thread-safe manner.
-     * 
-     * @return  an array builder
-     */
-    @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
-        return objectBuilderFactory.createArrayBuilder();
-    }
-    
-}
\ No newline at end of file
+    }    
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/IdPAttributePrincipalSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/IdPAttributePrincipalSerializer.java
index 8224a429d..eea80e2f0 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/IdPAttributePrincipalSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/IdPAttributePrincipalSerializer.java
@@ -89,7 +89,9 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
 
     /** Constructor. */
     public IdPAttributePrincipalSerializer() {
-        objectBuilderFactory = Json.createBuilderFactory(null);
+        final JsonBuilderFactory factory = Json.createBuilderFactory(null);
+        assert factory != null;
+        objectBuilderFactory = factory;
     }
     
     /** {@inheritDoc} */
@@ -107,6 +109,7 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
             final IdPAttribute attribute = ((IdPAttributePrincipal) principal).getAttribute();
             final JsonArrayBuilder arrayBuilder = getJsonArrayBuilder();
             for (final IdPAttributeValue value : attribute.getValues()) {
+                assert value != null;
                 final JsonObject obj = serializeValue(value);
                 if (obj != null) {
                     arrayBuilder.add(obj);
@@ -117,7 +120,9 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
             gen.write(PRINCIPAL_ENTRY_FIELD, arrayBuilder.build());
             gen.writeEnd();
         }
-        return sink.toString();
+        final String result = sink.toString();
+        assert result != null;
+        return result;
     }
         
     /** {@inheritDoc} */
@@ -138,8 +143,14 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
             final JsonObject obj = (JsonObject) st;
             final JsonString str = obj.getJsonString(PRINCIPAL_NAME_FIELD);
             final JsonArray vals = obj.getJsonArray(PRINCIPAL_ENTRY_FIELD);
-            if (str != null && !Strings.isNullOrEmpty(str.getString()) && vals != null) {
-                final IdPAttribute attribute = new IdPAttribute(str.getString());
+            final String nativeString;
+            if (str != null) {
+                nativeString = str.getString();
+            } else {
+                nativeString = null;
+            }
+            if (nativeString != null && !Strings.isNullOrEmpty(nativeString ) && vals != null) {
+                final IdPAttribute attribute = new IdPAttribute(nativeString);
                 final List<IdPAttributeValue> values = new ArrayList<>();
                 
                 for (final JsonValue entry : vals) {
@@ -175,7 +186,7 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
      * 
      * @return the object
      */
-    @Nonnull protected JsonObject serializeValue(@Nonnull final IdPAttributeValue value) {
+    @Nullable protected JsonObject serializeValue(@Nonnull final IdPAttributeValue value) {
         final JsonObjectBuilder builder = getJsonObjectBuilder();
         
         if (value instanceof EmptyAttributeValue) {
@@ -243,7 +254,9 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
      * @return  an object builder
      */
     @Nonnull private synchronized JsonObjectBuilder getJsonObjectBuilder() {
-        return objectBuilderFactory.createObjectBuilder();
+        final JsonObjectBuilder result = objectBuilderFactory.createObjectBuilder();
+        assert result != null;
+        return result;
     }
 
     /**
@@ -252,7 +265,9 @@ public class IdPAttributePrincipalSerializer extends AbstractPrincipalSerializer
      * @return  an array builder
      */
     @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
-        return objectBuilderFactory.createArrayBuilder();
+        final JsonArrayBuilder result = objectBuilderFactory.createArrayBuilder();
+        assert result != null;
+        return result;
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/InexactPrincipalEvalPredicateFactory.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/InexactPrincipalEvalPredicateFactory.java
index 1f401cb14..fd8be4a6d 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/InexactPrincipalEvalPredicateFactory.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/InexactPrincipalEvalPredicateFactory.java
@@ -57,7 +57,9 @@ public class InexactPrincipalEvalPredicateFactory implements PrincipalEvalPredic
 
     /** Constructor. */
     InexactPrincipalEvalPredicateFactory() {
-        matchingRules = HashMultimap.create();
+        final HashMultimap<String,String> hm = HashMultimap.create();
+        assert hm != null;
+        matchingRules = hm;
     }
     
     /**
@@ -111,7 +113,8 @@ public class InexactPrincipalEvalPredicateFactory implements PrincipalEvalPredic
         }
 
         /** {@inheritDoc} */
-        public boolean test(@Nullable final PrincipalSupportingComponent input) {
+        public boolean test(final PrincipalSupportingComponent input) {
+            assert input != null;
             final Set<String> matches = matchingRules.get(principal.getName());
             final Set<? extends Principal> inputs = input.getSupportedPrincipals(principal.getClass());
             
@@ -131,4 +134,4 @@ public class InexactPrincipalEvalPredicateFactory implements PrincipalEvalPredic
         }
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/LDAPPrincipalSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/LDAPPrincipalSerializer.java
index 638f6ecd9..cacc3af07 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/LDAPPrincipalSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/LDAPPrincipalSerializer.java
@@ -74,7 +74,9 @@ public class LDAPPrincipalSerializer extends AbstractPrincipalSerializer<String>
 
     /** Constructor. */
     public LDAPPrincipalSerializer() {
-        objectBuilderFactory = Json.createBuilderFactory(null);
+        final JsonBuilderFactory factory = Json.createBuilderFactory(null);
+        assert factory != null;
+        objectBuilderFactory = factory;
     }
     
     /** {@inheritDoc} */
@@ -103,7 +105,9 @@ public class LDAPPrincipalSerializer extends AbstractPrincipalSerializer<String>
             }
             gen.writeEnd();
         }
-        return sink.toString();
+        final String result = sink.toString();
+        assert result != null;
+        return result;
     }
     
     /** {@inheritDoc} */
@@ -157,7 +161,9 @@ public class LDAPPrincipalSerializer extends AbstractPrincipalSerializer<String>
      * @return  an object builder
      */
     @Nonnull private synchronized JsonObjectBuilder getJsonObjectBuilder() {
-        return objectBuilderFactory.createObjectBuilder();
+        final JsonObjectBuilder result = objectBuilderFactory.createObjectBuilder();
+        assert result != null;
+        return result;
     }
 
     /**
@@ -166,7 +172,9 @@ public class LDAPPrincipalSerializer extends AbstractPrincipalSerializer<String>
      * @return  an array builder
      */
     @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
-        return objectBuilderFactory.createArrayBuilder();
+        final JsonArrayBuilder result = objectBuilderFactory.createArrayBuilder();
+        assert result != null;
+        return result;
     }
-    
-}
\ No newline at end of file
+
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/ProxyAuthenticationPrincipalSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/ProxyAuthenticationPrincipalSerializer.java
index aeab1e3a9..5e4431d20 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/ProxyAuthenticationPrincipalSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/ProxyAuthenticationPrincipalSerializer.java
@@ -33,7 +33,6 @@ import javax.json.JsonBuilderFactory;
 import javax.json.JsonException;
 import javax.json.JsonNumber;
 import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 import javax.json.JsonReader;
 import javax.json.JsonString;
 import javax.json.JsonStructure;
@@ -41,12 +40,9 @@ import javax.json.JsonValue;
 import javax.json.JsonValue.ValueType;
 import javax.json.stream.JsonGenerator;
 
-import org.slf4j.Logger;
-
 import net.shibboleth.idp.authn.principal.AbstractPrincipalSerializer;
 import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * Principal serializer for {@link ProxyAuthenticationPrincipal}.
@@ -66,15 +62,14 @@ public class ProxyAuthenticationPrincipalSerializer extends AbstractPrincipalSer
     /** Pattern used to determine if input is supported. */
     private static final Pattern JSON_PATTERN = Pattern.compile("^\\{\"AA\":.*\\}$");
 
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(ProxyAuthenticationPrincipalSerializer.class);
-    
     /** JSON object bulder factory. */
     @Nonnull private final JsonBuilderFactory objectBuilderFactory;
 
     /** Constructor. */
     public ProxyAuthenticationPrincipalSerializer() {
-        objectBuilderFactory = Json.createBuilderFactory(null);
+        final JsonBuilderFactory factory = Json.createBuilderFactory(null);
+        assert factory != null;
+        objectBuilderFactory = factory;
     }
     
     /** {@inheritDoc} */
@@ -96,8 +91,9 @@ public class ProxyAuthenticationPrincipalSerializer extends AbstractPrincipalSer
         try (final JsonGenerator gen = getJsonGenerator(sink)) {
             gen.writeStartObject().write(PROXY_AUTH_FIELD, arrayBuilder.build());
             
-            if (proxyPrincipal.getProxyCount() != null) {
-                gen.write(PROXY_COUNT_FIELD, proxyPrincipal.getProxyCount());
+            final Integer proxyCount = proxyPrincipal.getProxyCount();
+            if (proxyCount != null) {
+                gen.write(PROXY_COUNT_FIELD, proxyCount );
             }
             
             if (!proxyPrincipal.getAudiences().isEmpty()) {
@@ -108,7 +104,9 @@ public class ProxyAuthenticationPrincipalSerializer extends AbstractPrincipalSer
             
             gen.writeEnd();
         }
-        return sink.toString();
+        final String result = sink.toString();
+        assert result != null;
+        return result;
     }
     
     /** {@inheritDoc} */
@@ -169,22 +167,16 @@ public class ProxyAuthenticationPrincipalSerializer extends AbstractPrincipalSer
     }
 // Checkstyle: CyclomaticComplexity ON
 
-    /**
-     * Get a {@link JsonObjectBuilder} in a thread-safe manner.
-     * 
-     * @return  an object builder
-     */
-    @Nonnull private synchronized JsonObjectBuilder getJsonObjectBuilder() {
-        return objectBuilderFactory.createObjectBuilder();
-    }
 
-    /**
-     * Get a {@link JsonArrayBuilder} in a thread-safe manner.
-     * 
-     * @return  an array builder
-     */
-    @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
-        return objectBuilderFactory.createArrayBuilder();
-    }
-    
-}
\ No newline at end of file
+     /**
+      * Get a {@link JsonArrayBuilder} in a thread-safe manner.
+      *
+      * @return  an array builder
+      */
+     @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
+        final JsonArrayBuilder result = objectBuilderFactory.createArrayBuilder();
+        assert result != null;
+        return result;
+     }   
+}
+
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/X500PrincipalSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/X500PrincipalSerializer.java
index 85f590ae6..7fbefc5ab 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/X500PrincipalSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/X500PrincipalSerializer.java
@@ -26,12 +26,8 @@ import java.util.regex.Pattern;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
-import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonBuilderFactory;
 import javax.json.JsonException;
 import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 import javax.json.JsonReader;
 import javax.json.JsonString;
 import javax.json.JsonStructure;
@@ -40,14 +36,11 @@ import javax.json.JsonValue.ValueType;
 import javax.json.stream.JsonGenerator;
 import javax.security.auth.x500.X500Principal;
 
-import org.slf4j.Logger;
-
 import net.shibboleth.idp.authn.principal.AbstractPrincipalSerializer;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.DecodingException;
 import net.shibboleth.shared.codec.EncodingException;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * Principal serializer for {@link X500Principal}.
@@ -62,17 +55,6 @@ public class X500PrincipalSerializer extends AbstractPrincipalSerializer<String>
 
     /** Pattern used to determine if input is supported. */
     private static final Pattern JSON_PATTERN = Pattern.compile("^\\{\"X500\":.*\\}$");
-
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(X500PrincipalSerializer.class);
-    
-    /** JSON object bulder factory. */
-    @Nonnull private final JsonBuilderFactory objectBuilderFactory;
-
-    /** Constructor. */
-    public X500PrincipalSerializer() {
-        objectBuilderFactory = Json.createBuilderFactory(null);
-    }
     
     /** {@inheritDoc} */
     @Override
@@ -87,7 +69,9 @@ public class X500PrincipalSerializer extends AbstractPrincipalSerializer<String>
 
         final String name;
         try {
-            name = Base64Support.encode(x500Principal.getEncoded(), false);
+            final byte encoded[] = x500Principal.getEncoded();
+            assert encoded != null;
+            name = Base64Support.encode(encoded, false);
         } catch (final EncodingException e) {
             throw new IOException(e);
         }
@@ -97,7 +81,9 @@ public class X500PrincipalSerializer extends AbstractPrincipalSerializer<String>
         try (final JsonGenerator gen = getJsonGenerator(sink)) {
             gen.writeStartObject().write(X500_NAME_FIELD, name).writeEnd();
         }
-        return sink.toString();
+        final String result = sink.toString();
+        assert result != null;
+        return result;
     }
     
     /** {@inheritDoc} */
@@ -117,31 +103,15 @@ public class X500PrincipalSerializer extends AbstractPrincipalSerializer<String>
             
             final JsonValue jsonValue = ((JsonObject) st).get(X500_NAME_FIELD);
             if (jsonValue != null && ValueType.STRING.equals(jsonValue.getValueType())) {
-                return new X500Principal(Base64Support.decode(((JsonString) jsonValue).getString()));
+                final String nativeString = ((JsonString) jsonValue).getString();
+                assert nativeString != null;
+                return new X500Principal(Base64Support.decode(nativeString));
             }
             
             throw new IOException("Serialized X500Principal missing name field");
         } catch (final JsonException | DecodingException | IllegalArgumentException e) {
             throw new IOException("Found invalid data while parsing X500Principal", e);
         }
-    }
-
-    /**
-     * Get a {@link JsonObjectBuilder} in a thread-safe manner.
-     * 
-     * @return  an object builder
-     */
-    @Nonnull private synchronized JsonObjectBuilder getJsonObjectBuilder() {
-        return objectBuilderFactory.createObjectBuilder();
-    }
-
-    /**
-     * Get a {@link JsonArrayBuilder} in a thread-safe manner.
-     * 
-     * @return  an array builder
-     */
-    @Nonnull private synchronized JsonArrayBuilder getJsonArrayBuilder() {
-        return objectBuilderFactory.createArrayBuilder();
-    }
-    
-}
\ No newline at end of file
+    }    
+}
+ 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
index eeff778fe..b3d5db946 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
@@ -1,4 +1,4 @@
-/*
+ /*
  * Licensed to the University Corporation for Advanced Internet Development,
  * Inc. (UCAID) under one or more contributor license agreements.  See the
  * NOTICE file distributed with this work for additional information regarding
@@ -25,12 +25,12 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
 import org.springframework.webflow.execution.RequestContext;
 
 import com.google.common.escape.Escaper;
 import com.google.common.net.UrlEscapers;
 
+import jakarta.servlet.http.HttpServletRequest;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
@@ -39,9 +39,6 @@ import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.component.AbstractInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-import jakarta.servlet.http.HttpServletRequest;
 
 /**
  * A {@link Function} that produces a discovery request URL using the protocol defined in
@@ -55,9 +52,6 @@ import jakarta.servlet.http.HttpServletRequest;
 public class DiscoveryProfileRequestFunction extends AbstractInitializableComponent
         implements Function<Pair<RequestContext,ProfileRequestContext>,String> {
 
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(DiscoveryProfileRequestFunction.class);
-
     /** URL query parameter escaper. */
     @Nonnull private Escaper escaper;
     
@@ -69,7 +63,9 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
     
     /** Constructor. */
     public DiscoveryProfileRequestFunction() {
-        escaper = UrlEscapers.urlFormParameterEscaper();
+        final Escaper esc = UrlEscapers.urlFormParameterEscaper();
+        assert esc != null;
+        escaper = esc;
         relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
     }
     
@@ -105,8 +101,9 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
     }
     
     /** {@inheritDoc} */
-    @Nullable public String apply(@Nonnull final Pair<RequestContext,ProfileRequestContext> input) {
+    @Nullable public String apply(final @Nullable Pair<RequestContext,ProfileRequestContext> input) {
         
+        assert input != null;
         final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(input.getSecond());
         Constraint.isNotNull(rpCtx, "RelyingPartyContext cannot be null");
         Constraint.isNotNull(rpCtx.getConfiguration(), "RelyingPartyConfiguration cannot be null");
@@ -115,6 +112,7 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
         Constraint.isNotEmpty(baseURL, "Discovery URL cannot be null or empty");
 
         final RelyingPartyConfiguration rpConfig = rpCtx.getConfiguration();
+        assert rpConfig!=null;
         Constraint.isTrue(rpConfig instanceof net.shibboleth.idp.profile.relyingparty.RelyingPartyConfiguration,
                 "RelyingPartyConfiguration was not of expected subclass");
         final String entityID = ((net.shibboleth.idp.profile.relyingparty.RelyingPartyConfiguration) rpConfig).getResponderId(
@@ -124,14 +122,17 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
         
         builder.append(baseURL.contains("?") ? '&' : '?').append("entityID=").append(escaper.escape(entityID));
         
+        final RequestContext requestCtx = input.getFirst();
+        final ProfileRequestContext prc = input.getSecond();
+        assert requestCtx != null && prc != null;
         final AuthenticationContext authenticationContext =
-                input.getSecond().getSubcontext(AuthenticationContext.class);
+                prc.getSubcontext(AuthenticationContext.class);
         if (authenticationContext != null && authenticationContext.isPassive()) {
             builder.append("&isPassive=true");
         }
         
         final HttpServletRequest httpServletRequest =
-                (HttpServletRequest) input.getFirst().getExternalContext().getNativeRequest();
+                (HttpServletRequest) requestCtx.getExternalContext().getNativeRequest();
         
         final StringBuilder selfBuilder = new StringBuilder(httpServletRequest.getScheme());
         selfBuilder.append("://").append(httpServletRequest.getServerName());
@@ -141,11 +142,11 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
             selfBuilder.append(':').append(port);
         }
         
-        selfBuilder.append(input.getFirst().getFlowExecutionUrl()).append("&_eventId_proceed=1");
+        selfBuilder.append(requestCtx.getFlowExecutionUrl()).append("&_eventId_proceed=1");
         
         builder.append("&return=").append(escaper.escape(selfBuilder.toString()));
         
         return builder.toString();
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/AttributeRevocationCondition.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/AttributeRevocationCondition.java
index d8f94ae9a..66a23bf8e 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/AttributeRevocationCondition.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/AttributeRevocationCondition.java
@@ -21,13 +21,13 @@ import java.time.DateTimeException;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.function.BiPredicate;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.messaging.context.BaseContext;
 import org.opensaml.messaging.context.ScratchContext;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
@@ -44,6 +44,7 @@ import net.shibboleth.profile.context.navigate.RelyingPartyIdLookupFunction;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.AbstractInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
@@ -171,10 +172,11 @@ public class AttributeRevocationCondition extends AbstractInitializableComponent
         log.debug("Checking revocation for principal name {} for {} result via attribute resolver", principal,
                 input2.getAuthenticationFlowId());
         
-        final ScratchContext context = input.getSubcontext(ScratchContext.class, true);
+        final ScratchContext context = input.getOrCreateSubcontext(ScratchContext.class);
         
         if (!context.getMap().containsKey(getClass())) {
             final AttributeResolutionContext resolutionContext = buildResolutionContext(input, principal);
+            assert attributeResolver != null;
             resolutionContext.resolveAttributes(attributeResolver);
             
             final Collection<Instant> records = new ArrayList<>();
@@ -201,7 +203,9 @@ public class AttributeRevocationCondition extends AbstractInitializableComponent
             }
             
             context.getMap().put(getClass(), records);
-            resolutionContext.getParent().removeSubcontext(resolutionContext);
+            final BaseContext parent = resolutionContext.getParent();
+            assert parent != null;
+            parent.removeSubcontext(resolutionContext);
         }
         
         return isRevoked(principal, input2, (Collection<Instant>) context.getMap().get(getClass()));
@@ -222,8 +226,9 @@ public class AttributeRevocationCondition extends AbstractInitializableComponent
         
         resolutionContext
             .setPrincipal(principal)
-            .setResolutionLabel("authn/revocation")
-            .setRequestedIdPAttributeNames(Collections.singletonList(attributeId));
+            .setResolutionLabel("authn/revocation");
+        assert attributeId != null;
+        resolutionContext.setRequestedIdPAttributeNames(CollectionSupport.singletonList(attributeId));
         
         if (recipientLookupStrategy != null) {
             resolutionContext.setAttributeRecipientID(recipientLookupStrategy.apply(profileRequestContext));
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/DoRevocationCacheOperation.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/DoRevocationCacheOperation.java
index ab428a1bd..cbfaa8680 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/DoRevocationCacheOperation.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/DoRevocationCacheOperation.java
@@ -46,7 +46,7 @@ import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.xml.DOMTypeSupport;
-
+import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
 /**
@@ -122,7 +122,7 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
 // Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override
-    protected boolean doPreExecute(final ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
         
         if (!super.doPreExecute(profileRequestContext)) {
             return false;
@@ -162,6 +162,7 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
                 return false;
             }
 
+            assert cacheId != null;
             revocationCache = getBean(requestContext, cacheId, RevocationCache.class);
             if (revocationCache == null) {
                 sendError(HttpServletResponse.SC_NOT_FOUND,
@@ -181,11 +182,13 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
     
     /** {@inheritDoc} */
     @Override
-    protected void doExecute(final ProfileRequestContext profileRequestContext) {
-        
+    protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
+
         try {
-            final String method = getHttpServletRequest().getMethod();
+            final HttpServletRequest request = getHttpServletRequest();
             final HttpServletResponse response = getHttpServletResponse();
+            assert request != null && response != null;
+            final String method = request.getMethod();
             
             response.setContentType("application/json");
             response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
@@ -215,12 +218,16 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
      */
     private void doGet() throws IOException {
         try {
+            assert revocationCache!=null && context!=null && key!=null;
             final String revocation = revocationCache.getRevocationRecord(context, key);
+            final HttpServletRequest request = getHttpServletRequest();
+            final HttpServletResponse response = getHttpServletResponse();
+            assert request != null && response != null;
             if (revocation != null) {
-                getHttpServletResponse().setStatus(HttpServletResponse.SC_OK);
+                response.setStatus(HttpServletResponse.SC_OK);
                 final JsonFactory jsonFactory = new JsonFactory();
                 try (final JsonGenerator g = jsonFactory.createGenerator(
-                        getHttpServletResponse().getOutputStream()).useDefaultPrettyPrinter()) {
+                        response.getOutputStream()).useDefaultPrettyPrinter()) {
                     g.setCodec(objectMapper);
                     g.writeStartObject();
                     g.writeObjectFieldStart("data");
@@ -230,7 +237,7 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
                     g.writeStringField("revocation", revocation);
                 }
             } else {
-                getHttpServletResponse().setStatus(HttpServletResponse.SC_NOT_FOUND);
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
             }
         } catch (final IOException e) {
             sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error",
@@ -245,8 +252,11 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
      */
     private void doPost() throws IOException {
         
-        final String value = getHttpServletRequest().getParameter("value");
-        final String duration = getHttpServletRequest().getParameter("duration");
+        final HttpServletRequest request = getHttpServletRequest();
+        final HttpServletResponse response = getHttpServletResponse();
+        assert request != null && response != null;
+        final String value = request.getParameter("value");
+        final String duration = request.getParameter("duration");
         
         if (value == null) {
             sendError(HttpServletResponse.SC_BAD_REQUEST, "Bad Request", "Request missing value parameter.");
@@ -271,13 +281,15 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
         
         final boolean result;
         if (durationSeconds != null) {
+            assert revocationCache!=null && context!=null && key!=null;
             result = revocationCache.revoke(context, key, value, durationSeconds);
         } else {
+            assert revocationCache!=null && context!=null && key!=null;
             result = revocationCache.revoke(context, key, value);
         }
         
         if (result) {
-            getHttpServletResponse().setStatus(HttpServletResponse.SC_ACCEPTED);
+            response.setStatus(HttpServletResponse.SC_ACCEPTED);
         } else {
             sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error",
                     "Attempt to insert revocation record failed.");
@@ -290,10 +302,13 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
      * @throws IOException if an I/O error occurs
      */
     private void doDelete() throws IOException {
+        final HttpServletResponse response = getHttpServletResponse();
+        assert response != null;
+        assert revocationCache!=null && context!=null && key!=null;
         if (revocationCache.unrevoke(context, key)) {
-            getHttpServletResponse().setStatus(HttpServletResponse.SC_NO_CONTENT);
+            response.setStatus(HttpServletResponse.SC_NO_CONTENT);
         } else {
-            getHttpServletResponse().setStatus(HttpServletResponse.SC_NOT_FOUND);
+            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
         }
     }
 
@@ -310,6 +325,7 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
             @Nonnull @NotEmpty final String detail) throws IOException {
         
         final HttpServletResponse response = getHttpServletResponse();
+        assert response != null;
         response.setContentType("application/json");
         response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
         response.setStatus(status);
@@ -324,4 +340,4 @@ public class DoRevocationCacheOperation extends AbstractProfileAction {
         objectMapper.writer().withDefaultPrettyPrinter().writeValue(response.getOutputStream(), errors);
     }
     
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/RevocationCacheCondition.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/RevocationCacheCondition.java
index f85b57f0e..ec662ce6e 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/RevocationCacheCondition.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/revocation/impl/RevocationCacheCondition.java
@@ -134,13 +134,17 @@ public class RevocationCacheCondition extends AbstractInitializableComponent
         log.debug("Checking revocation for principal name {} for {} result", principal,
                 input2.getAuthenticationFlowId());
         
-        final ScratchContext context = input.getSubcontext(ScratchContext.class, true);
+        final ScratchContext context = input.getOrCreateSubcontext(ScratchContext.class);
         if (!context.getMap().containsKey(getClass())) {
             try {
                 final String principalRecord = revocationCache.getRevocationRecord(REVOCATION_CONTEXT,
                         PRINCIPAL_REVOCATION_PREFIX + principal);
-                final HttpServletRequest request = httpServletRequestSupplier == null? null :
-                    httpServletRequestSupplier.get();
+                final HttpServletRequest request;
+                if (httpServletRequestSupplier != null) {
+                    request = httpServletRequestSupplier.get();
+                } else {
+                    request = null;
+                }
                 final String addressRecord = request != null ?
                         revocationCache.getRevocationRecord(REVOCATION_CONTEXT,
                                 ADDRESS_REVOCATION_PREFIX + request.getRemoteAddr()) :
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSAcceptorLoginModule.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSAcceptorLoginModule.java
index 27d344f32..0df90107b 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSAcceptorLoginModule.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSAcceptorLoginModule.java
@@ -95,7 +95,8 @@ public class GSSAcceptorLoginModule {
      * @throws LoginException if an error occurs
      */
     public Subject login() throws LoginException {
-        if (krbModule == null) {
+        final LoginModule module = krbModule;
+        if (module == null) {
             throw new LoginException("No JAAS module for Kerberos available");
         }
 
@@ -103,9 +104,9 @@ public class GSSAcceptorLoginModule {
         final UsernamePasswordCallbackHandler callbackH =
                 new UsernamePasswordCallbackHandler(realm.getServicePrincipal(), realm.getPassword());
         final Subject subject = new Subject();
-        krbModule.initialize(subject, callbackH, state, options);
-        if (krbModule.login()) {
-            krbModule.commit();
+        module.initialize(subject, callbackH, state, options);
+        if (module.login()) {
+            module.commit();
         }
         return subject;
     }
@@ -116,8 +117,9 @@ public class GSSAcceptorLoginModule {
      * @throws LoginException if an error occurs
      */
     public void logout() throws LoginException {
-        if (krbModule != null) {
-            krbModule.logout();
+        final LoginModule module = krbModule;
+        if (module != null) {
+            module .logout();
         }
     }
 
@@ -148,19 +150,21 @@ public class GSSAcceptorLoginModule {
         @Override
         public void handle(@Nullable final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
             if (callbacks != null && callbacks.length > 0) {
-                if (name == null || name.length() == 0) {
+                final String nm = name;
+                if (nm == null || nm.length() == 0) {
                     throw new IllegalArgumentException("No username provided");
                 }
 
-                if (password == null || password.length() == 0) {
+                final String pwd = password;
+                if (pwd == null || pwd.length() == 0) {
                     throw new IllegalArgumentException("No password provided");
                 }
 
                 for (final Callback c : callbacks) {
                     if (c instanceof NameCallback) {
-                        ((NameCallback) c).setName(name);
+                        ((NameCallback) c).setName(nm);
                     } else if (c instanceof PasswordCallback) {
-                        ((PasswordCallback) c).setPassword(password.toCharArray());
+                        ((PasswordCallback) c).setPassword(pwd.toCharArray());
                     } else {
                         throw new UnsupportedCallbackException(c);
                     }
@@ -169,4 +173,4 @@ public class GSSAcceptorLoginModule {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSContextAcceptor.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSContextAcceptor.java
index 405f422e7..19363e5f6 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSContextAcceptor.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/GSSContextAcceptor.java
@@ -53,7 +53,7 @@ public class GSSContextAcceptor {
     /** The Kerberos settings. */
     @Nonnull private KerberosSettings kerberosSettings;
 
-    /** The realm in use. */
+    /** The realm in use. Debug use only. */
     @Nullable private KerberosRealmSettings realmSettings;
     
     /** The Kerberos login module and server login state. */
@@ -110,14 +110,15 @@ public class GSSContextAcceptor {
     @Nullable public byte[] acceptSecContext(@Nonnull final byte[] inToken, final int offset, final int len)
             throws Exception {
 
-        if (context == null) {
+        final GSSContext ctxt = context;
+        if (ctxt == null) {
             log.trace("Processing first GSS input token");
             return acceptFirstToken(inToken, offset, len);
         }
         
         log.trace("Processing an additional GSS input token");
-        final byte[] tokenOut = context.acceptSecContext(inToken, offset, len);
-        if (context.isEstablished()) {
+        final byte[] tokenOut = ctxt.acceptSecContext(inToken, offset, len);
+        if (ctxt.isEstablished()) {
             log.trace("Security context established");
         } else {
             log.trace("Security context partially established");
@@ -171,16 +172,17 @@ public class GSSContextAcceptor {
         // We loop over each realm to determine which one might work.
         
         Exception preserved = null;
-        
         for (final KerberosRealmSettings realm : kerberosSettings.getRealms()) {
             
             log.debug("Validating the first GSS input token against service principal: {}",
                     realm.getServicePrincipal());
             try {
                 createGSSContext(realm);
+                assert context != null;
                 final byte[] tokenOut = context.acceptSecContext(inToken, offset, len);
                 realmSettings = realm;
-                if (getContext().isEstablished()) {
+                assert context != null;
+                if (context.isEstablished()) {
                     log.trace("Security context fully established");
                 } else {
                     log.trace("Security context partially established");
@@ -209,11 +211,12 @@ public class GSSContextAcceptor {
             throws GSSException, LoginException, PrivilegedActionException {
         
         // Establish server login credentials.
-        Subject krbSubject = null;
+        final Subject krbSubject;
         krbLoginModule = new GSSAcceptorLoginModule(realm, kerberosSettings.getRefreshKrb5Config(),
                 kerberosSettings.getLoginModuleClassName());
         try {
             krbSubject = krbLoginModule.login();
+            assert krbSubject != null;
         } catch (final LoginException e) {
             log.error("Server login error using principal: {}", realm.getServicePrincipal());
             throw e;
@@ -255,7 +258,8 @@ public class GSSContextAcceptor {
                 return newServerCreds;
             }
         };
-        return Subject.doAs(subject, action);
+        final GSSCredential result = Subject.doAs(subject, action);
+        assert result != null;
+        return result;
     }
-
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/KerberosSettings.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/KerberosSettings.java
index a3884f4f6..9232753b8 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/KerberosSettings.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/KerberosSettings.java
@@ -18,17 +18,15 @@
 package net.shibboleth.idp.authn.spnego.impl;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -44,12 +42,12 @@ public class KerberosSettings {
     private boolean refreshKrb5Config;
 
     /** List of realms (KerberosRealmSettings objects). */
-    @NonnullAfterInit @NonnullElements private Collection<KerberosRealmSettings> realmSettings;
+    @Nonnull @NonnullElements private Collection<KerberosRealmSettings> realmSettings;
 
     /** Constructor. */
     public KerberosSettings() {
         loginModuleClassName = "com.sun.security.auth.module.Krb5LoginModule";
-        realmSettings = Collections.emptyList();
+        realmSettings = CollectionSupport.emptyList();
     }
 
     /**
@@ -96,9 +94,9 @@ public class KerberosSettings {
      */
     public void setRealms(@Nullable @NonnullElements final Collection<KerberosRealmSettings> realms) {
         if (realms != null) {
-            realmSettings = List.copyOf(realms);
+            realmSettings = CollectionSupport.copyToList(realms);
         } else {
-            realmSettings = Collections.emptyList();
+            realmSettings = CollectionSupport.emptyList();
         }
     }
 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
index 3a1c3daf8..1bfacd72c 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
@@ -26,6 +26,7 @@ import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosPrincipal;
 
 import org.apache.commons.codec.binary.Base64;
+import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSName;
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -153,8 +154,10 @@ public class SPNEGOAuthnController {
                 return null;
             }
         }
+        assert acceptor != null;
 
         final byte[] gssapiData = Base64.decodeBase64(authorizationHeader.substring(10).getBytes());
+        assert gssapiData != null;
         log.trace("SPNEGO negotiation, Authorization header received, gssapi-data: {}", gssapiData);
 
         // NTLM Authentication is not supported.
@@ -179,10 +182,11 @@ public class SPNEGOAuthnController {
 
         // If the context is established, we can attempt to retrieve the name of the "context initiator."
         // In the case of the Kerberos mechanism, the context initiator is the Kerberos principal of the client.
-        if (acceptor.getContext() != null && acceptor.getContext().isEstablished()) {
+        final GSSContext ctx = acceptor.getContext();
+        if (ctx != null && ctx.isEstablished()) {
             log.debug("GSS security context is complete");
             try {
-                final GSSName clientGSSName = acceptor.getContext().getSrcName();
+                final GSSName clientGSSName = ctx.getSrcName();
                 if (clientGSSName == null) {
                     // This case should never happen, but we observed it. Handle it as authentication failure.
                     log.error("Error extracting principal name from security context, " +
@@ -208,7 +212,9 @@ public class SPNEGOAuthnController {
             // The context is not complete yet.
             // return "WWW-Authenticate: Negotiate <data>" to the browser
             log.trace("SPNEGO negotiation in process, output token: {}", tokenBytes);
-            return replyUnauthorizedNegotiate(prc, httpRequest, httpResponse, Base64.encodeBase64String(tokenBytes));
+            final String encoded = Base64.encodeBase64String(tokenBytes);
+            assert encoded != null;
+            return replyUnauthorizedNegotiate(prc, httpRequest, httpResponse, encoded);
         }
         
         return null;
@@ -226,7 +232,7 @@ public class SPNEGOAuthnController {
      * @throws ExternalAuthenticationException ...
      */
     @RequestMapping(value = "/{conversationKey}/error", method = RequestMethod.GET)
-    public void handleError(@PathVariable final String conversationKey, @Nonnull final HttpServletRequest httpRequest,
+    public void handleError(@PathVariable @Nonnull final String conversationKey, @Nonnull final HttpServletRequest httpRequest,
             @Nonnull final HttpServletResponse httpResponse) throws ExternalAuthenticationException, IOException {
 
         log.warn("SPNEGO authentication problem signaled by client");
@@ -252,7 +258,9 @@ public class SPNEGOAuthnController {
 
         // Store the user as a username and as a real KerberosPrincipal object.
         final Subject subject = new Subject();
-        subject.getPrincipals().add(new UsernamePrincipal(kerberosPrincipal.getName()));
+        final String name = kerberosPrincipal.getName();
+        assert name != null;
+        subject.getPrincipals().add(new UsernamePrincipal(name));
         subject.getPrincipals().add(kerberosPrincipal);
 
         // Finish the external authentication task and return to the flow.
@@ -326,7 +334,9 @@ public class SPNEGOAuthnController {
      */
     @Nonnull
     protected GSSContextAcceptor createGSSContextAcceptor(@Nonnull final SPNEGOContext spnegoCtx) throws GSSException {
-        return new GSSContextAcceptor(spnegoCtx.getKerberosSettings());
+        final KerberosSettings settings = spnegoCtx.getKerberosSettings();
+        assert settings != null;
+        return new GSSContextAcceptor(settings);
     }
 
     /**

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list