[java-identity-provider] branch main updated: IDP-2069 - Null Handling Task

Rod Widdowson rdw at steadingsoftware.com
Wed Apr 12 15:14:29 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=d9b41c81b676928edc651c17d2a1202b1aac9b59

The following commit(s) were added to refs/heads/main by this push:
     new d9b41c81b IDP-2069 - Null Handling Task
d9b41c81b is described below

commit d9b41c81b676928edc651c17d2a1202b1aac9b59
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Wed Apr 12 16:02:18 2023 +0100

    IDP-2069 - Null Handling Task
    
    https://shibboleth.atlassian.net/browse/IDP-2069
    
    idp-saml-impl, idp-authn-impl, idp-session-impl
       - More changes to exploit the @NonnullBeforeExec annotation
       - Remove warnings (yellow) for Generic Type issues,
         null issues, but not deprecations (except tests)
---
 .../idp/authn/duo/impl/ValidateDuoAuthAPI.java     | 36 ++++++++----------
 .../idp/authn/duo/impl/ValidateDuoWebResponse.java | 16 ++++----
 .../impl/TransitionMultiFactorAuthentication.java  | 32 +++++++---------
 .../authn/impl/ValidateExternalAuthentication.java | 44 +++++++++++-----------
 .../idp/authn/impl/ValidateRemoteUser.java         |  8 ++--
 .../idp/authn/impl/ValidateUserAgentAddress.java   | 13 +++----
 .../impl/FilterFlowsByNonBrowserSupportTest.java   | 10 ++---
 .../impl/ProfileInterceptorFlowDescriptorTest.java | 14 +++----
 ...WriteProfileInterceptorResultToStorageTest.java |  2 +-
 .../BaseAddAuthenticationStatementToAssertion.java | 16 +++++---
 .../saml/saml2/profile/impl/AddAuthnRequest.java   |  4 +-
 .../impl/ProcessAssertionsForAuthentication.java   | 20 ++++------
 .../profile/impl/ProcessRequestedAuthnContext.java |  7 ++--
 .../profile/impl/ValidateSAMLAuthentication.java   |  4 +-
 .../impl/BasicSPSessionCreationStrategy.java       |  4 +-
 .../idp/session/impl/DestroySessions.java          | 14 +++----
 .../idp/session/impl/DetectIdentitySwitch.java     | 15 +++-----
 .../impl/ExtractActiveAuthenticationResults.java   | 10 ++---
 .../impl/PopulateLogoutPropagationContext.java     |  3 +-
 .../PopulateMultiRPContextFromLogoutContext.java   | 12 +++---
 .../idp/session/impl/StorageBackedIdPSession.java  |  5 ++-
 .../impl/StorageBackedIdPSessionSerializer.java    | 28 ++++++++++----
 .../session/impl/StorageBackedSessionManager.java  | 24 +++++++-----
 .../UpdateSessionWithAuthenticationResult.java     | 15 +++-----
 .../session/impl/UpdateSessionWithSPSession.java   |  7 ++--
 .../session/impl/BasicSPSessionSerializerTest.java |  1 +
 .../idp/session/impl/DestroySessionsTest.java      |  1 +
 .../idp/session/impl/DetectIdentitySwitchTest.java |  1 +
 .../idp/session/impl/ProcessLogoutTest.java        |  2 +-
 .../session/impl/SessionManagerBaseTestCase.java   |  1 +
 .../StorageBackedIdPSessionSerializerTest.java     |  2 +-
 .../impl/StorageBackedSessionManagerTest.java      |  1 +
 .../UpdateSessionWithAuthenticationResultTest.java | 23 ++++++-----
 .../impl/UpdateSessionWithSPSessionTest.java       |  2 +
 34 files changed, 198 insertions(+), 199 deletions(-)

diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
index 76232d22e..05dd42335 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
@@ -48,6 +48,7 @@ import net.shibboleth.idp.authn.impl.AbstractAuditingValidationAction;
 import net.shibboleth.idp.profile.IdPAuditFields;
 import net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
@@ -99,13 +100,13 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
     @NonnullAfterInit private DuoPreauthAuthenticator preauthAuthenticator;
 
     /** DuoApi context for tokens. Non-Null after preExecute **/
-    @Nullable @NotEmpty private DuoAuthenticationContext duoContext;
+    @NonnullBeforeExec @NotEmpty private DuoAuthenticationContext duoContext;
 
     /** Duo integration to use. */
-    @Nullable private DuoIntegration duoIntegration;
+    @NonnullBeforeExec private DuoIntegration duoIntegration;
 
     /** Attempted username. */
-    @Nullable @NotEmpty private String username;
+    @NonnullBeforeExec @NotEmpty private String username;
 
     /** Constructor. */
     public ValidateDuoAuthAPI() {
@@ -202,14 +203,14 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             return false;
         }
 
-        final DuoAuthenticationContext context = duoContext = authenticationContext.getSubcontext(DuoAuthenticationContext.class);
-        if (context == null) {
+        duoContext = authenticationContext.getSubcontext(DuoAuthenticationContext.class);
+        if (duoContext == null) {
             log.info("{} No DuoAuthenticationContext available", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, "No DuoAuthenticationContext context available",
                     AuthnEventIds.INVALID_AUTHN_CTX);
             recordFailure(profileRequestContext);
             return false;
-        } else if (context.getFactor() == null) {
+        } else if (duoContext.getFactor() == null) {
             log.info("{} No factor set in DuoAuthenticationContext", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, "No Duo factor set in DuoAuthenticationContext",
                     AuthnEventIds.REQUEST_UNSUPPORTED);
@@ -217,7 +218,7 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             return false;
         }
 
-        context.setUsername(username);
+        duoContext.setUsername(username);
 
         return true;
     }
@@ -228,13 +229,10 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             @Nonnull final AuthenticationContext authenticationContext) {
 
         log.trace("{} Attempting Duo AuthAPI authentication", getLogPrefix());
-        final DuoAuthenticationContext duoCtx = duoContext;
-        assert duoCtx != null;
         
         try {
             // Duo AuthAPI pre-authentication
-            assert duoIntegration != null;
-            final DuoPreauthResponse preAuthResponse = preauthAuthenticator.authenticate(duoCtx, duoIntegration);
+            final DuoPreauthResponse preAuthResponse = preauthAuthenticator.authenticate(duoContext, duoIntegration);
             if (preAuthResponse == null) {
                 log.info("{} No Duo AuthAPI preauthentication response", getLogPrefix());
                 throw new DuoWebException("No preauthentication response");
@@ -262,10 +260,10 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             }
             
             // Validate device ID specified against the enrolled set.
-            if (duoCtx.getDeviceID() != null && !DuoAuthAPI.DUO_DEVICE_AUTO.equals(duoCtx.getDeviceID())) {
+            if (duoContext.getDeviceID() != null && !DuoAuthAPI.DUO_DEVICE_AUTO.equals(duoContext.getDeviceID())) {
                 boolean found = false;
                 for (final DuoDevice device : preAuthResponse.getDevices()) {
-                    final String deviceId = duoCtx.getDeviceID();
+                    final String deviceId = duoContext.getDeviceID();
                     assert deviceId != null;
                     if (deviceId.equals(device.getDevice())) {
                         found = true;
@@ -273,14 +271,14 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
                     } else if (deviceId.equals(device.getName())) {
                         log.debug("{} Remapped device ID based on device name ({}) for '{}'", getLogPrefix(),
                                 device.getName(), username);
-                        duoCtx.setDeviceID(device.getDevice());
+                        duoContext.setDeviceID(device.getDevice());
                         found = true;
                         break;
                     }
                 }
                 if (!found) {
                     log.info("{} Duo authentication failed for '{}': non-existent device ID ({})", getLogPrefix(),
-                            username, duoCtx.getDeviceID());
+                            username, duoContext.getDeviceID());
                     handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
                             AuthnEventIds.INVALID_CREDENTIALS);
                     recordFailure(profileRequestContext);
@@ -289,8 +287,7 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             }
 
             // Duo AuthAPI authentication
-            assert duoIntegration != null;
-            final DuoAuthResponse authenticationResponse = authAuthenticator.authenticate(duoCtx, duoIntegration);
+            final DuoAuthResponse authenticationResponse = authAuthenticator.authenticate(duoContext, duoIntegration);
             if (authenticationResponse == null) {
                 log.info("{} No Duo AuthAPI authentication response", getLogPrefix());
                 throw new DuoWebException("No authentication response");
@@ -299,7 +296,7 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
             final String authResult = authenticationResponse.getResult();
             if (DuoAuthAPI.DUO_AUTH_RESULT_ALLOW.equals(authResult)) {
                 log.info("{} Duo authentication succeeded for '{}' (Factor: {}, Device: {})", getLogPrefix(), username,
-                        duoCtx.getFactor(), duoCtx.getDeviceID());
+                        duoContext.getFactor(), duoContext.getDeviceID());
                 recordSuccess(profileRequestContext);
                 buildAuthenticationResult(profileRequestContext, authenticationContext);
             } else if (DuoAuthAPI.DUO_AUTH_RESULT_DENY.equals(authResult)) {
@@ -320,10 +317,9 @@ public class ValidateDuoAuthAPI extends AbstractAuditingValidationAction {
 
     /** {@inheritDoc} */
     @Override protected @Nonnull Subject populateSubject(@Nonnull final Subject subject) {
-        assert username != null;
+        assert isPreExecuteCalled();
         final DuoPrincipal princ = new DuoPrincipal(username);
         subject.getPrincipals().add(princ);
-        assert duoIntegration != null;
         final Set<Principal> princs = duoIntegration.getSupportedPrincipals(Principal.class);
         subject.getPrincipals().addAll(princs);
         return subject;
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoWebResponse.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoWebResponse.java
index 0ec7d6876..f950993aa 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoWebResponse.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoWebResponse.java
@@ -46,6 +46,7 @@ import net.shibboleth.idp.authn.duo.DuoPrincipal;
 import net.shibboleth.idp.authn.impl.AbstractAuditingValidationAction;
 import net.shibboleth.idp.profile.IdPAuditFields;
 import net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.logic.FunctionSupport;
@@ -87,13 +88,13 @@ public class ValidateDuoWebResponse extends AbstractAuditingValidationAction {
     @Nonnull private Function<ProfileRequestContext,String> usernameLookupStrategy;
     
     /** Duo integration to use. */
-    @Nullable private DuoIntegration duoIntegration;
+    @NonnullBeforeExec private DuoIntegration duoIntegration;
     
     /** Attempted username. */
-    @Nullable @NotEmpty private String username;
+    @NonnullBeforeExec @NotEmpty private String username;
     
     /** Signed response string. */
-    @Nullable @NotEmpty private String signedResponse;
+    @NonnullBeforeExec @NotEmpty private String signedResponse;
     
     /** Constructor. */
     public ValidateDuoWebResponse() {
@@ -166,8 +167,8 @@ public class ValidateDuoWebResponse extends AbstractAuditingValidationAction {
             return false;
         }
         
-        final String response =  signedResponse = servletRequest.getParameter(RESPONSE_PARAM);
-        if (response == null || response.isEmpty()) {
+        signedResponse = servletRequest.getParameter(RESPONSE_PARAM);
+        if (signedResponse == null || signedResponse.isEmpty()) {
             log.warn("{} No signed Duo response in the request", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                     AuthnEventIds.NO_CREDENTIALS);
@@ -187,7 +188,6 @@ public class ValidateDuoWebResponse extends AbstractAuditingValidationAction {
                 
         final String usernameFromDuo;
         try {
-            assert duoIntegration != null && signedResponse != null;
             usernameFromDuo = DuoSupport.validateSignedResponseToken(duoIntegration, signedResponse);
         } catch (final InvalidKeyException | NoSuchAlgorithmException | DuoWebException | IOException e) {
             log.warn("{} Error validating signed Duo response for username '{}'", getLogPrefix(), username, e);
@@ -195,7 +195,6 @@ public class ValidateDuoWebResponse extends AbstractAuditingValidationAction {
             recordFailure(profileRequestContext);
             return;
         }
-        assert username != null;
         if (!username.equals(usernameFromDuo)) {
             log.warn("{} Username '{}' from Duo response does not match previously established username '{}'",
                     getLogPrefix(), usernameFromDuo, username);
@@ -213,10 +212,9 @@ public class ValidateDuoWebResponse extends AbstractAuditingValidationAction {
     @Override
     protected @Nonnull Subject populateSubject(@Nonnull final Subject subject) {
 
-        assert username != null;
+        assert isPreExecuteCalled();
         final DuoPrincipal princ = new DuoPrincipal(username);
         subject.getPrincipals().add(princ);
-        assert duoIntegration != null;
         final Set<Principal> princs = duoIntegration.getSupportedPrincipals(Principal.class);
         subject.getPrincipals().addAll(princs);
 
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 2c62a68b7..d02a767a0 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
@@ -37,6 +37,7 @@ import net.shibboleth.idp.authn.MultiFactorAuthenticationTransition;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext;
 import net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -98,7 +99,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
     private boolean validateLoginTransitions;
 
     /** A subordinate {@link MultiFactorAuthenticationContext}, if any. */
-    @Nullable private MultiFactorAuthenticationContext mfaContext;
+    @NonnullBeforeExec private MultiFactorAuthenticationContext mfaContext;
     
     /** Holds the last event processed by the system. */
     @Nullable private String previousEvent;
@@ -168,18 +169,14 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         return true;
     }
 
-
 // Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override
     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(mfaCtxt.getAuthenticationFlowDescriptor());
+        authenticationContext.setAttemptedFlow(mfaContext.getAuthenticationFlowDescriptor());
 
         // If the holding variable is already set, this is a recursive invocation.
         if (previousEvent == null) {
@@ -200,7 +197,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
             if (EventIds.PROCEED_EVENT_ID.equals(previousEvent)) {                
                 log.debug("{} Preserving authentication result from '{}' flow", getLogPrefix(),
                         result.getAuthenticationFlowId());
-                mfaCtxt.getActiveResults().put(result.getAuthenticationFlowId(), result);
+                mfaContext.getActiveResults().put(result.getAuthenticationFlowId(), result);
             } else {
                 log.debug("{} Discarding incomplete authentication result from '{}' flow", getLogPrefix(),
                         result.getAuthenticationFlowId());
@@ -210,8 +207,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 = mfaCtxt.getNextFlowId();
-        mfaCtxt.setNextFlowId(null);
+        final String prevFlowId = mfaContext.getNextFlowId();
+        mfaContext.setNextFlowId(null);
         if (prevFlowId == null) {
             log.debug("{} Applying MFA transition rule to determine initial state", getLogPrefix());
         } else {
@@ -219,7 +216,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         }
 
         String flowId = null;
-        final MultiFactorAuthenticationTransition transition = mfaCtxt.getTransitionMap().get(prevFlowId);
+        final MultiFactorAuthenticationTransition transition = mfaContext.getTransitionMap().get(prevFlowId);
         if (transition != null) {
             assert previousEvent != null;
             flowId = transition.getNextFlowStrategy(previousEvent).apply(profileRequestContext);
@@ -229,11 +226,11 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
         }
         if (flowId != null) {
             log.debug("{} MFA flow transition after '{}' event to '{}' flow", getLogPrefix(), previousEvent, flowId);
-            mfaCtxt.setNextFlowId(flowId);
+            mfaContext.setNextFlowId(flowId);
             assert transition != null;
             doTransition(profileRequestContext, authenticationContext, transition);
         } else {
-            final String event = mfaCtxt.getEvent() != null ? mfaCtxt.getEvent() : previousEvent;
+            final String event = mfaContext.getEvent() != null ? mfaContext.getEvent() : previousEvent;
             assert event != null;
             log.debug("{} MFA flow completing with event '{}'", getLogPrefix(), event);
             if (EventIds.PROCEED_EVENT_ID.equals(event)) {
@@ -257,11 +254,10 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
             @Nonnull final AuthenticationContext authenticationContext,
             @Nonnull final MultiFactorAuthenticationTransition transition) {
 
-        MultiFactorAuthenticationContext mfaCtxt = mfaContext;
-        assert mfaCtxt != null;
+        assert isPreExecuteCalled();
 
         // Non-authentication flows can just be executed (via a "proceed" event).
-        final String flowId = Constraint.isNotNull(mfaCtxt.getNextFlowId(), "No previous flow");
+        final String flowId = Constraint.isNotNull(mfaContext.getNextFlowId(), "No previous flow");
         if (!flowId.startsWith("authn/")) {
             ActionSupport.buildProceedEvent(profileRequestContext);
             return;
@@ -280,7 +276,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 = mfaCtxt.getActiveResults().get(flowId);
+        final AuthenticationResult activeResult = mfaContext.getActiveResults().get(flowId);
         if (activeResult != null) {
             if (activeResult.test(profileRequestContext)) {
                 log.debug("{} Reusing active result for flow {}", getLogPrefix(), flowId);
@@ -291,7 +287,7 @@ public class TransitionMultiFactorAuthentication extends AbstractAuthenticationA
                 return;
             }
             log.debug("{} Active result for flow {} not reusable, ignoring", getLogPrefix(), flowId);
-            mfaCtxt.getActiveResults().remove(flowId);
+            mfaContext.getActiveResults().remove(flowId);
         }
      
         if (validateLoginTransitions) {
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 ac4e7fbd8..9c8436192 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
@@ -51,6 +51,7 @@ import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
 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.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
@@ -93,7 +94,7 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
     @Nullable private Pattern matchExpression;
     
     /** Context containing the result to validate. */
-    @Nullable private ExternalAuthenticationContext extContext;
+    @NonnullBeforeExec private ExternalAuthenticationContext extContext;
     
     /** Context for externally supplied inbound attributes. */
     @Nullable private AttributeContext attributeContext;
@@ -167,33 +168,32 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        @Nonnull ExternalAuthenticationContext localExtContext = Constraint.isNotNull(extContext, "external Authn Context cannot be null");
-        final Exception authnExp = localExtContext.getAuthnException();
-        final String principalName = localExtContext.getPrincipalName();
+        final Exception authnExp = extContext.getAuthnException();
+        final String principalName = extContext.getPrincipalName();
         if (authnExp != null) {
-            log.info("{} External authentication produced exception", getLogPrefix(), localExtContext.getAuthnException());
+            log.info("{} External authentication produced exception", getLogPrefix(), extContext.getAuthnException());
             handleError(profileRequestContext, authenticationContext, authnExp,
                     AuthnEventIds.AUTHN_EXCEPTION);
             recordFailure(profileRequestContext);
             return;
-        } else if (localExtContext.getAuthnError() != null) {
+        } else if (extContext.getAuthnError() != null) {
             log.info("{} External authentication produced error message: {}", getLogPrefix(),
-                    localExtContext.getAuthnError());
-            handleError(profileRequestContext, authenticationContext, localExtContext.getAuthnError(),
+                    extContext.getAuthnError());
+            handleError(profileRequestContext, authenticationContext, extContext.getAuthnError(),
                     AuthnEventIds.AUTHN_EXCEPTION);
             recordFailure(profileRequestContext);
             return;
         }
-        if (localExtContext.getSubject() != null) {
+        if (extContext.getSubject() != null) {
             log.info("{} External authentication succeeded for Subject", getLogPrefix());
-        } else if (localExtContext.getPrincipal() != null) {
+        } else if (extContext.getPrincipal() != null) {
             log.info("{} External authentication succeeded for Principal: {}", getLogPrefix(),
-                    localExtContext.getPrincipal());
-            localExtContext.setSubject(new Subject(false, Collections.singleton(localExtContext.getPrincipal()),
+                    extContext.getPrincipal());
+            extContext.setSubject(new Subject(false, Collections.singleton(extContext.getPrincipal()),
                     Collections.emptySet(), Collections.emptySet()));
         } else if (principalName!= null) {
             log.info("{} External authentication succeeded for user: {}", getLogPrefix(), principalName);
-            localExtContext.setSubject(new Subject(false,
+            extContext.setSubject(new Subject(false,
                     Collections.singleton(new UsernamePrincipal(principalName)),
                     Collections.emptySet(), Collections.emptySet()));
         } else {
@@ -203,7 +203,7 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
                     AuthnEventIds.NO_CREDENTIALS);
             return;
         }
-        final Subject subject = localExtContext.getSubject();
+        final Subject subject = extContext.getSubject();
         assert subject != null;
         
         if (!checkUsername(subject)) {
@@ -215,28 +215,28 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
         
         recordSuccess(profileRequestContext);
         
-        if (!localExtContext.getAuthenticatingAuthorities().isEmpty()) {
+        if (!extContext.getAuthenticatingAuthorities().isEmpty()) {
             final ProxyAuthenticationPrincipal proxied =
-                    new ProxyAuthenticationPrincipal(localExtContext.getAuthenticatingAuthorities());
+                    new ProxyAuthenticationPrincipal(extContext.getAuthenticatingAuthorities());
             subject.getPrincipals().add(proxied);
         }
         
-        if (localExtContext.doNotCache()) {
+        if (extContext.doNotCache()) {
             log.debug("{} Disabling caching of authentication result", getLogPrefix());
             authenticationContext.setResultCacheable(false);
         }
         
-        filterAttributes(localExtContext);
+        filterAttributes(extContext);
         
         buildAuthenticationResult(profileRequestContext, authenticationContext);
         
         final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
         if (ar != null) {
-            final Instant ai = localExtContext.getAuthnInstant();
+            final Instant ai = extContext.getAuthnInstant();
             if (ai != null) {
                 ar.setAuthenticationInstant(ai);
             }
-            if (localExtContext.isPreviousResult()) {
+            if (extContext.isPreviousResult()) {
                 ar.setPreviousResult(true);
             }
         }
@@ -248,8 +248,8 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
     @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
         // 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");
-        final Subject localSubject = Constraint.isNotNull(localExtContext.getSubject(), "external Authn Subject cannot be null");
+        assert isPreExecuteCalled();
+        final Subject localSubject = Constraint.isNotNull(extContext.getSubject(), "external Authn Subject cannot be null");
         localSubject.getPrincipals().addAll(subject.getPrincipals());
 
         final AttributeContext ac= attributeContext;
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 d69edb125..f4fead2b2 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
@@ -33,6 +33,7 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UsernameContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -70,7 +71,7 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
     @Nullable private Pattern matchExpression;
 
     /** Username context identifying identity to validate. */
-    @Nullable private UsernameContext usernameContext;
+    @NonnullBeforeExec private UsernameContext usernameContext;
     
     /** Constructor. */
     public ValidateRemoteUser() {
@@ -130,7 +131,6 @@ 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,
@@ -146,9 +146,7 @@ public class ValidateRemoteUser extends AbstractAuditingValidationAction {
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        final UsernameContext uCtxt = usernameContext;
-        assert uCtxt != null;
-        final String userName = uCtxt.getUsername();
+        final String userName = usernameContext.getUsername();
         assert userName != null;
         if (!isAuthenticated(userName)) {
             log.info("{} User '{}' was not valid", getLogPrefix(), userName);
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 b70b56f67..c0b0230ff 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
@@ -38,6 +38,7 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UserAgentContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.profile.IdPAuditFields;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -68,7 +69,7 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
     @Nonnull @NonnullElements private Map<String,Collection<IPRange>> mappings;
 
     /** User Agent context containing address to evaluate. */
-    @Nullable private UserAgentContext uaContext;
+    @NonnullBeforeExec private UserAgentContext uaContext;
     
     /** The principal name established by the action, if any. */
     @Nullable private String principalName;
@@ -107,15 +108,15 @@ public class ValidateUserAgentAddress extends AbstractAuditingValidationAction {
             return false;
         }
 
-        final UserAgentContext uaCtx = uaContext = authenticationContext.getSubcontext(UserAgentContext.class);
-        if (uaCtx == null) {
+        uaContext = authenticationContext.getSubcontext(UserAgentContext.class);
+        if (uaContext == null) {
             log.debug("{} No UserAgentContext available within authentication context", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                     AuthnEventIds.NO_CREDENTIALS);
             return false;
         }
 
-        if (uaCtx.getAddress() == null) {
+        if (uaContext.getAddress() == null) {
             log.debug("{} No address available within UserAgentContext", getLogPrefix());
             handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                     AuthnEventIds.NO_CREDENTIALS);
@@ -130,9 +131,7 @@ 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();
+        final InetAddress addr = uaContext.getAddress();
         assert addr != null;
         for (final Map.Entry<String,Collection<IPRange>> e : mappings.entrySet()) {
             final Collection<IPRange> ranges = e.getValue();
diff --git a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/FilterFlowsByNonBrowserSupportTest.java b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/FilterFlowsByNonBrowserSupportTest.java
index 94128a7bc..8449d259a 100644
--- a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/FilterFlowsByNonBrowserSupportTest.java
+++ b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/FilterFlowsByNonBrowserSupportTest.java
@@ -17,18 +17,16 @@
 
 package net.shibboleth.idp.profile.interceptor.impl;
 
-import net.shibboleth.idp.profile.context.ProfileInterceptorContext;
-import net.shibboleth.idp.profile.testing.ActionTestingSupport;
-
-import static org.testng.Assert.assertEquals;
-
 import org.springframework.webflow.execution.Event;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import net.shibboleth.idp.profile.context.ProfileInterceptorContext;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+
 /** {@link FilterFlowsByNonBrowserSupport} unit test. */
- at SuppressWarnings("javadoc")
+ at SuppressWarnings({"javadoc", "null"})
 public class FilterFlowsByNonBrowserSupportTest extends PopulateProfileInterceptorContextTest {
 
     private FilterFlowsByNonBrowserSupport action;
diff --git a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/ProfileInterceptorFlowDescriptorTest.java b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/ProfileInterceptorFlowDescriptorTest.java
index 997c37b82..b1a9b72ea 100644
--- a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/ProfileInterceptorFlowDescriptorTest.java
+++ b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/ProfileInterceptorFlowDescriptorTest.java
@@ -17,12 +17,6 @@
 
 package net.shibboleth.idp.profile.interceptor.impl;
 
-import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
-import net.shibboleth.idp.profile.interceptor.ProfileInterceptorFlowDescriptor;
-import net.shibboleth.idp.profile.testing.RequestContextBuilder;
-import net.shibboleth.shared.component.UnmodifiableComponentException;
-import net.shibboleth.shared.logic.PredicateSupport;
-
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.storage.StorageService;
 import org.springframework.webflow.execution.RequestContext;
@@ -30,10 +24,14 @@ import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.google.common.base.Predicates;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.profile.interceptor.ProfileInterceptorFlowDescriptor;
+import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.shared.component.UnmodifiableComponentException;
+import net.shibboleth.shared.logic.PredicateSupport;
 
 /** {@link ProfileInterceptorFlowDescriptor} unit test. */
- at SuppressWarnings("javadoc")
+ at SuppressWarnings({"javadoc", "null"})
 public class ProfileInterceptorFlowDescriptorTest {
 
     private ProfileInterceptorFlowDescriptor descriptor;
diff --git a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/WriteProfileInterceptorResultToStorageTest.java b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/WriteProfileInterceptorResultToStorageTest.java
index f04637ee8..3020315b8 100644
--- a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/WriteProfileInterceptorResultToStorageTest.java
+++ b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/interceptor/impl/WriteProfileInterceptorResultToStorageTest.java
@@ -40,7 +40,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /** {@link WriteProfileInterceptorResultToStorage} unit test. */
- at SuppressWarnings("javadoc")
+ at SuppressWarnings({"javadoc", "null"})
 public class WriteProfileInterceptorResultToStorageTest {
 
     private RequestContext src;
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAuthenticationStatementToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAuthenticationStatementToAssertion.java
index a698321f0..9506e3e2f 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAuthenticationStatementToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAuthenticationStatementToAssertion.java
@@ -37,6 +37,7 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.profile.config.navigate.IdentifierGenerationStrategyLookupFunction;
 import net.shibboleth.profile.context.navigate.IssuerLookupFunction;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.security.IdentifierGenerationStrategy;
@@ -71,13 +72,13 @@ public abstract class BaseAddAuthenticationStatementToAssertion extends Abstract
     @NonnullAfterInit private Function<ProfileRequestContext,String> addressLookupStrategy;
     
     /** AuthenticationResult basis of statement. */
-    @Nullable private AuthenticationResult authenticationResult;
+    @NonnullBeforeExec private AuthenticationResult authenticationResult;
 
     /** The generator to use. */
-    @Nullable private IdentifierGenerationStrategy idGenerator;
+    @NonnullBeforeExec private IdentifierGenerationStrategy idGenerator;
     
     /** EntityID to populate as assertion issuer. */
-    @Nullable private String issuerId;
+    @NonnullBeforeExec private String issuerId;
     
     /** Constructor. */
     public BaseAddAuthenticationStatementToAssertion() {
@@ -159,7 +160,8 @@ public abstract class BaseAddAuthenticationStatementToAssertion extends Abstract
      * @return the result to encode
      */
     @Nonnull public AuthenticationResult getAuthenticationResult() {
-        return Constraint.isNotNull(authenticationResult, "AuthenticationResult has not been initialized yet");
+        assert isPreExecuteCalled() && authenticationResult!=null;
+        return authenticationResult;
     }
 
     /**
@@ -168,7 +170,8 @@ public abstract class BaseAddAuthenticationStatementToAssertion extends Abstract
      * @return the ID generation strategy
      */
     @Nonnull public IdentifierGenerationStrategy getIdGenerator() {
-        return Constraint.isNotNull(idGenerator, "IdentifierGenerationStrategy has not been initialized yet");
+        assert isPreExecuteCalled() && idGenerator!=null;
+        return idGenerator;
     }
 
     /**
@@ -177,7 +180,8 @@ public abstract class BaseAddAuthenticationStatementToAssertion extends Abstract
      * @return the issuer name
      */
     @Nonnull public String getIssuerId() {
-        return Constraint.isNotNull(issuerId, "Issuer name has not been initialized yet");
+        assert isPreExecuteCalled() && issuerId!=null;
+        return issuerId;
     }
     
     /** {@inheritDoc} */
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
index 06f36edb2..67d5748d0 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
@@ -37,6 +37,7 @@ import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfigurati
 import net.shibboleth.profile.config.navigate.IdentifierGenerationStrategyLookupFunction;
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.profile.context.navigate.RelyingPartyIdLookupFunction;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.security.IdentifierGenerationStrategy;
@@ -109,7 +110,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
     @Nonnull private Function<ProfileRequestContext,ProxiedRequesterContext> proxiedRequesterContextLookupStrategy;
     
     /** The generator to use. */
-    @Nullable private IdentifierGenerationStrategy idGenerator;
+    @NonnullBeforeExec private IdentifierGenerationStrategy idGenerator;
     
     /** Applicable profile configuration. */
     @Nullable private BrowserSSOProfileConfiguration profileConfiguration;
@@ -266,7 +267,6 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
                         NameIDPolicy.DEFAULT_ELEMENT_NAME);
 
         final AuthnRequest object = requestBuilder.buildObject();
-        assert idGenerator!=null;
         object.setID(idGenerator.generateIdentifier());
         object.setIssueInstant(Instant.now());
         object.setVersion(SAMLVersion.VERSION_20);
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
index 1cec5b8b4..20ac50595 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
@@ -46,6 +46,7 @@ import org.slf4j.Logger;
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -71,10 +72,10 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
     @Nonnull private Function<Assertion,AuthnStatement> authnStatementSelectionStrategy;
     
     /** The Response to process. */
-    @Nullable private Response response;
+    @NonnullBeforeExec private Response response;
     
     /** The SAML authentication context. */
-    @Nullable private SAMLAuthnContext samlAuthnContext;
+    @NonnullBeforeExec private SAMLAuthnContext samlAuthnContext;
     
     /**
      * Constructor.
@@ -168,8 +169,7 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
         }
 
         response = responseResolver.apply(profileRequestContext);
-        final Response localResponse = response;
-        if (localResponse == null || localResponse.getAssertions() == null || localResponse.getAssertions().isEmpty()) {
+        if (response == null || response.getAssertions() == null || response.getAssertions().isEmpty()) {
             log.info("{} Profile context contained no candidate Assertions to process. Skipping further processing",
                     getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
@@ -189,22 +189,19 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
     /** {@inheritDoc} */
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
-        
-        final Response localResponse = response;
-        assert localResponse != null;
-        
+
         // Completely remove any non-valid Assertions from the Response
-        final List<Assertion> nonValid = localResponse.getAssertions().stream()
+        final List<Assertion> nonValid = response.getAssertions().stream()
                 .filter(new AssertionIsValid().negate())
                 .collect(Collectors.toList());
         log.debug("{} Removing {} non-valid Assertions from Response", getLogPrefix(), nonValid.size());
-        localResponse.getAssertions().removeAll(nonValid);
+        response.getAssertions().removeAll(nonValid);
 
         // For authn purposes, select only Assertions which contain at least 1 AuthnStatement and a confirmed Subject
         final Predicate<Assertion> selector = new AssertionContainsAuthenticationStatement()
                 .and(new AssertionContainsConfirmedSubject());
         
-        final List<Assertion> assertions = localResponse.getAssertions().stream()
+        final List<Assertion> assertions = response.getAssertions().stream()
                 .filter(selector)
                 .collect(Collectors.toList());
         if (assertions.isEmpty()) {
@@ -244,7 +241,6 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
             }
         }
         
-        assert samlAuthnContext != null;
         samlAuthnContext.setAuthnStatement(authnStatement).setSubject(authnAssertion.getSubject());
     }
 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
index 6dd63581c..7496fc54e 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
@@ -25,7 +25,6 @@ import java.util.Set;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.context.navigate.MessageLookup;
@@ -40,7 +39,6 @@ import org.opensaml.saml.saml2.core.AuthnContextDeclRef;
 import org.opensaml.saml.saml2.core.AuthnRequest;
 import org.opensaml.saml.saml2.core.RequestedAuthnContext;
 import org.slf4j.Logger;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
@@ -50,9 +48,11 @@ import net.shibboleth.idp.saml.authn.principal.AuthnContextDeclRefPrincipal;
 import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
 import net.shibboleth.profile.config.ProfileConfiguration;
 import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 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;
 import net.shibboleth.shared.primitive.StringSupport;
 
 /**
@@ -83,7 +83,7 @@ public class ProcessRequestedAuthnContext extends AbstractAuthenticationAction {
     @Nonnull @NonnullElements private Set<String> ignoredContexts;
     
     /** The request message to read from. */
-    @Nullable private AuthnRequest authnRequest;
+    @NonnullBeforeExec private AuthnRequest authnRequest;
     
     /** Constructor. */
     public ProcessRequestedAuthnContext() {
@@ -161,7 +161,6 @@ public class ProcessRequestedAuthnContext extends AbstractAuthenticationAction {
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
         
-        assert authnRequest!=null;
         final RequestedAuthnContext requestedCtx = authnRequest.getRequestedAuthnContext();
         if (requestedCtx == null) {
             log.debug("{} AuthnRequest did not contain a RequestedAuthnContext, nothing to do", getLogPrefix());
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
index 861b5a51d..96a4e7e28 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
@@ -82,6 +82,7 @@ import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfigurati
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.saml.profile.context.navigate.SAMLMetadataContextLookupFunction;
 import net.shibboleth.shared.annotation.constraint.Live;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
@@ -134,7 +135,7 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
     @Nullable @NotEmpty private String loggedAttributeId;
 
     /** Context containing the result to validate. */
-    @Nullable private SAMLAuthnContext samlAuthnContext;
+    @NonnullBeforeExec private SAMLAuthnContext samlAuthnContext;
     
     /** Store off profile config. */
     @Nullable private BrowserSSOProfileConfiguration profileConfiguration;
@@ -305,7 +306,6 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
         buildAuthenticationResult(profileRequestContext, authenticationContext);
         final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
         if (ar != null && prConfig.isProxiedAuthnInstant(profileRequestContext)) {
-            assert samlAuthnContext != null;
             final AuthnStatement as = samlAuthnContext.getAuthnStatement();
             assert as != null;
             final Instant ai = as.getAuthnInstant();
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/BasicSPSessionCreationStrategy.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/BasicSPSessionCreationStrategy.java
index cc5c7420d..52bb06994 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/BasicSPSessionCreationStrategy.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/BasicSPSessionCreationStrategy.java
@@ -91,7 +91,9 @@ public class BasicSPSessionCreationStrategy implements Function<ProfileRequestCo
         }
         
         final Instant now = Instant.now();
-        return new BasicSPSession(issuer, now, now.plus(sessionLifetime));
+        final Instant then = now.plus(sessionLifetime);
+        assert then!= null;
+        return new BasicSPSession(issuer, now, then);
     }
 
 }
\ No newline at end of file
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DestroySessions.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DestroySessions.java
index 0d2556dfe..cf314f87f 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DestroySessions.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DestroySessions.java
@@ -22,7 +22,6 @@ import java.util.function.Function;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.opensaml.messaging.context.BaseContext;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
@@ -38,6 +37,7 @@ import net.shibboleth.idp.session.SessionManager;
 import net.shibboleth.idp.session.context.LogoutContext;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -74,7 +74,7 @@ public class DestroySessions extends AbstractProfileAction {
     @Nullable private SessionContext sessionContext;
 
     /** LogoutContext to access. */
-    @Nullable private LogoutContext logoutContext;
+    @NonnullBeforeExec private LogoutContext logoutContext;
     
     /** Constructor. */
     public DestroySessions() {
@@ -136,8 +136,8 @@ public class DestroySessions extends AbstractProfileAction {
             return false;
         }
         
-        final LogoutContext lc = logoutContext = logoutContextLookupStrategy.apply(profileRequestContext);
-        if (lc == null || lc.getIdPSessions().isEmpty()) {
+        logoutContext = logoutContextLookupStrategy.apply(profileRequestContext);
+        if (logoutContext == null || logoutContext.getIdPSessions().isEmpty()) {
             log.debug("{} No LogoutContext or IdPSessions found, nothing to do", getLogPrefix());
             return false;
         }
@@ -151,10 +151,8 @@ public class DestroySessions extends AbstractProfileAction {
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
-        final LogoutContext lc = logoutContext;
-        assert lc != null;
         SessionContext sc = sessionContext;
-        for (final IdPSession session : lc.getIdPSessions()) {
+        for (final IdPSession session : logoutContext.getIdPSessions()) {
             assert session!= null;
             final IdPSession idpSession = sc != null ? sc.getIdPSession() : null;
             log.debug("{} Attempting destruction of session {}", getLogPrefix(), session.getId());
@@ -176,7 +174,7 @@ public class DestroySessions extends AbstractProfileAction {
             }
         }
         
-        lc.getIdPSessions().clear();
+        logoutContext.getIdPSessions().clear();
     }
     
 }
\ No newline at end of file
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DetectIdentitySwitch.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DetectIdentitySwitch.java
index c60c38595..7ce4a6fa9 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DetectIdentitySwitch.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/DetectIdentitySwitch.java
@@ -20,14 +20,12 @@ package net.shibboleth.idp.session.impl;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.AuthenticationResult;
@@ -39,9 +37,11 @@ import net.shibboleth.idp.session.SessionException;
 import net.shibboleth.idp.session.SessionManager;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 
 
 /**
@@ -76,10 +76,10 @@ public class DetectIdentitySwitch extends AbstractAuthenticationAction {
     @Nonnull private Function<ProfileRequestContext,SubjectCanonicalizationContext> c14nContextLookupStrategy;
     
     /** SessionContext to operate on. */
-    @Nullable private SessionContext sessionCtx;
+    @NonnullBeforeExec private SessionContext sessionCtx;
     
     /** A newly established principal name to check. */
-    @Nullable private String newPrincipalName;
+    @NonnullBeforeExec private String newPrincipalName;
     
     /** Constructor. */
     public DetectIdentitySwitch() {
@@ -161,10 +161,7 @@ public class DetectIdentitySwitch extends AbstractAuthenticationAction {
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        // Nullability checked in pre;
-        final SessionContext ctx =  sessionCtx;
-        assert ctx != null;
-        final IdPSession idpSession = ctx.getIdPSession();
+        final IdPSession idpSession = sessionCtx.getIdPSession();
         assert idpSession != null;
         if (idpSession.getPrincipalName().equals(newPrincipalName)) {
             log.debug("{} Identities from session and new authentication result match, nothing to do", getLogPrefix());
@@ -185,7 +182,7 @@ public class DetectIdentitySwitch extends AbstractAuthenticationAction {
         }
         
         // Establish context state as if the original session didn't exist.
-        ctx.setIdPSession(null);
+        sessionCtx.setIdPSession(null);
         authenticationContext.setActiveResults(CollectionSupport.<AuthenticationResult>emptyList());
         
         ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.IDENTITY_SWITCH);
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ExtractActiveAuthenticationResults.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ExtractActiveAuthenticationResults.java
index 39dcbcfe4..adcaf06d8 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ExtractActiveAuthenticationResults.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ExtractActiveAuthenticationResults.java
@@ -24,7 +24,6 @@ import java.util.List;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -36,6 +35,7 @@ import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.context.SessionContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -65,7 +65,7 @@ public class ExtractActiveAuthenticationResults extends AbstractAuthenticationAc
     @Nonnull private Function<ProfileRequestContext,SessionContext> sessionContextLookupStrategy;
     
     /** Session to copy results from. */
-    @Nullable private IdPSession session;
+    @NonnullBeforeExec private IdPSession session;
     
     /** Constructor. */
     public ExtractActiveAuthenticationResults() {
@@ -105,17 +105,15 @@ public class ExtractActiveAuthenticationResults extends AbstractAuthenticationAc
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        final IdPSession theSession = session;
-        assert theSession != null;
         if (authenticationContext.getHintedName() == null) {
-            authenticationContext.setHintedName(theSession.getPrincipalName());
+            authenticationContext.setHintedName(session.getPrincipalName());
         }
         
         final Instant now = Instant.now();
         final Duration maxAge = authenticationContext.getMaxAge();
         
         final List<AuthenticationResult> actives = new ArrayList<>();
-        for (final AuthenticationResult result : theSession.getAuthenticationResults()) {
+        for (final AuthenticationResult result : session.getAuthenticationResults()) {
             final AuthenticationFlowDescriptor descriptor =
                     authenticationContext.getPotentialFlows().get(result.getAuthenticationFlowId());
             if (descriptor == null) {
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateLogoutPropagationContext.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateLogoutPropagationContext.java
index c66b7683c..dd658f928 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateLogoutPropagationContext.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateLogoutPropagationContext.java
@@ -40,6 +40,7 @@ import net.shibboleth.idp.session.SPSessionSerializerRegistry;
 import net.shibboleth.idp.session.context.LogoutContext;
 import net.shibboleth.idp.session.context.LogoutPropagationContext;
 import net.shibboleth.idp.session.context.LogoutPropagationContext.Result;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.security.DataSealer;
@@ -88,7 +89,7 @@ public class PopulateLogoutPropagationContext extends AbstractProfileAction {
     @Nullable private Function<ProfileRequestContext,SPSession> sessionLookupStrategy;
     
     /** {@link SPSession} to operate on. */
-    @Nullable private SPSession session;
+    @NonnullBeforeExec private SPSession session;
 
     /** The value used to look up a session by reference. */
     @Nullable private String sessionKey;
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateMultiRPContextFromLogoutContext.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateMultiRPContextFromLogoutContext.java
index 73bda42c9..6dcd110df 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateMultiRPContextFromLogoutContext.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateMultiRPContextFromLogoutContext.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.session.impl;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 import javax.xml.namespace.QName;
 
 import org.opensaml.core.criterion.EntityIdCriterion;
@@ -34,7 +33,6 @@ import org.opensaml.saml.saml2.metadata.EntityDescriptor;
 import org.opensaml.saml.saml2.metadata.RoleDescriptor;
 import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
 import org.slf4j.Logger;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.context.MultiRelyingPartyContext;
@@ -42,9 +40,11 @@ import net.shibboleth.idp.session.SPSession;
 import net.shibboleth.idp.session.context.LogoutContext;
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
 
@@ -77,7 +77,7 @@ public class PopulateMultiRPContextFromLogoutContext extends AbstractProfileActi
     @Nonnull private QName role; 
     
     /** {@link LogoutContext} to process. */
-    @Nullable private LogoutContext logoutCtx;
+    @NonnullBeforeExec private LogoutContext logoutCtx;
     
     /** Constructor. */
     public PopulateMultiRPContextFromLogoutContext() {
@@ -148,12 +148,10 @@ public class PopulateMultiRPContextFromLogoutContext extends AbstractProfileActi
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         checkComponentActive();
         
-        final LogoutContext lCtx = logoutCtx;
-        assert lCtx != null;
         final MultiRelyingPartyContext multiCtx = new MultiRelyingPartyContext();
         profileRequestContext.addSubcontext(multiCtx, true);
         
-        for (final String relyingPartyId : lCtx.getSessionMap().keySet()) {
+        for (final String relyingPartyId : logoutCtx.getSessionMap().keySet()) {
             assert relyingPartyId != null;
             final RelyingPartyContext rpCtx = new RelyingPartyContext();
             rpCtx.setRelyingPartyId(relyingPartyId);
@@ -166,7 +164,7 @@ public class PopulateMultiRPContextFromLogoutContext extends AbstractProfileActi
             final EntityRoleCriterion roleCriterion = new EntityRoleCriterion(role);
             
             ProtocolCriterion protocolCriterion = null;
-            final SPSession spSession = lCtx.getSessions(relyingPartyId).iterator().next();
+            final SPSession spSession = logoutCtx.getSessions(relyingPartyId).iterator().next();
             final String protocol = spSession.getProtocol();
             if (protocol != null) {
                 protocolCriterion = new ProtocolCriterion(protocol);
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
index 5df7b05e4..21a75e1f0 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
@@ -649,8 +649,10 @@ public class StorageBackedIdPSession extends AbstractIdPSession {
             }
             
             // Deserializer starting past the colon delimiter.
+            final String recordValue =record.getValue().substring(pos + 1);
+            assert recordValue!=null;
             return spSessionSerializer.deserialize(
-                    record.getVersion(), getId(), key, record.getValue().substring(pos + 1), record.getExpiration());
+                    record.getVersion(), getId(), key, recordValue, record.getExpiration());
             
         } catch (final IOException e) {
             log.error("IOException loading SPSession for service {} from storage: {}", serviceId, e.getMessage());
@@ -677,6 +679,7 @@ public class StorageBackedIdPSession extends AbstractIdPSession {
         // Look up the serializer instance for that class type.
         final Class<? extends SPSession> claz = session.getClass();
         assert claz != null;
+        @SuppressWarnings("unchecked")
         final StorageSerializer<SPSession> spSessionSerializer =
                 (StorageSerializer<SPSession>) registry.lookup(claz);
         if (spSessionSerializer == null) {
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
index 6b0c380b8..c7874f5ea 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
@@ -97,7 +97,9 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
             @Nullable final StorageBackedIdPSession target) {
         sessionManager = Constraint.isNotNull(manager, "SessionManager cannot be null");
         targetObject = target;
-        jsonProvider = JsonProvider.provider();
+        final JsonProvider prov = JsonProvider.provider();;
+        assert prov!=null;
+        jsonProvider = prov;
     }
 
 // Checkstyle: CyclomaticComplexity OFF
@@ -148,8 +150,9 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
             }
 
             gen.writeEnd().close();
-
-            return sink.toString();
+            final String val = sink.toString();
+            assert val != null;
+            return val;
         } catch (final JsonException e) {
             log.error("Exception while serializing IdPSession: {}", e.getMessage());
             throw new IOException("Exception while serializing IdPSession", e);
@@ -181,22 +184,31 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
                 final Instant creation =
                         Instant.ofEpochMilli(obj.getJsonNumber(CREATION_INSTANT_FIELD).longValueExact());
                 final String principalName = obj.getString(PRINCIPAL_NAME_FIELD);
+                assert principalName!=null && creation != null;
                 objectToPopulate = new StorageBackedIdPSession(sessionManager, context, principalName, creation);
             }
 
             // Populate fields in-place, bypassing any storage interactions.
             objectToPopulate.setVersion(version);
-            objectToPopulate.doSetLastActivityInstant(
+            final Instant lastActivityInstant =
                     Instant.ofEpochMilli(expiration).minus(sessionManager.getSessionTimeout()).minus(
-                            sessionManager.getSessionSlop()));
+                            sessionManager.getSessionSlop());
+            assert lastActivityInstant!=null;
+            objectToPopulate.doSetLastActivityInstant(lastActivityInstant);
             if (obj.containsKey(IPV4_ADDRESS_FIELD)) {
-                objectToPopulate.doBindToAddress(obj.getString(IPV4_ADDRESS_FIELD));
+                final String addr = obj.getString(IPV4_ADDRESS_FIELD);
+                assert addr != null;
+                objectToPopulate.doBindToAddress(addr);
             }
             if (obj.containsKey(IPV6_ADDRESS_FIELD)) {
-                objectToPopulate.doBindToAddress(obj.getString(IPV6_ADDRESS_FIELD));
+                final String addr = obj.getString(IPV6_ADDRESS_FIELD);
+                assert addr != null;
+                objectToPopulate.doBindToAddress(addr);
             }
             if (obj.containsKey(UNK_ADDRESS_FIELD)) {
-                objectToPopulate.doBindToAddress(obj.getString(UNK_ADDRESS_FIELD));
+                final String addr = obj.getString(UNK_ADDRESS_FIELD);
+                assert addr != null;
+                objectToPopulate.doBindToAddress(addr);
             }
 
             objectToPopulate.getAuthenticationResultMap().clear();
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedSessionManager.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedSessionManager.java
index 8d9ae813b..d5868598a 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedSessionManager.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedSessionManager.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.session.impl;
 import java.io.IOException;
 import java.time.Duration;
 import java.time.Instant;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -35,13 +34,10 @@ import org.opensaml.storage.StorageSerializer;
 import org.opensaml.storage.StorageService;
 import org.opensaml.storage.VersionMismatchException;
 import org.slf4j.Logger;
-import net.shibboleth.shared.primitive.LoggerFactory;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
-import jakarta.servlet.http.Cookie;
-import jakarta.servlet.http.HttpServletRequest;
 import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.SPSession;
@@ -60,6 +56,7 @@ import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponen
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.net.CookieManager;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.NonnullSupplier;
 import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.shared.resolver.CriteriaSet;
@@ -67,6 +64,9 @@ import net.shibboleth.shared.resolver.ResolverException;
 import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.shared.servlet.HttpServletSupport;
 
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+
 /**
  * Implementation of {@link SessionManager} and {@link SessionResolver} interfaces that relies on a
  * {@link StorageService} for persistence and lifecycle management of data.
@@ -170,8 +170,11 @@ public class StorageBackedSessionManager extends AbstractIdentifiableInitializab
      * 
      */
     public StorageBackedSessionManager() {
-        sessionTimeout = Duration.ofHours(1);
-        sessionSlop = Duration.ZERO;
+        final Duration oneHour = Duration.ofHours(1);
+        final Duration zeroDuration = Duration.ZERO;
+        assert oneHour!=null && zeroDuration!= null;
+        sessionTimeout = oneHour;
+        sessionSlop = zeroDuration;
         serializer = new StorageBackedIdPSessionSerializer(this, null);
         flowDescriptorMap = new HashMap<>();
         consistentAddressCondition =
@@ -516,8 +519,10 @@ public class StorageBackedSessionManager extends AbstractIdentifiableInitializab
             throw new SessionException("Session IDs are too large for StorageService, check configuration");
         }
 
+        final Instant now = Instant.now();
+        assert now != null;
         final StorageBackedIdPSession newSession =
-                new StorageBackedIdPSession(this, sessionId, principalName, Instant.now());
+                new StorageBackedIdPSession(this, sessionId, principalName, now);
         newSession.doBindToAddress(remoteAddr);
 
         try {
@@ -889,8 +894,9 @@ public class StorageBackedSessionManager extends AbstractIdentifiableInitializab
         } catch (final VersionMismatchException e) {
             log.debug("Ignoring version mismatch while updating secondary index");
         }
-
-        return builder.build();
+        final Iterable<IdPSession> result = builder.build();
+        assert result != null;
+        return result;
     }
     
     /**
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResult.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResult.java
index 1e6487e35..7ebcd6884 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResult.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResult.java
@@ -39,6 +39,7 @@ import net.shibboleth.idp.session.SessionException;
 import net.shibboleth.idp.session.SessionManager;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -80,7 +81,7 @@ public class UpdateSessionWithAuthenticationResult extends AbstractAuthenticatio
     @Nonnull private Function<ProfileRequestContext,SubjectContext> subjectContextLookupStrategy;
     
     /** Existing or newly created SessionContext. */
-    @Nullable private SessionContext sessionCtx;
+    @NonnullBeforeExec private SessionContext sessionCtx;
 
     /** Existing SubjectContext. */
     @Nullable private SubjectContext subjectCtx;
@@ -150,7 +151,6 @@ public class UpdateSessionWithAuthenticationResult extends AbstractAuthenticatio
             }
             
             // We can only do work if a session exists or a non-empty SubjectContext exists.
-            assert sessionCtx != null;
             return sessionCtx.getIdPSession() != null || (subjectCtx != null && subjectCtx.getPrincipalName() != null);
         }
         
@@ -161,10 +161,8 @@ public class UpdateSessionWithAuthenticationResult extends AbstractAuthenticatio
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
-        final SessionContext sc = sessionCtx;
-        assert sc != null;;
 
-        final IdPSession session = sc.getIdPSession();
+        final IdPSession session = sessionCtx.getIdPSession();
         if (session != null) {
             try {
                 updateIdPSession(authenticationContext, session);
@@ -222,18 +220,17 @@ public class UpdateSessionWithAuthenticationResult extends AbstractAuthenticatio
     private void createIdPSession(@Nonnull final AuthenticationContext authenticationContext)
             throws SessionException {
 
-        final SessionContext sc = sessionCtx;
         final SubjectContext sbc = subjectCtx;
-        assert sbc != null && sc != null;;
+        assert sbc != null && isPreExecuteCalled();
         final String principalName = sbc.getPrincipalName();
         assert principalName != null;
         log.debug("{} Creating new session for principal {}", getLogPrefix(), principalName);
         
-        sc.setIdPSession(sessionManager.createSession(principalName));
+        sessionCtx.setIdPSession(sessionManager.createSession(principalName));
         if (authenticationContext.isResultCacheable()) {
             final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
             assert ar != null;
-            final IdPSession idPSession = sc.getIdPSession();
+            final IdPSession idPSession = sessionCtx.getIdPSession();
             assert idPSession != null;
             idPSession.addAuthenticationResult(ar);
         }
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSession.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSession.java
index 3bbf0b055..5c2a5e847 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSession.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSession.java
@@ -20,14 +20,13 @@ package net.shibboleth.idp.session.impl;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
-import net.shibboleth.shared.primitive.LoggerFactory;
+
 import com.google.common.base.Predicates;
 
 import net.shibboleth.idp.profile.AbstractProfileAction;
@@ -39,6 +38,7 @@ import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * An action that establishes a record of an {@link SPSession} in an existing {@link IdPSession} for the client.
@@ -71,7 +71,7 @@ public class UpdateSessionWithSPSession extends AbstractProfileAction {
     @Nonnull private Function<ProfileRequestContext,SessionContext> sessionContextLookupStrategy;
     
     /** Existing or newly created SessionContext. */
-    @Nullable private SessionContext sessionCtx;
+    @NonnullAfterInit private SessionContext sessionCtx;
     
     /** Constructor. */
     public UpdateSessionWithSPSession() {
@@ -147,7 +147,6 @@ public class UpdateSessionWithSPSession extends AbstractProfileAction {
             log.debug("{} SPSession was not returned, nothing to do", getLogPrefix());
             return;
         }
-        assert sessionCtx != null;
         final IdPSession idpSession = sessionCtx.getIdPSession();
         assert idpSession != null;
         try {
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/BasicSPSessionSerializerTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/BasicSPSessionSerializerTest.java
index 1e36fd037..2389c1546 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/BasicSPSessionSerializerTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/BasicSPSessionSerializerTest.java
@@ -33,6 +33,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /** {@link BasicSPSessionSerializer} unit test. */
+ at SuppressWarnings("null")
 public class BasicSPSessionSerializerTest {
 
     private static final String DATAPATH = "/net/shibboleth/idp/session/impl/";
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DestroySessionsTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DestroySessionsTest.java
index 67523bfa9..6e4c8ffbf 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DestroySessionsTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DestroySessionsTest.java
@@ -69,6 +69,7 @@ public class DestroySessionsTest extends SessionManagerBaseTestCase {
     }
     
     /** {@inheritDoc} */
+    @SuppressWarnings("null")
     @Override
     protected void adjustProperties() throws ComponentInitializationException {
         sessionManager.setTrackSPSessions(true);
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DetectIdentitySwitchTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DetectIdentitySwitchTest.java
index 7fc4a541b..da1f68c35 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DetectIdentitySwitchTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/DetectIdentitySwitchTest.java
@@ -42,6 +42,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /** {@link DetectIdentitySwitch} unit test. */
+ at SuppressWarnings("null")
 public class DetectIdentitySwitchTest extends SessionManagerBaseTestCase {
     
     private RequestContext src;
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/ProcessLogoutTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/ProcessLogoutTest.java
index 2d3c2d905..dfd7d5848 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/ProcessLogoutTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/ProcessLogoutTest.java
@@ -53,7 +53,7 @@ import net.shibboleth.shared.servlet.impl.ThreadLocalHttpServletRequestSupplier;
 import net.shibboleth.shared.servlet.impl.ThreadLocalHttpServletResponseSupplier;
 
 /** {@link ProcessLogout} unit test. */
- at SuppressWarnings("javadoc")
+ at SuppressWarnings({"javadoc", "null"})
 public class ProcessLogoutTest extends SessionManagerBaseTestCase {
     
     private RequestContext src;
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/SessionManagerBaseTestCase.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/SessionManagerBaseTestCase.java
index f427282b7..644c22dea 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/SessionManagerBaseTestCase.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/SessionManagerBaseTestCase.java
@@ -39,6 +39,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 
 /** Base class for tests requiring a SessionManager component to be set up. */
+ at SuppressWarnings({"null"})
 public class SessionManagerBaseTestCase extends OpenSAMLInitBaseTestCase {
     
     protected MemoryStorageService storageService;
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
index 754946b8e..ee8259db0 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
@@ -41,7 +41,7 @@ import net.shibboleth.shared.servlet.impl.ThreadLocalHttpServletRequestSupplier;
 import net.shibboleth.shared.servlet.impl.ThreadLocalHttpServletResponseSupplier;
 
 /** {@link StorageBackedIdPSessionSerializer} unit test. */
- at SuppressWarnings("javadoc")
+ at SuppressWarnings({"null"})
 public class StorageBackedIdPSessionSerializerTest {
 
     private static final String DATAPATH = "/net/shibboleth/idp/session/impl/";
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
index 1604c78d0..92fb23a0c 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
@@ -62,6 +62,7 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 /** {@link StorageBackedSessionManager} unit test. */
+ at SuppressWarnings({"javadoc", "null"})
 public class StorageBackedSessionManagerTest extends SessionManagerBaseTestCase {
 
     private static final Duration sessionSlop = Duration.ofMinutes(5);
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResultTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResultTest.java
index 76ea47c12..9bc634042 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResultTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithAuthenticationResultTest.java
@@ -18,7 +18,17 @@
 package net.shibboleth.idp.session.impl;
 
 import java.time.Instant;
-import java.util.Arrays;
+
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.storage.StorageSerializer;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.webflow.execution.Event;
+import org.springframework.webflow.execution.RequestContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
 
 import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.AuthenticationResult;
@@ -39,17 +49,6 @@ import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
 import net.shibboleth.shared.servlet.impl.HttpServletRequestResponseContext;
 
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.storage.StorageSerializer;
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.mock.web.MockHttpServletResponse;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
 /** {@link UpdateSessionWithAuthenticationResult} unit test. */
 public class UpdateSessionWithAuthenticationResultTest extends SessionManagerBaseTestCase {
     
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSessionTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSessionTest.java
index aa0717eb8..2efaac1b7 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSessionTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/UpdateSessionWithSPSessionTest.java
@@ -63,6 +63,7 @@ public class UpdateSessionWithSPSessionTest extends SessionManagerBaseTestCase {
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("null")
     @Override
     protected void adjustProperties() throws ComponentInitializationException {
         sessionManager.setTrackSPSessions(true);
@@ -137,6 +138,7 @@ public class UpdateSessionWithSPSessionTest extends SessionManagerBaseTestCase {
         }
         
         /** {@inheritDoc} */
+        @SuppressWarnings({"null"})
         public SPSession apply(ProfileRequestContext input) {
             return new BasicSPSession("https://sp.example.org", creationTime, expirationTime);
         }

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


More information about the commits mailing list