[java-identity-provider] branch master updated: IDP-1421 - CAS actions should avoid raising runtime exceptions

Scott Cantor cantor.2 at osu.edu
Mon Jul 1 11:26:03 EDT 2019


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

scantor pushed a commit to branch master
in repository java-identity-provider.

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

The following commit(s) were added to refs/heads/master by this push:
       new  683be3a   IDP-1421 - CAS actions should avoid raising runtime exceptions
683be3a is described below

commit 683be3aa3f814728acc56d4fe0a337f7a0acd113
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 1 11:25:56 2019 -0400

    IDP-1421 - CAS actions should avoid raising runtime exceptions
    
    https://issues.shibboleth.net/jira/browse/IDP-1421
    
    Converted all beans into prototypes.
    Switched where possible to non-Spring doExecute calls.
---
 .../idp/cas/config/impl/ConfigLookupFunction.java  |   2 +-
 .../cas/flow/impl/AbstractCASProtocolAction.java   |  74 ++++++++---
 .../impl/AbstractOutgoingSamlMessageAction.java    |  32 +++--
 .../impl/BuildAuthenticationContextAction.java     |  43 +++++--
 .../idp/cas/flow/impl/BuildProxyChainAction.java   |  59 ++++++---
 .../flow/impl/BuildRelyingPartyContextAction.java  |  64 +++++++---
 .../flow/impl/BuildSAMLMetadataContextAction.java  |  47 +++++--
 .../BuildSamlValidationFailureMessageAction.java   |  12 +-
 .../BuildSamlValidationSuccessMessageAction.java   |  22 ++--
 .../flow/impl/CheckProxyAuthorizationAction.java   |  40 ++++--
 .../idp/cas/flow/impl/GrantProxyTicketAction.java  | 116 ++++++++++++------
 .../cas/flow/impl/GrantServiceTicketAction.java    | 136 ++++++++++++++-------
 .../idp/cas/flow/impl/InitializeLoginAction.java   |  17 ++-
 .../idp/cas/flow/impl/InitializeProxyAction.java   |  34 +++---
 .../cas/flow/impl/InitializeValidateAction.java    |  19 ++-
 .../cas/flow/impl/PopulateProtocolErrorAction.java |  38 ++++--
 .../PrepareTicketValidationResponseAction.java     |  63 +++++++---
 .../cas/flow/impl/ProcessSamlMessageAction.java    |  25 ++--
 .../flow/impl/PublishProtocolMessageAction.java    |  28 +++--
 .../impl/UpdateIdPSessionWithSPSessionAction.java  |  58 ++++++---
 .../cas/flow/impl/ValidateProxyCallbackAction.java |  95 +++++++++-----
 .../idp/cas/flow/impl/ValidateRenewAction.java     |  50 +++++---
 .../idp/cas/flow/impl/ValidateTicketAction.java    | 101 ++++++++++-----
 .../cas/flow/impl/WriteValidateResponseAction.java |  45 ++++---
 .../impl/BuildRelyingPartyContextActionTest.java   |   8 +-
 .../system/flows/cas/cas-abstract-beans.xml        |  35 +++---
 .../system/flows/cas/login/login-beans.xml         |  25 ++--
 .../system/flows/cas/proxy/proxy-beans.xml         |   7 +-
 .../cas/proxyValidate/proxyValidate-beans.xml      |   2 +-
 .../flows/cas/samlValidate/samlValidate-beans.xml  |  24 ++--
 .../system/flows/cas/validate-abstract-beans.xml   |  17 +--
 .../system/flows/cas/validate/validate-beans.xml   |  14 ++-
 32 files changed, 889 insertions(+), 463 deletions(-)

diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ConfigLookupFunction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ConfigLookupFunction.java
index 6ff3869..256cba5 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ConfigLookupFunction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ConfigLookupFunction.java
@@ -50,7 +50,7 @@ public class ConfigLookupFunction<T extends AbstractProtocolConfiguration>
     /** {@inheritDoc} */
     @Nullable public T apply(@Nullable final ProfileRequestContext profileRequestContext) {
         if (profileRequestContext != null) {
-            final RelyingPartyContext rpContext = profileRequestContext.getSubcontext(RelyingPartyContext.class, false);
+            final RelyingPartyContext rpContext = profileRequestContext.getSubcontext(RelyingPartyContext.class);
             if (rpContext != null && configClass.isInstance(rpContext.getProfileConfig())) {
                 return configClass.cast(rpContext.getProfileConfig());
             }
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractCASProtocolAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractCASProtocolAction.java
index d5aaaff..45be3fc 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractCASProtocolAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractCASProtocolAction.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.cas.flow.impl;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.ProtocolContext;
 import net.shibboleth.idp.cas.service.Service;
@@ -29,7 +30,13 @@ import net.shibboleth.idp.cas.ticket.TicketContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.webflow.execution.Event;
+import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Base class for CAS protocol actions.
@@ -41,7 +48,11 @@ import org.opensaml.profile.context.ProfileRequestContext;
  */
 public abstract class AbstractCASProtocolAction<RequestType, ResponseType> extends AbstractProfileAction {
 
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractCASProtocolAction.class);
+    
     /** Looks up a CAS protocol context from IdP profile request context. */
+    @Nonnull
     private final Function<ProfileRequestContext,ProtocolContext<RequestType,ResponseType>> protocolLookupFunction;
 
     /** Constructor. */
@@ -54,12 +65,14 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @return CAS request
+     * 
+     * @throws EventException to propagate an event 
      */
-    @Nonnull
-    protected RequestType getCASRequest(final ProfileRequestContext prc) {
+    @Nonnull protected RequestType getCASRequest(@Nullable final ProfileRequestContext prc) throws EventException {
         final RequestType request = getProtocolContext(prc).getRequest();
         if (request == null) {
-            throw new IllegalStateException("CAS protocol request not found");
+            log.error("{} CAS protocol request not found", getLogPrefix());
+            throw new EventException(EventIds.INVALID_MSG_CTX);
         }
         return request;
     }
@@ -69,8 +82,11 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @param request CAS request
+     * 
+     * @throws EventException to propagate an event 
      */
-    protected void setCASRequest(final ProfileRequestContext prc, @Nonnull final RequestType request) {
+    protected void setCASRequest(@Nullable final ProfileRequestContext prc, @Nonnull final RequestType request)
+            throws EventException {
         getProtocolContext(prc).setRequest(Constraint.isNotNull(request, "CAS request cannot be null"));
     }
 
@@ -79,12 +95,14 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @return CAS response
+     * 
+     * @throws EventException to propagate an event
      */
-    @Nonnull
-    protected ResponseType getCASResponse(final ProfileRequestContext prc) {
+    @Nonnull protected ResponseType getCASResponse(@Nullable final ProfileRequestContext prc) throws EventException {
         final ResponseType response = getProtocolContext(prc).getResponse();
         if (response == null) {
-            throw new IllegalStateException("CAS protocol response not found");
+            log.error("{} CAS protocol response not found", getLogPrefix());
+            throw new EventException(EventIds.INVALID_MSG_CTX);
         }
         return response;
     }
@@ -94,8 +112,11 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @param response CAS response
+     * 
+     * @throws EventException to propagate an event 
      */
-    protected void setCASResponse(final ProfileRequestContext prc, @Nonnull final ResponseType response) {
+    protected void setCASResponse(@Nullable final ProfileRequestContext prc, @Nonnull final ResponseType response)
+            throws EventException {
         getProtocolContext(prc).setResponse(Constraint.isNotNull(response, "CAS response cannot be null"));
     }
 
@@ -104,11 +125,14 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @return CAS ticket
+     * 
+     * @throws EventException to propagate an event 
      */
-    @Nonnull protected Ticket getCASTicket(final ProfileRequestContext prc) {
+    @Nonnull protected Ticket getCASTicket(final ProfileRequestContext prc) throws EventException {
         final TicketContext context = getProtocolContext(prc).getSubcontext(TicketContext.class);
         if (context == null || context.getTicket() == null) {
-            throw new IllegalStateException("CAS protocol ticket not found");
+            log.error("{} CAS protocol ticket not found", getLogPrefix());
+            throw new EventException(EventIds.INVALID_MSG_CTX);
         }
         return context.getTicket();
     }
@@ -118,8 +142,11 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @param ticket CAS ticket
+     * 
+     * @throws EventException to propagate an event 
      */
-    protected void setCASTicket(final ProfileRequestContext prc, @Nonnull final Ticket ticket) {
+    protected void setCASTicket(@Nullable final ProfileRequestContext prc, @Nonnull final Ticket ticket)
+            throws EventException {
         getProtocolContext(prc).addSubcontext(
                 new TicketContext(Constraint.isNotNull(ticket, "CAS ticket cannot be null")));
     }
@@ -129,11 +156,14 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @return CAS service
+     * 
+     * @throws EventException to propagate an event
      */
-    @Nonnull protected Service getCASService(final ProfileRequestContext prc) {
+    @Nonnull protected Service getCASService(@Nullable final ProfileRequestContext prc) throws EventException {
         final ServiceContext context = getProtocolContext(prc).getSubcontext(ServiceContext.class);
         if (context == null || context.getService() == null) {
-            throw new IllegalStateException("CAS protocol service not found");
+            log.error("{} CAS protocol service not found", getLogPrefix());
+            throw new EventException(EventIds.INVALID_MSG_CTX);
         }
         return context.getService();
     }
@@ -143,8 +173,11 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @param service CAS service
+     * 
+     * @throws EventException to propagate an event
      */
-    protected void setCASService(final ProfileRequestContext prc, @Nonnull final Service service) {
+    protected void setCASService(@Nullable final ProfileRequestContext prc, @Nonnull final Service service)
+            throws EventException {
         getProtocolContext(prc).addSubcontext(
                 new ServiceContext(Constraint.isNotNull(service, "CAS service cannot be null")));
     }
@@ -154,12 +187,17 @@ public abstract class AbstractCASProtocolAction<RequestType, ResponseType> exten
      * 
      * @param prc profile request context
      * @return CAS protocol context
+     * 
+     * @throws EventException to propagate an event 
      */
-    @Nonnull protected ProtocolContext<RequestType, ResponseType> getProtocolContext(final ProfileRequestContext prc) {
-        final ProtocolContext<RequestType, ResponseType> casCtx = protocolLookupFunction.apply(prc);
+    @Nonnull protected ProtocolContext<RequestType,ResponseType> getProtocolContext(
+            @Nullable final ProfileRequestContext prc) throws EventException {
+        final ProtocolContext<RequestType,ResponseType> casCtx = protocolLookupFunction.apply(prc);
         if (casCtx == null) {
-            throw new IllegalArgumentException("CAS ProtocolContext not found in ProfileRequestContext");
+            log.error("{} CAS ProtocolContext not found in ProfileRequestContext", getLogPrefix());
+            throw new EventException(EventIds.INVALID_PROFILE_CTX);
         }
         return casCtx;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractOutgoingSamlMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractOutgoingSamlMessageAction.java
index 78977ae..2933395 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractOutgoingSamlMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/AbstractOutgoingSamlMessageAction.java
@@ -23,7 +23,6 @@ import javax.xml.namespace.QName;
 import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
-import net.shibboleth.idp.profile.ActionSupport;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -33,6 +32,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -43,8 +44,6 @@ import org.opensaml.soap.messaging.context.SOAP11Context;
 import org.opensaml.soap.soap11.Body;
 import org.opensaml.soap.soap11.Envelope;
 import org.opensaml.soap.util.SOAPConstants;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Base class for all actions that build SAML {@link Response} messages for output.
@@ -90,8 +89,6 @@ public abstract class AbstractOutgoingSamlMessageAction extends
         }
     }
 
-
-
     /**
      * Build the SAML object.
      * 
@@ -108,15 +105,14 @@ public abstract class AbstractOutgoingSamlMessageAction extends
     }
 
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
         final MessageContext<SAMLObject> msgContext = new MessageContext<>();
         try {
-            msgContext.setMessage(buildSamlResponse(springRequestContext, profileRequestContext));
-        } catch (final IllegalStateException e) {
-            return ProtocolError.IllegalState.event(this);
+            msgContext.setMessage(buildSamlResponse(profileRequestContext));
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.IllegalState.event(this));
+            return;
         }
         final SAMLBindingContext bindingContext = new SAMLBindingContext();
         bindingContext.setBindingUri(outgoingBinding.getId());
@@ -131,18 +127,18 @@ public abstract class AbstractOutgoingSamlMessageAction extends
         msgContext.addSubcontext(soapCtx);
 
         profileRequestContext.setOutboundMessageContext(msgContext);
-
-        return ActionSupport.buildProceedEvent(this);
     }
 
     /**
      * Build the SAML response.
      * 
-     * @param springRequestContext Spring request context
      * @param profileRequestContext profile request context
+     * 
      * @return SAML response
+     * 
+     * @throws EventException to signal an event
      */
-    protected abstract Response buildSamlResponse(
-            @Nonnull RequestContext springRequestContext,
-            @Nonnull ProfileRequestContext<SAMLObject, SAMLObject> profileRequestContext);
-}
+    @Nonnull protected abstract Response buildSamlResponse(
+            @Nonnull final ProfileRequestContext<SAMLObject,SAMLObject> profileRequestContext) throws EventException;
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
index 9a85c64..8028677 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
@@ -18,6 +18,7 @@
 package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
@@ -25,29 +26,50 @@ import net.shibboleth.idp.cas.config.impl.LoginConfiguration;
 import net.shibboleth.idp.cas.protocol.ServiceTicketRequest;
 import net.shibboleth.idp.cas.protocol.ServiceTicketResponse;
 
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Builds an authentication context from an incoming {@link ServiceTicketRequest} message.
  *
  * @author Marvin S. Addison
  */
-public class BuildAuthenticationContextAction extends
-        AbstractCASProtocolAction<ServiceTicketRequest, ServiceTicketResponse> {
+public class BuildAuthenticationContextAction
+        extends AbstractCASProtocolAction<ServiceTicketRequest,ServiceTicketResponse> {
 
     /** Profile configuration lookup function. */
-    private final ConfigLookupFunction<LoginConfiguration> configLookupFunction =
-            new ConfigLookupFunction<>(LoginConfiguration.class);
+    @Nonnull private final ConfigLookupFunction<LoginConfiguration> configLookupFunction;
 
-    @Nonnull
+    /** Stores off CAS request. */
+    @Nullable private ServiceTicketRequest request;
+    
+    /** Constructor. */
+    public BuildAuthenticationContextAction() {
+        configLookupFunction = new ConfigLookupFunction<>(LoginConfiguration.class);
+    }
+    
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        try {
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+        
+        return true;
+    }
+    
     @Override
-    protected Event doExecute(@Nonnull final RequestContext springRequestContext,
-            @Nonnull final ProfileRequestContext profileRequestContext){
+    @Nonnull protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
         final AuthenticationContext ac = new AuthenticationContext();
-        ac.setForceAuthn(getCASRequest(profileRequestContext).isRenew());
+        ac.setForceAuthn(request.isRenew());
         ac.setIsPassive(false);
 
         if (!ac.isForceAuthn()) {
@@ -59,7 +81,6 @@ public class BuildAuthenticationContextAction extends
         
         profileRequestContext.addSubcontext(ac, true);
         profileRequestContext.setBrowserProfile(true);
-        return null;
     }
     
 }
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildProxyChainAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildProxyChainAction.java
index 975612e..3f614cf 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildProxyChainAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildProxyChainAction.java
@@ -18,6 +18,7 @@
 package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
@@ -27,11 +28,12 @@ import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.Ticket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Action that builds the chain of visited proxies for a successful proxy ticket validation event. Possible outcomes:
@@ -45,35 +47,52 @@ import org.springframework.webflow.execution.RequestContext;
  * @author Marvin S. Addison
  */
 public class BuildProxyChainAction
-        extends AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
+        extends AbstractCASProtocolAction<TicketValidationRequest,TicketValidationResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(BuildProxyChainAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(BuildProxyChainAction.class);
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx ticketServiceEx;
-
+    @Nonnull private final TicketServiceEx ticketServiceEx;
+    
+    /** Response. */
+    @Nullable private TicketValidationResponse response;
+    
+    /** Ticket. */
+    @Nullable private Ticket ticket;
 
     /**
-     * Creates a new instance.
+     * Constructor.
      *
      * @param ticketService Ticket service component.
      */
     public BuildProxyChainAction(@Nonnull final TicketServiceEx ticketService) {
         ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
     }
+    
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        try {
+            response = getCASResponse(profileRequestContext);
+            ticket = getCASTicket(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+        
+        return true;
+    }
 
-    @Nonnull
     @Override
-    protected Event doExecute(
-        final @Nonnull RequestContext springRequestContext,
-        final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        final TicketValidationResponse response = getCASResponse(profileRequestContext);
-        final Ticket ticket = getCASTicket(profileRequestContext);
         if (!(ticket instanceof ProxyTicket)) {
-            return ProtocolError.InvalidTicketType.event(this);
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.InvalidTicketType.event(this));
+            return;
         }
         final ProxyTicket pt = (ProxyTicket) ticket;
         ProxyGrantingTicket pgt;
@@ -81,13 +100,13 @@ public class BuildProxyChainAction
         do {
             pgt = ticketServiceEx.fetchProxyGrantingTicket(pgtId);
             if (pgt == null) {
-                log.debug("PGT {} not found", pgtId);
-                return ProtocolError.BrokenProxyChain.event(this);
+                log.debug("{} PGT {} not found", getLogPrefix(), pgtId);
+                ActionSupport.buildEvent(profileRequestContext, ProtocolError.BrokenProxyChain.event(this));
+                return;
             }
             response.addProxy(pgt.getService());
             pgtId = pgt.getParentId();
         } while (pgtId != null);
-
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
index 0ea94d2..3a685dd 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
@@ -28,13 +28,16 @@ import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.service.Service;
 import net.shibboleth.idp.cas.service.ServiceRegistry;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Creates the {@link RelyingPartyContext} as a child of the {@link ProfileRequestContext}. The component queries
@@ -46,16 +49,16 @@ import org.springframework.webflow.execution.RequestContext;
 public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
 
     /** Name of group to which unverified services belong. */
-    public static final String UNVERIFIED_GROUP = "unverified";
+    @Nonnull @NotEmpty public static final String UNVERIFIED_GROUP = "unverified";
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(BuildRelyingPartyContextAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(BuildRelyingPartyContextAction.class);
 
     /** List of registries to query for verified CAS services (relying parties). */
-    @Nonnull
-    @NotEmpty
-    private final List<ServiceRegistry> serviceRegistries;
-
+    @Nonnull @NonnullElements @NotEmpty private final List<ServiceRegistry> serviceRegistries;
+    
+    /** Request. */
+    @Nullable private Object request;
 
     /**
      * Creates a new instance.
@@ -65,15 +68,29 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
     public BuildRelyingPartyContextAction(@Nonnull @NotEmpty final ServiceRegistry ... registries) {
         serviceRegistries = Arrays.asList(Constraint.isNotEmpty(registries, "Service registries cannot be null"));
     }
+    
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        try {
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+        
+        return true;
+    }
+    
 
-    @Nonnull
     @Override
-    protected Event doExecute(
-        final @Nonnull RequestContext springRequestContext,
-        final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Nonnull protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
 
         final String serviceURL;
-        final Object request = getCASRequest(profileRequestContext);
+        
         if (request instanceof ServiceTicketRequest) {
             serviceURL = ((ServiceTicketRequest) request).getService();
         } else if (request instanceof ProxyTicketRequest) {
@@ -81,22 +98,30 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
         } else if (request instanceof TicketValidationRequest) {
             serviceURL = ((TicketValidationRequest) request).getService();
         } else {
-            throw new IllegalStateException("Service URL not found in flow state");
+            log.warn("{} Service URL not found in flow state", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return;
         }
+        
         Service service = query(serviceURL);
         final RelyingPartyContext rpc = new RelyingPartyContext();
         rpc.setVerified(service != null);
         rpc.setRelyingPartyId(serviceURL);
         if (service != null) {
-            log.debug("Setting up RP context for verified relying party {}", service);
+            log.debug("{} Setting up RP context for verified relying party {}", getLogPrefix(), service);
         } else {
             service = new Service(serviceURL, UNVERIFIED_GROUP, false);
-            log.debug("Setting up RP context for unverified relying party {}", service);
+            log.debug("{} Setting up RP context for unverified relying party {}", getLogPrefix(), service);
         }
-        log.debug("Relying party context created for {}", service);
+        log.debug("{} Relying party context created for {}", getLogPrefix(), service);
+        
         profileRequestContext.addSubcontext(rpc);
-        setCASService(profileRequestContext, service);
-        return null;
+        
+        try {
+            setCASService(profileRequestContext, service);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+        }
     }
 
     /**
@@ -115,6 +140,7 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
                 return service;
             }
         }
+        
         return null;
     }
     
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSAMLMetadataContextAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSAMLMetadataContextAction.java
index e42b2c5..e70095a 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSAMLMetadataContextAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSAMLMetadataContextAction.java
@@ -18,16 +18,19 @@
 package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.service.Service;
 import net.shibboleth.idp.cas.service.impl.ServiceEntityDescriptor;
+import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Builds a {@link SAMLMetadataContext} child of {@link RelyingPartyContext} to facilitate relying party selection
@@ -41,23 +44,45 @@ import org.springframework.webflow.execution.RequestContext;
  */
 public class BuildSAMLMetadataContextAction extends AbstractCASProtocolAction {
 
+    /** CAS service. */
+    @Nullable private Service service;
+    
+    /** RelyingPartyContext. */
+    @Nullable private RelyingPartyContext rpCtx;
+    
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-        final RelyingPartyContext rpCtx = profileRequestContext.getSubcontext(RelyingPartyContext.class);
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        try {
+            service = getCASService(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+        
+        rpCtx = profileRequestContext.getSubcontext(RelyingPartyContext.class);
         if (rpCtx == null) {
-            throw new IllegalStateException("RelyingPartyContext not found");
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
         }
+
+        return true;
+    }    
+    
+    @Override
+    protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
+        
         final SAMLMetadataContext mdCtx = new SAMLMetadataContext();
-        final Service service = getCASService(profileRequestContext);
         final EntityDescriptor entity = service.getEntityDescriptor() != null
                 ? service.getEntityDescriptor()
                 : new ServiceEntityDescriptor(service);
         mdCtx.setEntityDescriptor(entity);
         mdCtx.setRoleDescriptor(service.getRoleDescriptor());
+        
         rpCtx.setRelyingPartyIdContextTree(mdCtx);
-
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationFailureMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationFailureMessageAction.java
index bb242fb..ad93c12 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationFailureMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationFailureMessageAction.java
@@ -24,13 +24,14 @@ import javax.xml.namespace.QName;
 
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
+
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.saml1.core.Response;
 import org.opensaml.saml.saml1.core.Status;
 import org.opensaml.saml.saml1.core.StatusCode;
 import org.opensaml.saml.saml1.core.StatusMessage;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Creates the SAML response message for failed ticket validation at the <code>/samlValidate</code> URI.
@@ -39,11 +40,9 @@ import org.springframework.webflow.execution.RequestContext;
  */
 public class BuildSamlValidationFailureMessageAction extends AbstractOutgoingSamlMessageAction {
 
-    @Nonnull
     @Override
-    protected Response buildSamlResponse(
-            @Nonnull final RequestContext springRequestContext,
-            @Nonnull final ProfileRequestContext<SAMLObject, SAMLObject> profileRequestContext) {
+    @Nonnull protected Response buildSamlResponse(
+            @Nonnull final ProfileRequestContext<SAMLObject,SAMLObject> profileRequestContext) throws EventException {
 
         final TicketValidationRequest request = getCASRequest(profileRequestContext);
         final TicketValidationResponse validationResponse = getCASResponse(profileRequestContext);
@@ -61,4 +60,5 @@ public class BuildSamlValidationFailureMessageAction extends AbstractOutgoingSam
 
         return response;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
index cf02a88..cbcb258 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
@@ -21,10 +21,12 @@ import java.time.Instant;
 
 import javax.annotation.Nonnull;
 
+import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
 import net.shibboleth.idp.cas.ticket.Ticket;
 import net.shibboleth.idp.cas.ticket.TicketState;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
@@ -32,6 +34,7 @@ import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrate
 import org.opensaml.core.xml.XMLObjectBuilder;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.core.xml.schema.XSString;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -52,7 +55,6 @@ import org.opensaml.saml.saml1.core.Subject;
 import org.opensaml.saml.saml1.core.SubjectConfirmation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Creates the SAML response message for successful ticket validation at the <code>/samlValidate</code> URI.
@@ -80,27 +82,24 @@ public class BuildSamlValidationSuccessMessageAction extends AbstractOutgoingSam
 
 
     /**
-     * Creates a new instance with required parameters.
+     * Constructor.
      *
      * @param strategy SAML identifier generation strategy.
      * @param id IdP entity ID.
      */
-    public BuildSamlValidationSuccessMessageAction(final IdentifierGenerationStrategy strategy, final String id) {
+    public BuildSamlValidationSuccessMessageAction(@Nonnull final IdentifierGenerationStrategy strategy,
+            @Nonnull @NotEmpty final String id) {
         Constraint.isNotNull(strategy, "IdentifierGenerationStrategy cannot be null");
         identifierGenerationStrategy = strategy;
         entityID = Constraint.isNotNull(StringSupport.trimOrNull(id), "EntityID cannot be null");
         
         attrValueBuilder = XMLObjectProviderRegistrySupport.getBuilderFactory().<XSString>getBuilderOrThrow(
                 XSString.TYPE_NAME);
-
     }
 
-
-    @Nonnull
     @Override
-    protected Response buildSamlResponse(
-            @Nonnull final RequestContext springRequestContext,
-            @Nonnull final ProfileRequestContext<SAMLObject, SAMLObject> profileRequestContext) {
+    @Nonnull protected Response buildSamlResponse(
+            @Nonnull final ProfileRequestContext<SAMLObject,SAMLObject> profileRequestContext) throws EventException {
 
         final Instant now = Instant.now();
 
@@ -109,7 +108,7 @@ public class BuildSamlValidationSuccessMessageAction extends AbstractOutgoingSam
         final Ticket ticket = getCASTicket(profileRequestContext);
         final TicketState state = ticket.getTicketState();
         if (state == null) {
-            throw new IllegalStateException("TicketState cannot be null");
+            throw new EventException(ProtocolError.IllegalState.name());
         }
         log.debug("Building SAML response for {} in IdP session {}", request.getService(), state.getSessionId());
 
@@ -210,4 +209,5 @@ public class BuildSamlValidationSuccessMessageAction extends AbstractOutgoingSam
         stringValue.setValue(value);
         return stringValue;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/CheckProxyAuthorizationAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/CheckProxyAuthorizationAction.java
index 12e8776..6ca0605 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/CheckProxyAuthorizationAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/CheckProxyAuthorizationAction.java
@@ -18,15 +18,17 @@
 package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.service.Service;
 import net.shibboleth.idp.cas.service.ServiceContext;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Checks the current {@link ServiceContext} to determine whether the service/relying party is authorized to proxy.
@@ -41,18 +43,34 @@ import org.springframework.webflow.execution.RequestContext;
 public class CheckProxyAuthorizationAction extends AbstractCASProtocolAction {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(CheckProxyAuthorizationAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(CheckProxyAuthorizationAction.class);
 
+    /** CAS service. */
+    @Nullable private Service service;
+    
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        try {
+            service = getCASService(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+        
+        return true;
+    }    
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        final Service service = getCASService(profileRequestContext);
         if (!service.isAuthorizedToProxy()) {
-            log.info("{} is not authorized to proxy", service.getName());
-            return ProtocolError.ProxyNotAuthorized.event(this);
+            log.info("{} Service '{}' is not authorized to proxy", getLogPrefix(), service.getName());
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.ProxyNotAuthorized.event(this));
         }
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
index ff315f6..6c6810f 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
@@ -21,6 +21,7 @@ import java.time.Instant;
 import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import com.google.common.base.Predicates;
 import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
@@ -31,6 +32,7 @@ import net.shibboleth.idp.cas.protocol.ProxyTicketResponse;
 import net.shibboleth.idp.cas.ticket.ProxyGrantingTicket;
 import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.SessionException;
@@ -40,11 +42,13 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Generates and stores a CAS protocol proxy ticket. Possible outcomes:
@@ -59,8 +63,7 @@ import org.springframework.webflow.execution.RequestContext;
 public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicketRequest, ProxyTicketResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(GrantProxyTicketAction.class);
-
+    @Nonnull private final Logger log = LoggerFactory.getLogger(GrantProxyTicketAction.class);
 
     /** Profile configuration lookup function. */
     @Nonnull private final ConfigLookupFunction<ProxyConfiguration> configLookupFunction;
@@ -74,15 +77,26 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
     /** Whether to resolve and validate IdP session as part of granting a proxy ticket. */
     @Nonnull private Predicate<ProfileRequestContext> validateIdPSessionPredicate;
 
+    /** Profile config. */
+    @Nullable private ProxyConfiguration proxyConfig;
+    
+    /** Security config. */
+    @Nullable private SecurityConfiguration securityConfig;
+    
+    /** CAS ticket. */
+    @Nullable private ProxyGrantingTicket pgt;
+    
+    /** CAS request. */
+    @Nullable private ProxyTicketRequest request;
 
     /**
-     * Creates a new instance.
+     * Constructor.
      *
      * @param ticketService Ticket service component.
      * @param resolver session resolver
      */
-    public GrantProxyTicketAction(
-            @Nonnull final TicketServiceEx ticketService, @Nonnull final SessionResolver resolver) {
+    public GrantProxyTicketAction(@Nonnull final TicketServiceEx ticketService,
+            @Nonnull final SessionResolver resolver) {
         casTicketService = Constraint.isNotNull(ticketService, "TicketService cannot be null");
         sessionResolver = Constraint.isNotNull(resolver, "SessionResolver cannot be null");
         
@@ -106,66 +120,90 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
         validateIdPSessionPredicate = Constraint.isNotNull(predicate, "Session validation condition cannot be null");
     }
 
-    /** {@inheritDoc} */
     @Override
-    @Nonnull
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-
-        final ProxyGrantingTicket pgt = (ProxyGrantingTicket) getCASTicket(profileRequestContext);
-        if (pgt == null || pgt.getExpirationInstant().isBefore(Instant.now())) {
-            return ProtocolError.TicketExpired.event(this);
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        proxyConfig = configLookupFunction.apply(profileRequestContext);
+        if (proxyConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
         }
-        final ProxyConfiguration config = configLookupFunction.apply(profileRequestContext);
-        if (config == null) {
-            log.warn("Proxy ticket configuration undefined");
-            return ProtocolError.IllegalState.event(this);
+        
+        securityConfig = proxyConfig.getSecurityConfiguration(profileRequestContext);
+        if (securityConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
+            return false;
         }
         
-        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
-        if (securityConfiguration == null || securityConfiguration.getIdGenerator() == null) {
-            log.warn("Invalid proxy ticket configuration: SecurityConfiguration#idGenerator undefined");
-            return ProtocolError.IllegalState.event(this);
+        try {
+            request = getCASRequest(profileRequestContext);
+            pgt = (ProxyGrantingTicket) getCASTicket(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
         }
+        
+        return true;
+    }    
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        if (pgt.getExpirationInstant().isBefore(Instant.now())) {
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketExpired.event(this));
+            return;
+        }
+        
         if (validateIdPSessionPredicate.test(profileRequestContext)) {
             IdPSession session = null;
             try {
-                log.debug("Attempting to retrieve session {}", pgt.getSessionId());
+                log.debug("{} Attempting to retrieve session {}", getLogPrefix(), pgt.getSessionId());
                 session = sessionResolver.resolveSingle(new CriteriaSet(new SessionIdCriterion(pgt.getSessionId())));
             } catch (final ResolverException e) {
-                log.warn("IdPSession resolution error: {}", e);
+                log.warn("{} IdPSession resolution error: {}", getLogPrefix(), e);
             }
             boolean expired = true;
             if (session == null) {
-                log.info("IdPSession {} not found", pgt.getSessionId());
+                log.info("{} IdPSession {} not found", getLogPrefix(), pgt.getSessionId());
             } else {
                 try {
                     expired = !session.checkTimeout();
-                    log.debug("Session {} expired={}", pgt.getSessionId(), expired);
+                    log.debug("{} Session {} expired={}", getLogPrefix(), pgt.getSessionId(), expired);
                 } catch (final SessionException e) {
-                    log.warn("Error performing session timeout check: {}. Assuming session has expired.", e);
+                    log.warn("{} Error performing session timeout check: {}. Assuming session has expired.",
+                            getLogPrefix(), e);
                 }
             }
             if (expired) {
-                return ProtocolError.SessionExpired.event(this);
+                ActionSupport.buildEvent(profileRequestContext, ProtocolError.SessionExpired.event(this));
+                return;
             }
         }
-        final ProxyTicketRequest request = getCASRequest(profileRequestContext);
         final ProxyTicket pt;
         try {
-            log.debug("Granting proxy ticket for {}", request.getTargetService());
+            log.debug("{} Granting proxy ticket for {}", getLogPrefix(), request.getTargetService());
             pt = casTicketService.createProxyTicket(
-                    securityConfiguration.getIdGenerator().generateIdentifier(),
-                    Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext)),
+                    securityConfig.getIdGenerator().generateIdentifier(),
+                    Instant.now().plus(proxyConfig.getTicketValidityPeriod(profileRequestContext)),
                     pgt,
                     request.getTargetService());
         } catch (final RuntimeException e) {
             log.error("Failed granting proxy ticket due to error.", e);
-            return ProtocolError.TicketCreationError.event(this);
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketCreationError.event(this));
+            return;
         }
-        log.info("Granted proxy ticket for {}", request.getTargetService());
-        setCASResponse(profileRequestContext, new ProxyTicketResponse(pt.getId()));
-        return null;
+        
+        try {
+            setCASResponse(profileRequestContext, new ProxyTicketResponse(pt.getId()));
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return;
+        }
+        
+        log.info("{} Granted proxy ticket for {}", getLogPrefix(), request.getTargetService());
     }
-}
+    
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
index fa218e9..0afe3c1 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
@@ -21,8 +21,10 @@ import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.AuthenticationResult;
+import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.authn.context.navigate.SubjectContextPrincipalLookupFunction;
@@ -34,16 +36,18 @@ import net.shibboleth.idp.cas.protocol.ServiceTicketResponse;
 import net.shibboleth.idp.cas.ticket.ServiceTicket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
 import net.shibboleth.idp.cas.ticket.TicketState;
+import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Generates and stores a CAS protocol service ticket. Possible outcomes:
@@ -74,9 +78,23 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
     /** Manages CAS tickets. */
     @Nonnull private final TicketServiceEx ticketServiceEx;
 
+    /** Profile config. */
+    @Nullable private LoginConfiguration loginConfig;
+    
+    /** Security config. */
+    @Nullable private SecurityConfiguration securityConfig;
+    
+    /** IdP's session. */
+    @Nullable private IdPSession session;
+    
+    /** Authentication result. */
+    @Nullable private AuthenticationResult authnResult;
+    
+    /** CAS request. */
+    @Nullable private ServiceTicketRequest request;
 
     /**
-     * Creates a new instance.
+     * Constructor.
      *
      * @param ticketService Ticket service component.
      */
@@ -90,72 +108,105 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
                 new ChildContextLookup<>(SubjectContext.class));
     }
 
-    /** {@inheritDoc} */
-    @Nonnull
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-
-        final ServiceTicketRequest request = getCASRequest(profileRequestContext);
-        final IdPSession session = getIdPSession(profileRequestContext);
-        final LoginConfiguration config = configLookupFunction.apply(profileRequestContext);
-        if (config == null) {
-            throw new IllegalStateException("Service ticket configuration undefined");
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
         }
         
-        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
-        if (securityConfiguration == null || securityConfiguration == null) {
-            throw new IllegalStateException(
-                    "Invalid service ticket configuration: SecurityConfiguration#idGenerator undefined");
+        loginConfig = configLookupFunction.apply(profileRequestContext);
+        if (loginConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
         }
+        
+        securityConfig = loginConfig.getSecurityConfiguration(profileRequestContext);
+        if (securityConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
+            return false;
+        }
+        
+        try {
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+
+        session = getIdPSession(profileRequestContext);
+        if (session == null) {
+            // TODO: I think this should be revisited, unclear why the TicketState later needs this.
+            // It may be needed specifically if the check below for an active AuthnResult fails, but that's
+            // a secondary requirement that would only happen when absolutely needed.
+            log.warn("{} No IdP session found", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
         final AuthenticationContext authnCtx = authnCtxLookupFunction.apply(profileRequestContext);
-        final AuthenticationResult authnResult;
         if (authnCtx != null) {
             authnResult = authnCtx.getAuthenticationResult();
         } else {
-            authnResult = getLatestAuthenticationResult(session);
+            authnResult = getLatestAuthenticationResult();
+        }
+        
+        if (authnResult == null) {
+            log.warn("{} No AuthenticationResult found", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
+            return false;
         }
+        
+        return true;
+    }    
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+                
         final ServiceTicket ticket;
         try {
-            log.debug("Granting service ticket for {}", request.getService());
+            log.debug("{} Granting service ticket for {}", getLogPrefix(), request.getService());
             final TicketState state = new TicketState(
                     session.getId(),
                     getPrincipalName(profileRequestContext),
                     authnResult.getAuthenticationInstant(),
                     authnResult.getAuthenticationFlowId());
             ticket = ticketServiceEx.createServiceTicket(
-                    securityConfiguration.getIdGenerator().generateIdentifier(),
-                    Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext)),
+                    securityConfig.getIdGenerator().generateIdentifier(),
+                    Instant.now().plus(loginConfig.getTicketValidityPeriod(profileRequestContext)),
                     request.getService(),
                     state,
                     request.isRenew());
         } catch (final RuntimeException e) {
-            log.error("Failed granting service ticket due to error.", e);
-            return ProtocolError.TicketCreationError.event(this);
+            log.error("{} Failed granting service ticket due to error.", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketCreationError.event(this));
+            return;
         }
-        log.info("Granted service ticket for {}", request.getService());
+        
         final ServiceTicketResponse response = new ServiceTicketResponse(request.getService(), ticket.getId());
         if (request.isSAML()) {
             response.setSaml(true);
         }
-        setCASResponse(profileRequestContext, response);
-        return null;
+        
+        try {
+            setCASResponse(profileRequestContext, response);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return;
+        }
+
+        log.info("{} Granted service ticket for {}", getLogPrefix(), request.getService());
     }
 
     /**
      * Get the IdP session.
      *
-     * @param prc profile request context.
+     * @param prc profile request context
+     * 
      * @return IdP session
      */
-    @Nonnull
-    private IdPSession getIdPSession(final ProfileRequestContext prc) {
+    @Nullable private IdPSession getIdPSession(final ProfileRequestContext prc) {
         final SessionContext sessionContext = sessionContextFunction.apply(prc);
-        if (sessionContext == null || sessionContext.getIdPSession() == null) {
-            throw new IllegalStateException("Cannot locate IdP session");
-        }
-        return sessionContext.getIdPSession();
+        return sessionContext != null ? sessionContext.getIdPSession() : null;
     }
 
     /**
@@ -164,8 +215,7 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
      * @param prc profile request context.
      * @return Principal name.
      */
-    @Nonnull
-    private String getPrincipalName(final ProfileRequestContext prc) {
+    @Nonnull private String getPrincipalName(final ProfileRequestContext prc) {
         final String principal = principalLookupFunction.apply(prc);
         if (principal == null ) {
             throw new IllegalStateException("Cannot determine IdP subject principal name.");
@@ -176,22 +226,20 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
     /**
      * Gets the most recent authentication result from the IdP session.
      *
-     * @param session IdP session to ask for authentication results.
-     *
      * @return Latest authentication result.
      *
      * @throws IllegalStateException If no authentication results are found.
      */
-    private AuthenticationResult getLatestAuthenticationResult(final IdPSession session) {
+    @Nullable private AuthenticationResult getLatestAuthenticationResult() {
         AuthenticationResult latest = null;
+        
         for (final AuthenticationResult result : session.getAuthenticationResults()) {
             if (latest == null || result.getAuthenticationInstant().isAfter(latest.getAuthenticationInstant())) {
                 latest = result;
             }
         }
-        if (latest == null) {
-            throw new IllegalStateException("Cannot find authentication results in IdP session");
-        }
+        
         return latest;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeLoginAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeLoginAction.java
index 2d0e96b..8d3aa1b 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeLoginAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeLoginAction.java
@@ -24,6 +24,9 @@ import net.shibboleth.idp.cas.protocol.ProtocolParam;
 import net.shibboleth.idp.cas.protocol.SamlParam;
 import net.shibboleth.idp.cas.protocol.ServiceTicketRequest;
 import net.shibboleth.idp.cas.protocol.ServiceTicketResponse;
+import net.shibboleth.idp.profile.ActionSupport;
+
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.springframework.webflow.core.collection.ParameterMap;
 import org.springframework.webflow.execution.Event;
@@ -40,11 +43,9 @@ import org.springframework.webflow.execution.RequestContext;
  */
 public class InitializeLoginAction extends AbstractCASProtocolAction<ServiceTicketRequest, ServiceTicketResponse> {
 
-    @Nonnull
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
 
         final ParameterMap params = springRequestContext.getRequestParameters();
         String service = params.get(ProtocolParam.Service.id());
@@ -76,8 +77,12 @@ public class InitializeLoginAction extends AbstractCASProtocolAction<ServiceTick
             serviceTicketRequest.setMethod(method);
         }
 
-        setCASRequest(profileRequestContext, serviceTicketRequest);
+        try {
+            setCASRequest(profileRequestContext, serviceTicketRequest);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
 
-        return null;
+        return ActionSupport.buildProceedEvent(this);
     }
 }
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeProxyAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeProxyAction.java
index 8925942..3c65d1c 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeProxyAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeProxyAction.java
@@ -26,7 +26,10 @@ import net.shibboleth.idp.cas.protocol.ProxyTicketResponse;
 import net.shibboleth.idp.cas.ticket.ProxyGrantingTicket;
 import net.shibboleth.idp.cas.ticket.TicketContext;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.ActionSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,12 +58,10 @@ import org.springframework.webflow.execution.RequestContext;
 public class InitializeProxyAction extends AbstractCASProtocolAction<ProxyTicketRequest, ProxyTicketResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(InitializeProxyAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(InitializeProxyAction.class);
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx ticketServiceEx;
-
+    @Nonnull private final TicketServiceEx ticketServiceEx;
 
     /**
      * Constructor.
@@ -71,12 +72,10 @@ public class InitializeProxyAction extends AbstractCASProtocolAction<ProxyTicket
         ticketServiceEx = Constraint.isNotNull(ticketService, "Ticket service cannot be null.");
     }
 
-    @Nonnull
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
+        
         final ParameterMap params = springRequestContext.getRequestParameters();
         String service = params.get(ProtocolParam.TargetService.id());
         Event result = null;
@@ -90,20 +89,27 @@ public class InitializeProxyAction extends AbstractCASProtocolAction<ProxyTicket
             result = ProtocolError.TicketNotSpecified.event(this);
         }
         final ProxyTicketRequest proxyTicketRequest = new ProxyTicketRequest(ticket, service);
-        setCASRequest(profileRequestContext, proxyTicketRequest);
+        try {
+            setCASRequest(profileRequestContext, proxyTicketRequest);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
+        
         if (result == null) {
             try {
-                log.debug("Fetching proxy-granting ticket {}", proxyTicketRequest.getPgt());
+                log.debug("{} Fetching proxy-granting ticket {}", getLogPrefix(), proxyTicketRequest.getPgt());
                 final ProxyGrantingTicket pgt = ticketServiceEx.fetchProxyGrantingTicket(proxyTicketRequest.getPgt());
                 if (pgt == null) {
                     return ProtocolError.TicketExpired.event(this);
                 }
                 setCASTicket(profileRequestContext, pgt);
-            } catch (final RuntimeException e) {
-                log.error("Failed looking up " + proxyTicketRequest.getPgt(), e);
+            } catch (final Exception e) {
+                log.error("{} Failed looking up {}", getLogPrefix(), proxyTicketRequest.getPgt(), e);
                 return ProtocolError.TicketRetrievalError.event(this);
             }
         }
+        
         return result;
     }
-}
+    
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeValidateAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeValidateAction.java
index 75f0590..4d73730 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeValidateAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/InitializeValidateAction.java
@@ -23,6 +23,9 @@ import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.protocol.ProtocolParam;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
+import net.shibboleth.idp.profile.ActionSupport;
+
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.springframework.webflow.core.collection.ParameterMap;
 import org.springframework.webflow.execution.Event;
@@ -41,11 +44,10 @@ import org.springframework.webflow.execution.RequestContext;
  */
 public class InitializeValidateAction extends
         AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
-    @Nonnull
+
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
 
         final ParameterMap params = springRequestContext.getRequestParameters();
         String service = params.get(ProtocolParam.Service.id());
@@ -67,8 +69,13 @@ public class InitializeValidateAction extends
         }
         ticketValidationRequest.setPgtUrl(params.get(ProtocolParam.PgtUrl.id()));
 
-        setCASRequest(profileRequestContext, ticketValidationRequest);
+        try {
+            setCASRequest(profileRequestContext, ticketValidationRequest);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
 
         return result;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PopulateProtocolErrorAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PopulateProtocolErrorAction.java
index 1fed84c..ec9c4ef 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PopulateProtocolErrorAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PopulateProtocolErrorAction.java
@@ -19,7 +19,11 @@ package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
 
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.webflow.execution.Event;
 import org.springframework.webflow.execution.RequestContext;
 
@@ -29,6 +33,7 @@ import net.shibboleth.idp.cas.protocol.ProxyTicketRequest;
 import net.shibboleth.idp.cas.protocol.ProxyTicketResponse;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
+import net.shibboleth.idp.profile.ActionSupport;
 
 /**
  * Populates error information needed for protocol error messages.
@@ -37,20 +42,30 @@ import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
  */
 public class PopulateProtocolErrorAction extends AbstractCASProtocolAction {
 
-    @Nonnull
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateProtocolErrorAction.class);
+    
     @Override
-    protected Event doExecute(
-            @Nonnull final RequestContext springRequestContext,
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
             @Nonnull final ProfileRequestContext profileRequestContext) {
-        final Object request = getCASRequest(profileRequestContext);
+
+        final Object request;
+        try {
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
+
         final AbstractProtocolResponse response;
         if (request instanceof ProxyTicketRequest) {
             response = new ProxyTicketResponse();
         } else if (request instanceof TicketValidationRequest) {
             response = new TicketValidationResponse();
         } else {
-            throw new IllegalArgumentException("Invalid request type: " + request);
+            log.error("{} Invalid request type: {}", getLogPrefix(), request);
+            return ActionSupport.buildEvent(this, EventIds.INVALID_MESSAGE);
         }
+        
         String code = (String) springRequestContext.getCurrentEvent().getAttributes().get("code");
         String detail = (String) springRequestContext.getCurrentEvent().getAttributes().get("detailCode");
         if (code == null) {
@@ -59,9 +74,16 @@ public class PopulateProtocolErrorAction extends AbstractCASProtocolAction {
         if (detail == null) {
             detail = ProtocolError.IllegalState.getDetailCode();
         }
+        
         response.setErrorCode(code);
         response.setErrorDetail(detail);
-        setCASResponse(profileRequestContext, response);
-        return null;
+        try {
+            setCASResponse(profileRequestContext, response);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
+        
+        return ActionSupport.buildProceedEvent(this);
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
index 387b096..56fe23f 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.attribute.AttributeEncodingException;
 import net.shibboleth.idp.attribute.IdPAttribute;
@@ -55,6 +56,7 @@ import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -91,6 +93,15 @@ public class PrepareTicketValidationResponseAction extends
     
     /** Fallback rule that does a simple/default encode. */
     @NonnullAfterInit private TranscodingRule defaultTranscodingRule;
+    
+    /** Stored off context from request. */
+    @Nullable private AttributeContext attributeContext;
+    
+    /** Profile configuration. */
+    @Nullable private ValidateConfiguration validateConfiguration;
+    
+    /** CAS response. */
+    @Nullable private TicketValidationResponse response;
 
     /** Constructor. */
     public PrepareTicketValidationResponseAction() {
@@ -127,42 +138,60 @@ public class PrepareTicketValidationResponseAction extends
                 Collections.singletonMap(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder));
     }
     
-    /** {@inheritDoc} */
- // CheckStyle: CyclomaticComplexity OFF
     @Override
-    protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
-
-        final AttributeContext ac = attributeContextFunction.apply(profileRequestContext);
-        if (ac == null) {
-            throw new IllegalStateException("AttributeContext not found in profile request context.");
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
         }
-
-        final ValidateConfiguration validateConfiguration = configLookupFunction.apply(profileRequestContext);
+        
+        attributeContext = attributeContextFunction.apply(profileRequestContext);
+        if (attributeContext == null) {
+            log.warn("{} AttributeContext not found in profile request context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_ATTRIBUTE_CTX);
+            return false;
+        }
+        
+        validateConfiguration = configLookupFunction.apply(profileRequestContext);
         if (validateConfiguration == null) {
-            throw new IllegalArgumentException("Cannot locate ValidateConfiguration");
+            log.warn("{} Cannot locate ValidateConfiguration", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
+        }
+        
+        try {
+            response = getCASResponse(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
         }
+        
+        return true;
+    }    
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
         final String principal;
         final String userAttributeName = validateConfiguration.getUserAttribute(profileRequestContext);
         if (userAttributeName != null) {
-            log.debug("Using {} for CAS username", userAttributeName);
-            final IdPAttribute attribute = ac.getIdPAttributes().get(userAttributeName);
+            log.debug("{} Using {} for CAS username", getLogPrefix(), userAttributeName);
+            final IdPAttribute attribute = attributeContext.getIdPAttributes().get(userAttributeName);
             if (attribute != null && !attribute.getValues().isEmpty()) {
                 final IdPAttributeValue value = attribute.getValues().get(0);
                 if (value instanceof ScopedStringAttributeValue) {
                     final ScopedStringAttributeValue scopedValue = (ScopedStringAttributeValue) value;
-                    log.warn("Lossy use of attribute value {} from attribute {}",
+                    log.warn("{} Lossy use of attribute value {} from attribute {}", getLogPrefix(),
                             scopedValue.getValue(), attribute.getId());
                     principal = scopedValue.getValue();
                 } else if (value instanceof StringAttributeValue) {
                     principal = ((StringAttributeValue) value).getValue();
                 } else {
-                    log.warn("Use of attribute value type {} from attribute {}",
+                    log.warn("{} Use of attribute value type {} from attribute {}", getLogPrefix(),
                             value.getClass(), attribute.getId());
                     principal = value.getNativeValue().toString();
                 }
             } else {
-                log.debug("Filtered attribute {} has no value", userAttributeName);
+                log.debug("{} Filtered attribute {} has no value", getLogPrefix(), userAttributeName);
                 principal = null;
             }
         } else {
@@ -173,10 +202,9 @@ public class PrepareTicketValidationResponseAction extends
             throw new IllegalStateException("Principal cannot be null");
         }
 
-        final TicketValidationResponse response = getCASResponse(profileRequestContext);
         response.setUserName(principal);
         
-        final Collection<IdPAttribute> inputAttributes = ac.getIdPAttributes().values();
+        final Collection<IdPAttribute> inputAttributes = attributeContext.getIdPAttributes().values();
         final ArrayList<Attribute> encodedAttributes = new ArrayList<>(inputAttributes.size());
         
         ServiceableComponent<AttributeTranscoderRegistry> component = null;
@@ -198,7 +226,6 @@ public class PrepareTicketValidationResponseAction extends
         
         encodedAttributes.forEach(a -> response.addAttribute(a));
     }
-    // CheckStyle: CyclomaticComplexity ON
 
     /**
      * Access the registry of transcoding rules to transform the input attribute into a target type.
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ProcessSamlMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ProcessSamlMessageAction.java
index 34f2d91..80da408 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ProcessSamlMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ProcessSamlMessageAction.java
@@ -25,7 +25,10 @@ import net.shibboleth.idp.cas.protocol.ProtocolParam;
 import net.shibboleth.idp.cas.protocol.SamlParam;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
+import net.shibboleth.idp.profile.ActionSupport;
+
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.saml1.core.AssertionArtifact;
@@ -52,14 +55,11 @@ public class ProcessSamlMessageAction extends
         AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
 
     /** Class logger. */
-    @Nonnull
-    private final Logger log = LoggerFactory.getLogger(ProcessSamlMessageAction.class);
-
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ProcessSamlMessageAction.class);
 
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
 
         profileRequestContext.setProfileId(ValidateConfiguration.PROFILE_ID);
 
@@ -79,7 +79,7 @@ public class ProcessSamlMessageAction extends
                 break;
             }
         } else {
-            log.info("Unexpected SAMLObject type {}", msgContext.getMessage().getClass().getName());
+            log.warn("{} Unexpected SAMLObject type {}", getLogPrefix(), msgContext.getMessage().getClass().getName());
             return ProtocolError.ProtocolViolation.event(this);
         }
         if (ticket == null) {
@@ -92,8 +92,13 @@ public class ProcessSamlMessageAction extends
             ticketValidationRequest.setRenew(true);
         }
 
-        setCASRequest(profileRequestContext, ticketValidationRequest);
+        try {
+            setCASRequest(profileRequestContext, ticketValidationRequest);
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
+        }
 
-        return null;
+        return ActionSupport.buildProceedEvent(this);
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PublishProtocolMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PublishProtocolMessageAction.java
index d0aabe5..6bc18e3 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PublishProtocolMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PublishProtocolMessageAction.java
@@ -19,10 +19,13 @@ package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
 
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.springframework.webflow.execution.Event;
 import org.springframework.webflow.execution.RequestContext;
 
+import net.shibboleth.idp.profile.ActionSupport;
+
 /**
  * Action to publish the CAS protocol request or response messages, i.e.
  * {@link net.shibboleth.idp.cas.protocol.ProtocolContext#getResponse()}, in Spring Webflow
@@ -47,19 +50,26 @@ public class PublishProtocolMessageAction extends AbstractCASProtocolAction {
     }
 
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Nonnull protected Event doExecute(@Nonnull final RequestContext springRequestContext,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
 
         final Object message;
-        if (requestFlag) {
-            message = getCASRequest(profileRequestContext);
-        } else {
-            message = getCASResponse(profileRequestContext);
+        
+        try {
+            if (requestFlag) {
+                message = getCASRequest(profileRequestContext);
+            } else {
+                message = getCASResponse(profileRequestContext);
+            }
+        } catch (final EventException e) {
+            return ActionSupport.buildEvent(this, e.getEventID());
         }
+        
         final String className = message.getClass().getSimpleName();
         final String keyName = className.substring(0, 1).toLowerCase() + className.substring(1);
         springRequestContext.getFlowScope().put(keyName, message);
-        return null;
+        
+        return ActionSupport.buildProceedEvent(this);
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/UpdateIdPSessionWithSPSessionAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/UpdateIdPSessionWithSPSessionAction.java
index 5cb3b4c..6319e17 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/UpdateIdPSessionWithSPSessionAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/UpdateIdPSessionWithSPSessionAction.java
@@ -21,6 +21,7 @@ import java.time.Duration;
 import java.time.Instant;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.service.Service;
 import net.shibboleth.idp.cas.session.impl.CASSPSession;
@@ -34,14 +35,14 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
- * Conditionally updates the {@link net.shibboleth.idp.session.IdPSession} with a {@link CASSPSession} to support SLO.
+ * Conditionally updates the {@link IdPSession} with a {@link CASSPSession} to support SLO.
  * If the service granted access to indicates participation in SLO via {@link Service#singleLogoutParticipant},
  * then a {@link CASSPSession} is created to track the SP session in order that it may receive SLO messages upon
  * a request to the CAS <code>/logout</code> URI.
@@ -59,35 +60,54 @@ public class UpdateIdPSessionWithSPSessionAction extends AbstractCASProtocolActi
     /** Lifetime of sessions to create. */
     @Nonnull private final Duration sessionLifetime;
 
+    /** Ticket. */
+    @Nullable private Ticket ticket;
+    
+    /** CAS service. */
+    @Nullable private Service service;
 
     /**
-     * Creates a new instance with given parameters.
+     * Constructor.
      *
      * @param resolver Session resolver component
      * @param lifetime determines upper bound for expiration of the {@link CASSPSession} to be created
      */
     public UpdateIdPSessionWithSPSessionAction(@Nonnull final SessionResolver resolver,
             @Nonnull final Duration lifetime) {
-        sessionResolver = Constraint.isNotNull(resolver, "Session resolver cannot be null.");
+        sessionResolver = Constraint.isNotNull(resolver, "Session resolver cannot be null");
         sessionLifetime = Constraint.isNotNull(lifetime, "Lifetime cannot be null");
     }
 
-    /** {@inheritDoc} */
     @Override
-    @Nonnull protected Event doExecute(final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
 
-        final Ticket ticket = getCASTicket(profileRequestContext);
-        final Service service = getCASService(profileRequestContext);
-        if (!service.isSingleLogoutParticipant()) {
-            return null;
+        try {
+            service = getCASService(profileRequestContext);
+            if (!service.isSingleLogoutParticipant()) {
+                return false;
+            }
+            
+            ticket = getCASTicket(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
         }
+
+        return true;
+    }
+    
+    @Override
+    @Nonnull protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
         IdPSession session = null;
         try {
-            log.debug("Attempting to retrieve session {}", ticket.getSessionId());
+            log.debug("{} Attempting to retrieve session {}", getLogPrefix(), ticket.getSessionId());
             session = sessionResolver.resolveSingle(new CriteriaSet(new SessionIdCriterion(ticket.getSessionId())));
         } catch (final ResolverException e) {
-            log.warn("Possible sign of misconfiguration, IdPSession resolution error: {}", e);
+            log.warn("{} Possible sign of misconfiguration, IdPSession resolution error: {}", getLogPrefix(), e);
         }
         if (session != null) {
             final Instant now = Instant.now();
@@ -96,15 +116,15 @@ public class UpdateIdPSessionWithSPSessionAction extends AbstractCASProtocolActi
                     now,
                     now.plus(sessionLifetime),
                     ticket.getId());
-            log.debug("Created SP session {}", sps);
+            log.debug("{} Created SP session {}", getLogPrefix(), sps);
             try {
                 session.addSPSession(sps);
             } catch (final SessionException e) {
-                log.warn("Failed updating IdPSession with CASSPSession", e);
+                log.warn("{} Failed updating IdPSession with CASSPSession", getLogPrefix(), e);
             }
         } else {
-            log.info("Cannot store CASSPSession since IdPSession not found");
+            log.info("{} Cannot store CASSPSession since IdPSession not found", getLogPrefix());
         }
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
index 66b2b03..61babc6 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
@@ -22,13 +22,15 @@ import java.net.URISyntaxException;
 import java.time.Instant;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.http.client.utils.URIBuilder;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
 import net.shibboleth.idp.cas.config.impl.ValidateConfiguration;
@@ -42,6 +44,7 @@ import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.ServiceTicket;
 import net.shibboleth.idp.cas.ticket.Ticket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
@@ -74,48 +77,71 @@ public class ValidateProxyCallbackAction
     /** Manages CAS tickets. */
     @Nonnull private final TicketServiceEx ticketServiceEx;
 
+    /** Profile config. */
+    @Nullable private ValidateConfiguration validateConfig;
+    
+    /** Security config. */
+    @Nullable private SecurityConfiguration securityConfig;
+    
+    /** CAS ticket. */
+    @Nullable private Ticket ticket;
 
+    /** CAS request. */
+    @Nullable private TicketValidationRequest request;
+
+    /** CAS response. */
+    @Nullable private TicketValidationResponse response;
+    
     /**
-     * Creates a new instance.
+     * Constructor.
      *
      * @param validator Component that validates the proxy callback endpoint.
      * @param ticketService Ticket service component.
      */
-    public ValidateProxyCallbackAction(
-            @Nonnull final ProxyValidator validator,
+    public ValidateProxyCallbackAction(@Nonnull final ProxyValidator validator,
             @Nonnull final TicketServiceEx ticketService) {
         proxyValidator = Constraint.isNotNull(validator, "ProxyValidator cannot be null");
         ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
         
         configLookupFunction = new ConfigLookupFunction<>(ValidateConfiguration.class);
     }
-
+    
     @Override
-    @Nonnull
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-
-        final TicketValidationRequest request = getCASRequest(profileRequestContext);
-        final TicketValidationResponse response = getCASResponse(profileRequestContext);
-        final Ticket ticket = getCASTicket(profileRequestContext);
-        final ValidateConfiguration config = configLookupFunction.apply(profileRequestContext);
-        if (config == null) {
-            throw new IllegalStateException("Proxy-granting ticket configuration undefined");
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        validateConfig = configLookupFunction.apply(profileRequestContext);
+        if (validateConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
         }
         
-        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
-        if (securityConfiguration == null || securityConfiguration.getIdGenerator() == null) {
-            throw new IllegalStateException(
-                    "Invalid proxy-granting ticket configuration: SecurityConfiguration#idGenerator undefined");
+        securityConfig = validateConfig.getSecurityConfiguration(profileRequestContext);
+        if (securityConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
+            return false;
         }
         
-        final IdentifierGenerationStrategy pgtGenerator = config.getPGTIOUGenerator(profileRequestContext);
-        if (pgtGenerator == null) {
-            throw new IllegalStateException("Invalid proxy-granting ticket configuration: PGTIOUGenerator undefined");
+        try {
+            ticket = getCASTicket(profileRequestContext);
+            request = getCASRequest(profileRequestContext);
+            response = getCASResponse(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
         }
+
+        return true;
+    }
+
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        final IdentifierGenerationStrategy pgtGenerator = validateConfig.getPGTIOUGenerator(profileRequestContext);
         final ProxyIdentifiers proxyIds = new ProxyIdentifiers(
-                securityConfiguration.getIdGenerator().generateIdentifier(),
+                securityConfig.getIdGenerator().generateIdentifier(),
                 pgtGenerator.generateIdentifier());
         final URI proxyCallbackUri;
         try {
@@ -124,12 +150,16 @@ public class ValidateProxyCallbackAction
                     .addParameter(ProtocolParam.PgtIou.id(), proxyIds.getPgtIou())
                     .build();
         } catch (final URISyntaxException e) {
-            throw new RuntimeException("Error creating proxy callback URL", e);
+            log.warn("{} Error creating proxy callback URL", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, EventIds.RUNTIME_EXCEPTION);
+            return;
         }
+        
         try {
-            log.debug("Attempting proxy authentication to {}", proxyCallbackUri);
+            log.debug("{} Attempting proxy authentication to {}", getLogPrefix(), proxyCallbackUri);
             proxyValidator.validate(profileRequestContext, proxyCallbackUri);
-            final Instant expiration = Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext));
+            final Instant expiration =
+                    Instant.now().plus(validateConfig.getTicketValidityPeriod(profileRequestContext));
             if (ticket instanceof ServiceTicket) {
                 ticketServiceEx.createProxyGrantingTicket(proxyIds.getPgtId(), expiration, (ServiceTicket) ticket);
             } else {
@@ -137,9 +167,10 @@ public class ValidateProxyCallbackAction
             }
             response.setPgtIou(proxyIds.getPgtIou());
         } catch (final Exception e) {
-            log.info("Proxy authentication failed for " + request.getPgtUrl() + ": " + e);
-            return ProtocolError.ProxyCallbackAuthenticationFailure.event(this);
+            log.warn("{} Proxy authentication failed for {}", getLogPrefix(), request.getPgtUrl(), e);
+            ActionSupport.buildEvent(profileRequestContext,
+                    ProtocolError.ProxyCallbackAuthenticationFailure.event(this));
         }
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateRenewAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateRenewAction.java
index 1f80e46..6403817 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateRenewAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateRenewAction.java
@@ -18,17 +18,19 @@
 package net.shibboleth.idp.cas.flow.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.ProtocolError;
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
 import net.shibboleth.idp.cas.ticket.ServiceTicket;
 import net.shibboleth.idp.cas.ticket.Ticket;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * Ensures that a service ticket validation request that specifies renew=true matches the renew flag on the ticket
@@ -44,28 +46,48 @@ import org.springframework.webflow.execution.RequestContext;
 public class ValidateRenewAction extends AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(ValidateRenewAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateRenewAction.class);
+
+    /** CAS ticket. */
+    @Nullable private Ticket ticket;
 
+    /** CAS request. */
+    @Nullable private TicketValidationRequest request;
+
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        try {
+            ticket = getCASTicket(profileRequestContext);
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
 
-    @Nonnull
+        return true;
+    }
+    
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        final TicketValidationRequest request = getCASRequest(profileRequestContext);
-        final Ticket ticket = getCASTicket(profileRequestContext);
         if (ticket instanceof ServiceTicket) {
             if (request.isRenew() != ((ServiceTicket) ticket).isRenew()) {
-                log.debug("Renew=true requested at validation time but ticket not issued with renew=true.");
-                return ProtocolError.TicketNotFromRenew.event(this);
+                log.debug("{} Renew=true requested at validation time but ticket not issued with renew=true",
+                        getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketNotFromRenew.event(this));
+                return;
             }
         } else {
             // Proxy ticket validation
             if (request.isRenew()) {
-                return ProtocolError.RenewIncompatibleWithProxy.event(this);
+                ActionSupport.buildEvent(profileRequestContext, ProtocolError.RenewIncompatibleWithProxy.event(this));
+                return;
             }
         }
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
index 74691c0..d54a48d 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.cas.flow.impl;
 import java.time.Instant;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
 import net.shibboleth.idp.cas.config.impl.LoginConfiguration;
@@ -31,12 +32,14 @@ import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
 import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.Ticket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * CAS protocol service ticket validation action. Emits one of the following events based on validation result:
@@ -55,39 +58,55 @@ import org.springframework.webflow.execution.RequestContext;
 public class ValidateTicketAction extends AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(ValidateTicketAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateTicketAction.class);
 
     /** Profile configuration lookup function. */
-    private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction =
-            new ConfigLookupFunction<>(ValidateConfiguration.class);
+    @Nonnull private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction;
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx ticketServiceEx;
+    @Nonnull private final TicketServiceEx ticketServiceEx;
 
+    /** Profile config. */
+    @Nullable private ValidateConfiguration validateConfig;
 
+    /** CAS request. */
+    @Nullable private TicketValidationRequest request;
+    
     /**
-     * Creates a new instance.
+     * Constructor.
      *
-     * @param ticketService Ticket service component.
+     * @param ticketService ticket service component
      */
     public ValidateTicketAction(@Nonnull final TicketServiceEx ticketService) {
         ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
+        configLookupFunction = new ConfigLookupFunction<>(ValidateConfiguration.class);
     }
 
-    @Nonnull
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
-
-        final ValidateConfiguration config = configLookupFunction.apply(profileRequestContext);
-        if (config == null) {
-            log.warn("Ticket validation configuration undefined");
-            return ProtocolError.IllegalState.event(this);
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        validateConfig = configLookupFunction.apply(profileRequestContext);
+        if (validateConfig == null) {
+            ActionSupport.buildEvent(profileRequestContext,IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
         }
+        
+        try {
+            request = getCASRequest(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+
+        return true;
+    }
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        final TicketValidationRequest request = getCASRequest(profileRequestContext);
         final Ticket ticket;
         try {
             final String ticketId = request.getTicket();
@@ -97,32 +116,48 @@ public class ValidateTicketAction extends AbstractCASProtocolAction<TicketValida
             } else if (ticketId.startsWith(ProxyConfiguration.DEFAULT_TICKET_PREFIX)) {
                 ticket = ticketServiceEx.removeProxyTicket(ticketId);
             } else {
-                return ProtocolError.InvalidTicketFormat.event(this);
+                ActionSupport.buildEvent(profileRequestContext, ProtocolError.InvalidTicketFormat.event(this));
+                return;
             }
             if (ticket != null) {
-                log.debug("Found and removed {}/{} from ticket store", ticket, ticket.getSessionId());
+                log.debug("{} Found and removed {}/{} from ticket store", getLogPrefix(), ticket,
+                        ticket.getSessionId());
             }
         } catch (final RuntimeException e) {
-            log.debug("CAS ticket retrieval failed with error: {}", e);
-            return ProtocolError.TicketRetrievalError.event(this);
+            log.debug("{} CAS ticket retrieval failed with error: {}", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketRetrievalError.event(this));
+            return;
         }
 
         if (ticket == null || ticket.getExpirationInstant().isBefore(Instant.now())) {
-            return ProtocolError.TicketExpired.event(this);
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.TicketExpired.event(this));
+            return;
         }
 
-        if (config.getServiceComparator(profileRequestContext).compare(
+        if (validateConfig.getServiceComparator(profileRequestContext).compare(
                 ticket.getService(), request.getService()) != 0) {
-            log.debug("Service issued for {} does not match {}", ticket.getService(), request.getService());
-            return ProtocolError.ServiceMismatch.event(this);
+            log.debug("{} Service issued for {} does not match {}", getLogPrefix(), ticket.getService(),
+                    request.getService());
+            ActionSupport.buildEvent(profileRequestContext, ProtocolError.ServiceMismatch.event(this));
+            return;
+        }
+
+        try {
+            setCASResponse(profileRequestContext, new TicketValidationResponse());
+            setCASTicket(profileRequestContext, ticket);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return;
         }
 
-        log.info("Successfully validated {} for {}", request.getTicket(), request.getService());
-        setCASResponse(profileRequestContext, new TicketValidationResponse());
-        setCASTicket(profileRequestContext, ticket);
+        log.info("{} Successfully validated {} for {}", getLogPrefix(), request.getTicket(), request.getService());
+        
         if (ticket instanceof ProxyTicket) {
-            return Events.ProxyTicketValidated.event(this);
+            ActionSupport.buildEvent(profileRequestContext, Events.ProxyTicketValidated.event(this));
+            return;
         }
-        return Events.ServiceTicketValidated.event(this);
+        
+        ActionSupport.buildEvent(profileRequestContext, Events.ServiceTicketValidated.event(this));
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/WriteValidateResponseAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/WriteValidateResponseAction.java
index fad8d09..98c75e5 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/WriteValidateResponseAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/WriteValidateResponseAction.java
@@ -20,13 +20,15 @@ package net.shibboleth.idp.cas.flow.impl;
 import java.io.IOException;
 import java.io.PrintWriter;
 import javax.annotation.Nonnull;
-import javax.servlet.http.HttpServletResponse;
+import javax.annotation.Nullable;
 
 import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
 import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventException;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
 
 /**
  * CAS 1.0 protocol response handler.
@@ -36,12 +38,16 @@ import org.springframework.webflow.execution.RequestContext;
  */
 public class WriteValidateResponseAction extends
         AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse>  {
+    
     /** CAS 1.0 protocol content type is plain text. */
-    private static final String CONTENT_TYPE = "text/plain;charset=utf-8";
+    @Nonnull @NotEmpty private static final String CONTENT_TYPE = "text/plain;charset=utf-8";
 
     /** Protocol success flag indicates what kind of response to provide. */
     private final boolean success;
 
+    /** CAS response. */
+    @Nullable private TicketValidationResponse response;
+    
     /**
      * Constructor.
      *
@@ -52,16 +58,27 @@ public class WriteValidateResponseAction extends
     }
 
     @Override
-    protected Event doExecute(
-            final @Nonnull RequestContext springRequestContext,
-            final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
 
-        final TicketValidationResponse response = getCASResponse(profileRequestContext);
         try {
-            final HttpServletResponse servletResponse =
-                    (HttpServletResponse) springRequestContext.getExternalContext().getNativeResponse();
-            servletResponse.setContentType(CONTENT_TYPE);
-            final PrintWriter output = servletResponse.getWriter();
+            response = getCASResponse(profileRequestContext);
+        } catch (final EventException e) {
+            ActionSupport.buildEvent(profileRequestContext, e.getEventID());
+            return false;
+        }
+
+        return true;
+    }
+    
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        try {
+            getHttpServletResponse().setContentType(CONTENT_TYPE);
+            final PrintWriter output = getHttpServletResponse().getWriter();
             if (success) {
                 output.print("yes\n");
                 output.print(response.getUserName() + '\n');
@@ -72,6 +89,6 @@ public class WriteValidateResponseAction extends
         } catch (final IOException e) {
             throw new RuntimeException("IO error writing CAS protocol response", e);
         }
-        return null;
     }
-}
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextActionTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextActionTest.java
index c4464fa..12e81e8 100644
--- a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextActionTest.java
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextActionTest.java
@@ -28,13 +28,15 @@ import org.testng.annotations.Test;
 
 import static org.testng.Assert.*;
 
+import org.opensaml.profile.action.EventException;
+
 public class BuildRelyingPartyContextActionTest extends AbstractFlowActionTest {
 
     @Autowired
     private BuildRelyingPartyContextAction action;
 
     @Test
-    public void testExecuteFromServiceTicketRequest() {
+    public void testExecuteFromServiceTicketRequest() throws EventException {
         final String serviceURL = "https://serviceA.example.org:8443/landing";
         final RequestContext requestContext = new TestContextBuilder(LoginConfiguration.PROFILE_ID)
                 .addProtocolContext(new ServiceTicketRequest(serviceURL), null)
@@ -47,7 +49,7 @@ public class BuildRelyingPartyContextActionTest extends AbstractFlowActionTest {
     }
 
     @Test
-    public void testExecuteFromTicketValidationRequest() {
+    public void testExecuteFromTicketValidationRequest() throws EventException {
         final String serviceURL = "http://serviceB.example.org/";
         final RequestContext requestContext = new TestContextBuilder(LoginConfiguration.PROFILE_ID)
                 .addProtocolContext(new TicketValidationRequest(serviceURL, "ST-123"), null)
@@ -60,7 +62,7 @@ public class BuildRelyingPartyContextActionTest extends AbstractFlowActionTest {
     }
 
     @Test
-    public void testExecuteFromProxyTicketRequest() {
+    public void testExecuteFromProxyTicketRequest() throws EventException {
         final String serviceURL = "http://mallory.untrusted.org/";
         final RequestContext requestContext = new TestContextBuilder(LoginConfiguration.PROFILE_ID)
                 .addProtocolContext(new ProxyTicketRequest("PGT-123", serviceURL), null)
diff --git a/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml b/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
index 5cca89d..ec50f98 100644
--- a/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
@@ -29,15 +29,14 @@
         p:metricStrategy="#{getObject('shibboleth.metrics.MetricStrategy')}" />
 
     <bean id="BuildRelyingPartyContext"
-          class="net.shibboleth.idp.cas.flow.impl.BuildRelyingPartyContextAction"
+          class="net.shibboleth.idp.cas.flow.impl.BuildRelyingPartyContextAction" scope="prototype"
           c:registries="#{getObject('shibboleth.CASServiceRegistries') ?: getObject('shibboleth.DefaultCASServiceRegistries')}" />
 
-    <bean id="BuildSAMLMetadataContext"
+    <bean id="BuildSAMLMetadataContext" scope="prototype"
           class="net.shibboleth.idp.cas.flow.impl.BuildSAMLMetadataContextAction" />
 
     <bean id="PopulateInboundInterceptContext"
-          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
           p:availableFlows-ref="shibboleth.AvailableInterceptFlows">
         <property name="activeFlowsLookupStrategy">
             <bean class="net.shibboleth.idp.profile.config.navigate.InboundFlowsLookupFunction" />
@@ -45,8 +44,7 @@
     </bean>
 
     <bean id="PopulateOutboundInterceptContext"
-          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
           p:availableFlows-ref="shibboleth.AvailableInterceptFlows">
         <property name="activeFlowsLookupStrategy">
             <bean class="net.shibboleth.idp.profile.config.navigate.OutboundFlowsLookupFunction" />
@@ -54,37 +52,32 @@
     </bean>
 
     <bean id="PublishProtocolRequest"
-          class="net.shibboleth.idp.cas.flow.impl.PublishProtocolMessageAction"
+          class="net.shibboleth.idp.cas.flow.impl.PublishProtocolMessageAction" scope="prototype"
           c:isRequest="true" />
 
     <bean id="PublishProtocolResponse"
-          class="net.shibboleth.idp.cas.flow.impl.PublishProtocolMessageAction"
+          class="net.shibboleth.idp.cas.flow.impl.PublishProtocolMessageAction" scope="prototype"
           c:isRequest="false" />
 
     <bean id="SelectProfileConfiguration"
-          class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration"
-          scope="prototype" />
+          class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype" />
 
     <bean id="SelectRelyingPartyConfiguration"
-          class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype"
           p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
 
     <bean id="PopulateSubjectContext"
-          class="net.shibboleth.idp.profile.impl.PopulateSubjectContext"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.impl.PopulateSubjectContext" scope="prototype"
           p:principalNameLookupStrategy-ref="PrincipalLookupFunction" />
 
     <bean id="ResolveAttributes"
-          class="net.shibboleth.idp.profile.impl.ResolveAttributes"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.impl.ResolveAttributes" scope="prototype"
           c:resolverService-ref="shibboleth.AttributeResolverService"
           p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
           p:maskFailures="%{idp.service.attribute.resolver.maskFailures:true}" />
 
     <bean id="FilterAttributes"
-          class="net.shibboleth.idp.profile.impl.FilterAttributes"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.impl.FilterAttributes" scope="prototype"
           c:filterService-ref="shibboleth.AttributeFilterService"
           p:maskFailures="%{idp.service.attribute.filter.maskFailures:true}"
           p:metadataResolver-ref="shibboleth.MetadataResolver">
@@ -106,8 +99,7 @@
           p:eventMap="#{getObject('shibboleth.EventViewMap')}" />
 
     <bean id="WriteAuditLog"
-          class="net.shibboleth.idp.profile.audit.impl.WriteAuditLog"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.audit.impl.WriteAuditLog" scope="prototype"
           p:formattingMap-ref="shibboleth.AuditFormattingMap"
           p:dateTimeFormat="#{getObject('shibboleth.AuditDateTimeFormat')}"
           p:useDefaultTimeZone="#{getObject('shibboleth.AuditDefaultTimeZone') ?: false}"
@@ -117,5 +109,6 @@
           p:fieldExtractors="#{getObject('shibboleth.ErrorViewAuditExtractors') ?: getObject('shibboleth.DefaultErrorViewAuditExtractors')}" />
 
     <bean id="PopulateProtocolError"
-          class="net.shibboleth.idp.cas.flow.impl.PopulateProtocolErrorAction" />
+          class="net.shibboleth.idp.cas.flow.impl.PopulateProtocolErrorAction" scope="prototype" />
+          
 </beans>
diff --git a/idp-conf/src/main/resources/system/flows/cas/login/login-beans.xml b/idp-conf/src/main/resources/system/flows/cas/login/login-beans.xml
index e778061..73ff17a 100644
--- a/idp-conf/src/main/resources/system/flows/cas/login/login-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/login/login-beans.xml
@@ -10,7 +10,7 @@
 
     <!-- Action beans -->
     <bean id="InitializeProfileRequestContext"
-          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext"
+          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext" scope="prototype"
           p:profileId="#{T(net.shibboleth.idp.cas.config.impl.LoginConfiguration).PROFILE_ID}"
           p:loggingId="%{idp.service.logging.cas:SSO}"
           p:browserProfile="true" />
@@ -20,43 +20,39 @@
           p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
 
     <bean id="PopulateClientStorageLoadContext"
-          class="org.opensaml.storage.impl.client.PopulateClientStorageLoadContext"
-          scope="prototype"
+          class="org.opensaml.storage.impl.client.PopulateClientStorageLoadContext" scope="prototype"
           p:storageServices="#{ getObject('shibboleth.ClientStorageServices') ?: getObject('shibboleth.DefaultClientStorageServices') }" />
 
     <bean id="PopulateClientStorageSaveContext"
-          class="org.opensaml.storage.impl.client.PopulateClientStorageSaveContext"
-          scope="prototype"
+          class="org.opensaml.storage.impl.client.PopulateClientStorageSaveContext" scope="prototype"
           p:storageServices="#{ getObject('shibboleth.ClientStorageServices') ?: getObject('shibboleth.DefaultClientStorageServices') }" />
 
     <bean id="InitializeLogin"
-          class="net.shibboleth.idp.cas.flow.impl.InitializeLoginAction" />
+          class="net.shibboleth.idp.cas.flow.impl.InitializeLoginAction" scope="prototype"/>
 
     <bean id="BuildAuthenticationContext"
-          class="net.shibboleth.idp.cas.flow.impl.BuildAuthenticationContextAction" />
+          class="net.shibboleth.idp.cas.flow.impl.BuildAuthenticationContextAction" scope="prototype" />
 
     <bean id="GrantServiceTicket"
-          class="net.shibboleth.idp.cas.flow.impl.GrantServiceTicketAction"
+          class="net.shibboleth.idp.cas.flow.impl.GrantServiceTicketAction" scope="prototype"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
 
     <bean id="PopulateSessionContext"
-          class="net.shibboleth.idp.session.impl.PopulateSessionContext"
-          scope="prototype"
+          class="net.shibboleth.idp.session.impl.PopulateSessionContext" scope="prototype"
           p:activationCondition="%{idp.session.enabled:true}"
           p:httpServletRequest-ref="shibboleth.HttpServletRequest"
           p:sessionResolver-ref="shibboleth.SessionManager" />
 
     <bean id="LoginConfigLookup"
-          class="net.shibboleth.idp.cas.config.impl.ConfigLookupFunction"
+          class="net.shibboleth.idp.cas.config.impl.ConfigLookupFunction" scope="prototype"
           c:clazz="net.shibboleth.idp.cas.config.impl.LoginConfiguration" />
 
     <bean id="SubjectContextLookup"
-          class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+          class="org.opensaml.messaging.context.navigate.ChildContextLookup" scope="prototype"
           c:type="net.shibboleth.idp.authn.context.SubjectContext" />
 
     <bean id="PopulatePostAuthnInterceptContext"
-          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext"
-          scope="prototype"
+          class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
           p:availableFlows-ref="shibboleth.AvailableInterceptFlows">
         <property name="activeFlowsLookupStrategy">
             <bean class="net.shibboleth.idp.authn.config.navigate.PostAuthenticationFlowsLookupFunction" />
@@ -77,4 +73,5 @@
         </constructor-arg>
         <constructor-arg name="f" ref="SessionContextLookup" />
     </bean>
+    
 </beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/proxy/proxy-beans.xml b/idp-conf/src/main/resources/system/flows/cas/proxy/proxy-beans.xml
index 0cfb86a..8c7290f 100644
--- a/idp-conf/src/main/resources/system/flows/cas/proxy/proxy-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/proxy/proxy-beans.xml
@@ -10,17 +10,17 @@
 
     <!-- Action beans -->
     <bean id="InitializeProfileRequestContext"
-          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext"
+          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext" scope="prototype"
           p:profileId="#{T(net.shibboleth.idp.cas.config.impl.ProxyConfiguration).PROFILE_ID}"
           p:loggingId="%{idp.service.logging.cas:SSO}"
           p:browserProfile="false" />
 
     <bean id="InitializeProxy"
-          class="net.shibboleth.idp.cas.flow.impl.InitializeProxyAction"
+          class="net.shibboleth.idp.cas.flow.impl.InitializeProxyAction" scope="prototype"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
 
     <bean id="GrantProxyTicket"
-          class="net.shibboleth.idp.cas.flow.impl.GrantProxyTicketAction"
+          class="net.shibboleth.idp.cas.flow.impl.GrantProxyTicketAction" scope="prototype"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}"
           c:resolver-ref="shibboleth.SessionManager"
           p:validateIdPSessionPredicate="#{getObject('shibboleth.CASProxyValidateIdPSessionPredicate') ?: getObject('shibboleth.DefaultCASProxyValidateIdPSessionPredicate')}" />
@@ -30,4 +30,5 @@
 
     <!-- Supplementary beans -->
     <bean id="PrincipalLookupFunction" class="net.shibboleth.idp.cas.ticket.TicketPrincipalLookupFunction" />
+    
 </beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/proxyValidate/proxyValidate-beans.xml b/idp-conf/src/main/resources/system/flows/cas/proxyValidate/proxyValidate-beans.xml
index 31e8729..2d5f04e 100644
--- a/idp-conf/src/main/resources/system/flows/cas/proxyValidate/proxyValidate-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/proxyValidate/proxyValidate-beans.xml
@@ -9,7 +9,7 @@
 
     <!-- Action beans -->
     <bean id="BuildProxyChain"
-          class="net.shibboleth.idp.cas.flow.impl.BuildProxyChainAction"
+          class="net.shibboleth.idp.cas.flow.impl.BuildProxyChainAction" scope="prototype"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
 
 </beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-beans.xml b/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-beans.xml
index 5caa20b..d2f0278 100644
--- a/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-beans.xml
@@ -9,41 +9,35 @@
        default-init-method="initialize">
 
     <bean id="DecodeMessage"
-          class="org.opensaml.profile.action.impl.DecodeMessage"
-          scope="prototype"
+          class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype"
           c:messageDecoder-ref="SoapDecoder" />
 
     <bean id="SoapDecoder" 
-          class="org.opensaml.saml.saml1.binding.decoding.impl.HTTPSOAP11Decoder"
-          scope="prototype"
+          class="org.opensaml.saml.saml1.binding.decoding.impl.HTTPSOAP11Decoder" scope="prototype"
           p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
 
     <bean id="ProcessSamlMessage"
-          class="net.shibboleth.idp.cas.flow.impl.ProcessSamlMessageAction"
-          scope="prototype" />
+          class="net.shibboleth.idp.cas.flow.impl.ProcessSamlMessageAction" scope="prototype" />
 
     <bean id="BuildSamlValidationSuccessMessage" 
-          class="net.shibboleth.idp.cas.flow.impl.BuildSamlValidationSuccessMessageAction"
-          scope="prototype"
+          class="net.shibboleth.idp.cas.flow.impl.BuildSamlValidationSuccessMessageAction" scope="prototype"
           c:strategy-ref="shibboleth.DefaultIdentifierGenerationStrategy"
           c:id="%{idp.entityID}"
           p:outgoingBinding-ref="shibboleth.Binding.SAML1SOAP" />
 
     <bean id="BuildSamlValidationFailureMessage"
-          class="net.shibboleth.idp.cas.flow.impl.BuildSamlValidationFailureMessageAction"
-          scope="prototype"
+          class="net.shibboleth.idp.cas.flow.impl.BuildSamlValidationFailureMessageAction" scope="prototype"
           p:outgoingBinding-ref="shibboleth.Binding.SAML1SOAP" />
 
     <bean id="MessageEncoderFactory"
-          class="net.shibboleth.idp.saml.profile.impl.SpringAwareMessageEncoderFactory" />
+          class="net.shibboleth.idp.saml.profile.impl.SpringAwareMessageEncoderFactory" scope="prototype" />
 
     <bean id="EncodeMessage"
-          class="org.opensaml.profile.action.impl.EncodeMessage"
-          scope="prototype"
+          class="org.opensaml.profile.action.impl.EncodeMessage" scope="prototype"
           p:messageEncoderFactory-ref="MessageEncoderFactory"
           p:messageHandler="#{getObject('shibboleth.BindingSpecificMessageHandler')}" />
 
    <bean id="RecordResponseComplete"
-          class="net.shibboleth.idp.profile.impl.RecordResponseComplete"
-          scope="prototype" />
+          class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
+          
 </beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
index a4a7c62..64163b1 100644
--- a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
@@ -10,7 +10,7 @@
 
     <!-- Action beans -->
     <bean id="InitializeProfileRequestContext"
-          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext"
+          class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext" scope="prototype"
           p:profileId="#{T(net.shibboleth.idp.cas.config.impl.ValidateConfiguration).PROFILE_ID}"
           p:loggingId="%{idp.service.logging.cas:SSO}"
           p:browserProfile="false" />
@@ -20,29 +20,29 @@
         p:metricStrategy="#{getObject('shibboleth.metrics.MetricStrategy')}" />
 
     <bean id="InitializeValidate"
-          class="net.shibboleth.idp.cas.flow.impl.InitializeValidateAction" />
+          class="net.shibboleth.idp.cas.flow.impl.InitializeValidateAction" scope="prototype" />
 
     <bean id="ValidateTicket"
-          class="net.shibboleth.idp.cas.flow.impl.ValidateTicketAction"
+          class="net.shibboleth.idp.cas.flow.impl.ValidateTicketAction" scope="prototype"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
 
     <bean id="ValidateRenew"
-          class="net.shibboleth.idp.cas.flow.impl.ValidateRenewAction" />
+          class="net.shibboleth.idp.cas.flow.impl.ValidateRenewAction" scope="prototype" />
 
     <bean id="CheckProxyAuthorization"
-          class="net.shibboleth.idp.cas.flow.impl.CheckProxyAuthorizationAction" />
+          class="net.shibboleth.idp.cas.flow.impl.CheckProxyAuthorizationAction" scope="prototype" />
 
     <bean id="ValidateProxyCallback"
-          class="net.shibboleth.idp.cas.flow.impl.ValidateProxyCallbackAction"
+          class="net.shibboleth.idp.cas.flow.impl.ValidateProxyCallbackAction" scope="prototype"
           c:proxyAuthenticator="#{getObject('shibboleth.CASProxyAuthenticator') ?: getObject('shibboleth.DefaultCASProxyAuthenticator')}"
           c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
 
     <bean id="PrepareTicketValidationResponse"
-          class="net.shibboleth.idp.cas.flow.impl.PrepareTicketValidationResponseAction"
+          class="net.shibboleth.idp.cas.flow.impl.PrepareTicketValidationResponseAction" scope="prototype"
           p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
 
     <bean id="UpdateIdPSessionWithSPSession"
-          class="net.shibboleth.idp.cas.flow.impl.UpdateIdPSessionWithSPSessionAction"
+          class="net.shibboleth.idp.cas.flow.impl.UpdateIdPSessionWithSPSessionAction" scope="prototype"
           c:lifetime="%{idp.session.defaultSPlifetime:PT2H}"
           c:resolver-ref="shibboleth.SessionManager" />
 
@@ -55,4 +55,5 @@
 
     <!-- Supplementary beans -->
     <bean id="PrincipalLookupFunction" class="net.shibboleth.idp.cas.ticket.TicketPrincipalLookupFunction" />
+    
 </beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/validate/validate-beans.xml b/idp-conf/src/main/resources/system/flows/cas/validate/validate-beans.xml
index 5faedfe..8829027 100644
--- a/idp-conf/src/main/resources/system/flows/cas/validate/validate-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/validate/validate-beans.xml
@@ -2,21 +2,23 @@
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd"
        default-init-method="initialize">
 
     <bean id="WriteValidateSuccess"
-          class="net.shibboleth.idp.cas.flow.impl.WriteValidateResponseAction"
-          c:successFlag="true" />
+          class="net.shibboleth.idp.cas.flow.impl.WriteValidateResponseAction" scope="prototype"
+          c:successFlag="true"
+          p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
 
     <bean id="WriteValidateFailure"
-          class="net.shibboleth.idp.cas.flow.impl.WriteValidateResponseAction"
-          c:successFlag="false" />
+          class="net.shibboleth.idp.cas.flow.impl.WriteValidateResponseAction" scope="prototype"
+          c:successFlag="false"
+          p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
 
     <bean id="RecordResponseComplete"
-          class="net.shibboleth.idp.profile.impl.RecordResponseComplete"
-          scope="prototype" />
+          class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
 
 </beans>
\ No newline at end of file

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


More information about the commits mailing list