Hmm, I was apparently wrong, about Hazelcast not working originally. Further experimentation seems to indicate otherwise, though I'm still somewhat confused as to what's happening.
Unlike CAS 5.0.x, after I create a TGT on the source node (e.g. node1), I don't see it being logged on the other Hazelcast nodes (node2). However if I then shut down node1 and reload /cas/login, the UI reports "Credentials are rejected/invalid and authentication attempt has failed." above the Duo MFA iframe. But in node2's log, I then see:
DEBUG [org.apereo.cas.ticket.registry.AbstractTicketRegistry] - <Encoded original ticket id [TGT-1-*****IJZpAj5I8s-node1] to [812...265]>
So the TGT from node1 does in fact appear to be available to node2.
If I continue with the Duo authentication, it succeeds. despite the confusing user experience. But here the logs/flow also confuse me further.
ERROR [org.apereo.cas.adaptors.duo.authn.DuoSecurityAuthenticationHandler] - <Transaction has expired. Please check that the system time is correct.>
com.duosecurity.duoweb.DuoWebException: Transaction has expired. Please check that the system time is correct.
INFO [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <[mfa-duo] exception details: [Transaction has expired. Please check that the system time is correct.].>
ERROR [org.apereo.cas.web.flow.resolver.impl.AbstractCasWebflowEventResolver] - <1 errors, 0 successes>
org.apereo.cas.authentication.AuthenticationException: 1 errors, 0 successes
...
DEBUG [org.apereo.cas.web.flow.actions.MultifactorAuthenticationBypassAction] - <Bypass rules determined MFA should execute for user [baron] and provider [mfa-duo]>
DEBUG [org.apereo.cas.web.flow.actions.MultifactorAuthenticationBypassAction] - <Authentication updated to forget any existing bypass for user [baron] for provider [mfa-duo]>
DEBUG [org.apereo.cas.util.http.SimpleHttpClient] - <Response code received from server matched [200].>
DEBUG [org.apereo.cas.adaptors.duo.authn.BasicDuoSecurityAuthenticationService] - <Received Duo ping response [{"response": "pong", "stat": "OK"}]>
2021-06-14 15:36:08,570 DEBUG [org.apereo.cas.adaptors.duo.authn.BaseDuoSecurityAuthenticationService] - <Contacting Duo to inquire about username [baron]>
2021-06-14 15:36:09,103 DEBUG [org.apereo.cas.adaptors.duo.authn.BaseDuoSecurityAuthenticationService] - <Received Duo admin response [{"code": 40301, "message": "Access forbidden", "message_detail": "Wrong integration type for this API.", "stat": "FAIL"}]>
2021-06-14 15:36:09,106 WARN [org.apereo.cas.adaptors.duo.authn.BaseDuoSecurityAuthenticationService] - <Duo returned an Invalid response with message [Access forbidden] and detail [Wrong integration type for this API.] when determining user account. This maybe a configuration error in the admin request and Duo will still be considered available.>
2021-06-14 15:36:09,113 DEBUG [org.apereo.cas.adaptors.duo.authn.BaseDuoSecurityAuthenticationService] - <Fetched and cached duo user account [DuoSecurityUserAccount(status=AUTH, enrollPortalUrl=null, username=baron, message=null)]>
2021-06-14 15:36:09,113 DEBUG [org.apereo.cas.web.flow.actions.CheckWebAuthenticationRequestAction] - <Authenticated request is identified as web-based via type [application/x-www-form-urlencoded]>
[then this gets recorded as a login failure]
DEBUG [org.apereo.cas.web.support.AbstractThrottledSubmissionHandlerInterceptorAdapter] - <Recording submission failure for [/cas/login]>
DEBUG [org.apereo.cas.web.support.AbstractInMemoryThrottledSubmissionHandlerInterceptorAdapter] - <Recording submission failure [10.11.12.13]>
[Then it tries the TGT again from Hazelcast?]
DEBUG [org.apereo.cas.ticket.registry.AbstractTicketRegistry] - <Encoded original ticket id [TGT-1-*****IJZpAj5I8s-node1] to [812...265]>
DEBUG [org.apereo.cas.ticket.registry.HazelcastTicketRegistry] - <Locating map name [ticketGrantingTicketsCache] for ticket definition [DefaultTicketDefinition(implementationClass=class org.apereo.cas.ticket.TicketGrantingTicketImpl, prefix=TGT, properties=DefaultTicketDefinitionProperties(cascadeRemovals=false, storageName=ticketGrantingTicketsCache,,storageTimeout=28800, storagePassword=null, excludeFromCascade=false), order=
2147483647)]>
DEBUG [org.apereo.cas.ticket.registry.HazelcastTicketRegistry] - <Located Hazelcast map instance [ticketGrantingTicketsCache]>
WARN [org.apereo.cas.ticket.registry.AbstractTicketRegistry] - <Ticket passed is null and cannot be decoded>
[Then it appears to try for an authentication method based on the Duo MFA?]
DEBUG [org.apereo.cas.web.flow.resolver.impl.AbstractCasWebflowEventResolver] - <Handling authentication transaction for credential [DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authentication credentials provided for this transaction are [[DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Candidate/Registered authentication handlers for this transaction are [[org.apereo.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler, org.apereo.cas.authentication.LdapAuthenticationHandler, org.apereo.cas.adaptors.duo.authn.DuoSecurityAuthenticationHandler]]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Authentication handler resolvers for this transaction are [[org.apereo.cas.authentication.handler.ByCredentialTypeAuthenticationHandlerResolver, org.apereo.cas.authentication.handler.RegisteredServiceAuthenticationHandlerResolver]]>
DEBUG [org.apereo.cas.authentication.AuthenticationHandlerResolver] - <Default authentication handlers used for this transaction are [HttpBasedServiceCredentialsAuthenticationHandler,LdapAuthenticationHandler,mfa-duo]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Resolved and finalized authentication handlers to carry out this authentication transaction are [[org.apereo.cas.authentication.handler.ByCredentialTypeAuthenticationHandlerResolver, org.apereo.cas.authentication.handler.RegisteredServiceAuthenticationHandlerResolver]]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Candidate resolved authentication handlers for this transaction are [[...HttpBasedServiceCredentialsAuthenticationHandler, ...LdapAuthenticationHandler, ...DuoSecurityAuthenticationHandler]]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Attempting to authenticate credential [DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authentication handler [HttpBasedServiceCredentialsAuthenticationHandler] does not support the credential type [DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]. Trying next...>
2021-06-14 15:38:31,709 DEBUG [org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler] - <Credential is not one of username/password and is not accepted by handler [LdapAuthenticationHandler]>
2021-06-14 15:38:31,709 DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authentication handler [LdapAuthenticationHandler] does not support the credential type [DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]. Trying next...>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Attempting authentication of [baron] using [mfa-duo]>
DEBUG [org.apereo.cas.adaptors.duo.authn.DuoSecurityAuthenticationHandler] - <Verified Duo authentication for user [baron]>
INFO [org.apereo.cas.adaptors.duo.authn.DuoSecurityAuthenticationHandler] - <Successful Duo authentication for [baron]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authentication handler [mfa-duo] successfully authenticated [DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Final principal resolved for this authentication event is [SimplePrincipal(id=baron, attributes={})]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Authentication policy resolvers for this transaction are [[org.apereo.cas.authentication.policy.RegisteredServiceAuthenticationPolicyResolver]]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Authentication policy resolvers produced no candidate authentication handler. Using default policies>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Executing authentication policy [AtLeastOneCredentialValidatedAuthenticationPolicy]>
DEBUG [org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler] - <Credential is not one of username/password and is not accepted by handler [LdapAuthenticationHandler]>
DEBUG [org.apereo.cas.authentication.policy.AtLeastOneCredentialValidatedAuthenticationPolicy] - <Authentication policy is satisfied having found at least one authentication transactions>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Authentication policy resolvers for this transaction are [[org.apereo.cas.authentication.policy.RegisteredServiceAuthenticationPolicyResolver]]>
DEBUG [org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan] - <Authentication policy resolvers produced no candidate authentication handler. Using default policies>
DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Executing authentication policy [AtLeastOneCredentialValidatedAuthenticationPolicy]>
DEBUG [org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler] - <Credential is not one of username/password and is not accepted by handler [LdapAuthenticationHandler]>
DEBUG [org.apereo.cas.authentication.policy.AtLeastOneCredentialValidatedAuthenticationPolicy] - <Authentication policy is satisfied having found at least one authentication transactions>
[Which appears to result in a successful authentication]
INFO [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authenticated principal [baron] with attributes [{}] via credentials [[DuoSecurityCredential(username=baron, signedDuoResponse=AUTH|YmF...Q==|14...5b, providerId=mfa-duo-1...)]].>
DEBUG [org.apereo.cas.web.flow.resolver.impl.AbstractCasWebflowEventResolver] - <Issuing ticket-granting tickets for service [null]>
DEBUG [org.apereo.cas.web.flow.resolver.impl.AbstractCasWebflowEventResolver] - <Resolved single event [success] via [org.apereo.cas.adaptors.duo.web.flow.DuoSecurityAuthenticationWebflowEventResolver] for this context>
But does this suggest it would have failed if not for the Duo MFA? Since the MFA is opt-in for our users, this is presumably a problem.
The WARNing "Ticket passed is null and cannot be decoded" is troubling and seems like it should not have failed?