/** {@inheritDoc} */ @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) { final AuthenticationContext authnCtx = new AuthenticationContext(); if (authnRequest != null) { authnCtx.setForceAuthn(authnRequest.isForceAuthn()); authnCtx.setIsPassive(authnRequest.isPassive()); } final AuthenticationContext initialAuthnContext = profileRequestContext.getSubcontext(AuthenticationContext.class); if (initialAuthnContext != null) { authnCtx.setInitialAuthenticationResult(initialAuthnContext.getAuthenticationResult()); } if (!authnCtx.isForceAuthn()) { authnCtx.setForceAuthn(forceAuthnPredicate.apply(profileRequestContext)); } profileRequestContext.addSubcontext(authnCtx, true); log.debug("{} Created authentication context: {}", getLogPrefix(), authnCtx); }
/** * Navigate to the {@link SPNEGOContext} in the context tree. * * @param prc profile request context * * @return the child context, or null */ @Nullable private SPNEGOContext getSPNEGOContext(@Nonnull final ProfileRequestContext prc) { final AuthenticationContext authnContext = prc.getSubcontext(AuthenticationContext.class); return authnContext != null ? authnContext.getSubcontext(SPNEGOContext.class) : null; }
/** * Update an existing session. * * <p>If the result is the product of an attempted flow, then it's added to the session. * If reused, its last activity time is updated.</p> * * @param authenticationContext current authentication context * @param session session to update * @throws SessionException if an error occurs updating the session */ private void updateIdPSession(@Nonnull final AuthenticationContext authenticationContext, @Nonnull final IdPSession session) throws SessionException { if (authenticationContext.getAttemptedFlow() != null) { if (authenticationContext.isResultCacheable()) { log.debug("{} Adding new AuthenticationResult for flow {} to existing session {}", getLogPrefix(), authenticationContext.getAuthenticationResult().getAuthenticationFlowId(), session.getId()); session.addAuthenticationResult(authenticationContext.getAuthenticationResult()); } } else { log.debug("{} Updating activity time on reused AuthenticationResult for flow {} in existing session {}", getLogPrefix(), authenticationContext.getAuthenticationResult().getAuthenticationFlowId(), session.getId()); session.updateAuthenticationResultActivity(authenticationContext.getAuthenticationResult()); } }
/** {@inheritDoc} */ @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final AuthenticationContext authenticationContext) { if (!authenticationContext.isForceAuthn() && authenticationContext.getMaxAge() == 0) { log.debug("{} Request does not have forced authentication requirement, nothing to do", getLogPrefix()); return false; } return super.doPreExecute(profileRequestContext, authenticationContext); }
/** * Get whether one or more of the active results in this context satisfies the request. * * @return true iff at least one of the active results satisfies the request */ public boolean isAcceptable() { final AuthenticationContext authnContext = (AuthenticationContext) getParent(); if (authnContext != null) { for (final AuthenticationResult result : activeResults.values()) { // Only include Principals from fresh results or when forced authn is off. if (!(authnContext.isForceAuthn() && result.isPreviousResult())) { if (authnContext.isAcceptable(result)) { return true; } } } } return false; }
/** {@inheritDoc} */ @Override @Nullable public Boolean apply(@Nullable final AuthenticationContext input) { if (input != null && input.getAuthenticationResult() != null) { return input.getAuthenticationResult().isPreviousResult(); } else { return null; } }
LOG.debug("Found an authentication context in the profile request context"); final RequestedPrincipalContext principalContext = authCtx.getSubcontext(RequestedPrincipalContext.class); if (principalContext != null && principalContext.getMatchingPrincipal() != null) { LOG.debug("Found requested principal context context with matching principal {}", authorities.add(new SimpleGrantedAuthority(authority.toString())); if (authCtx.getAuthenticationResult() != null) { final AuthenticationMethodRefAuthority authority = new AuthenticationMethodRefAuthority( authCtx.getAuthenticationResult().getAuthenticationFlowId()); LOG.debug("Adding authority {}", authority.getAuthority()); authorities.add(new SimpleGrantedAuthority(authority.toString()));
if (authenticationContext.getInitialAuthenticationResult() != null && authenticationContext.getPotentialFlows().containsKey( authenticationContext.getInitialAuthenticationResult().getAuthenticationFlowId())) { authenticationContext.getInitialAuthenticationResult().getAuthenticationFlowId(), authenticationContext.getInitialAuthenticationResult())); } else if (authenticationContext.isForceAuthn()) { log.debug("{} Forced authentication requested, selecting an inactive flow", getLogPrefix()); selectRequestedInactiveFlow(profileRequestContext, authenticationContext); } else if (authenticationContext.getActiveResults().isEmpty()) { log.debug("{} No active results available, selecting an inactive flow", getLogPrefix()); selectRequestedInactiveFlow(profileRequestContext, authenticationContext); } else { selectRequestedFlow(profileRequestContext, authenticationContext, authenticationContext.getActiveResults());
final AuthenticationFlowDescriptor flow = authenticationContext.getPotentialFlows().get( authenticationContext.getSignaledFlowId()); if (flow == null) { log.error("{} Signaled flow {} is not available", getLogPrefix(), authenticationContext.getSignaledFlowId()); ActionSupport.buildEvent(profileRequestContext, authenticationContext.isPassive() ? AuthnEventIds.NO_PASSIVE : AuthnEventIds.NO_POTENTIAL_FLOW); authenticationContext.setSignaledFlowId(null); return; authenticationContext.setSignaledFlowId(null); if (!authenticationContext.isForceAuthn() && flow.getReuseCondition().apply(profileRequestContext)) { activeResult = authenticationContext.getActiveResults().get(flow.getId()); } else if (authenticationContext.getInitialAuthenticationResult() != null && authenticationContext.getInitialAuthenticationResult().getAuthenticationFlowId().equals( flow.getId())) { activeResult = authenticationContext.getInitialAuthenticationResult(); } else { activeResult = null; if (authenticationContext.isPassive() && !flow.isPassiveAuthenticationSupported()) { log.error("{} Signaled flow {} does not support passive authentication", getLogPrefix(), flow.getId()); ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_PASSIVE); authenticationContext.isPassive() ? AuthnEventIds.NO_PASSIVE : AuthnEventIds.NO_POTENTIAL_FLOW);
/** {@inheritDoc} */ @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final AuthenticationContext authenticationContext) { if (!super.doPreExecute(profileRequestContext, authenticationContext)) { return false; } if (authenticationContext.getAttemptedFlow() == null) { log.debug("{} No attempted flow within authentication context", getLogPrefix()); ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX); recordFailure(); return false; } extContext = authenticationContext.getSubcontext(ExternalAuthenticationContext.class); if (extContext == null) { log.debug("{} No ExternalAuthenticationContext available within authentication context", getLogPrefix()); ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX); recordFailure(); return false; } return true; }
@Nonnull final ProfileRequestContext profileRequestContext) { log.debug("{} Building authentication context", getLogPrefix()); final AuthenticationContext ac = new AuthenticationContext(); ac.setForceAuthn(authZContext.isForceAuthentication()); if (ac.isForceAuthn()) { log.debug("Authentication context requires force authN for {}", authorizationRequest.getClientId());
@Nonnull final AuthenticationContext authenticationContext) { if (addDefaultPrincipals && authenticationContext.getAttemptedFlow() != null) { log.debug("{} Adding custom Principal(s) defined on underlying flow descriptor", getLogPrefix()); getSubject().getPrincipals().addAll( authenticationContext.getAttemptedFlow().getSupportedPrincipals()); final AuthenticationResult result = new AuthenticationResult(authenticationContext.getAttemptedFlow().getId(), populateSubject(getSubject())); authenticationContext.setAuthenticationResult(result); if (authenticationContext.isResultCacheable() && resultCachingPredicate != null) { authenticationContext.setResultCacheable(resultCachingPredicate.apply(profileRequestContext)); log.info("{} Predicate indicates authentication result {} be cacheable in a session", getLogPrefix(), authenticationContext.isResultCacheable() ? "will" : "will not");
/** * Create a new session and populate the SessionContext. * * @param authenticationContext current authentication context * @throws SessionException if an error occurs creating the session */ private void createIdPSession(@Nonnull final AuthenticationContext authenticationContext) throws SessionException { log.debug("{} Creating new session for principal {}", getLogPrefix(), subjectCtx.getPrincipalName()); sessionCtx.setIdPSession(sessionManager.createSession(subjectCtx.getPrincipalName())); if (authenticationContext.isResultCacheable()) { sessionCtx.getIdPSession().addAuthenticationResult(authenticationContext.getAuthenticationResult()); } } }
/** {@inheritDoc} */ @SuppressWarnings("deprecation") @Override protected void doStart(@Nonnull final HttpServletRequest request) throws ExternalAuthenticationException { final AuthenticationContext authnContext = profileRequestContext.getSubcontext(AuthenticationContext.class); if (authnContext == null) { throw new ExternalAuthenticationException("No AuthenticationContext found"); } else if (authnContext.getAttemptedFlow() == null) { throw new ExternalAuthenticationException("No attempted authentication flow set"); } request.setAttribute(ProfileRequestContext.BINDING_KEY, profileRequestContext); request.setAttribute(EXTENDED_FLOW_PARAM, extendedFlow); request.setAttribute(PASSIVE_AUTHN_PARAM, authnContext.isPassive()); request.setAttribute(FORCE_AUTHN_PARAM, authnContext.isForceAuthn()); final Collection<Principal> principals = authnContext.getAttemptedFlow().getSupportedPrincipals(); if (!principals.isEmpty()) { request.setAttribute(AUTHN_METHOD_PARAM, principals.iterator().next().getName()); } final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext); if (rpCtx != null) { request.setAttribute(RELYING_PARTY_PARAM, rpCtx.getRelyingPartyId()); } }
final AuthenticationFlowDescriptor flow = authenticationContext.getAvailableFlows().get(flowId); if (flow == null) { log.error("{} Targeted login flow '{}' is not configured, check available flow descriptors", getLogPrefix(), flowId); ActionSupport.buildEvent(profileRequestContext, authenticationContext.isPassive() ? AuthnEventIds.NO_PASSIVE : AuthnEventIds.NO_POTENTIAL_FLOW); return; if (authenticationContext.isPassive() && !flow.isPassiveAuthenticationSupported()) { log.error("{} Targeted login flow '{}' does not support passive authentication", getLogPrefix(), flowId); ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_PASSIVE); return; } else if ((authenticationContext.isForceAuthn() || authenticationContext.getMaxAge() > 0) && !flow.isForcedAuthenticationSupported()) { log.error("{} Targeted login flow '{}' does not support forced re-authentication", log.error("{} Targeted login flow '{}' does not support non-browser authentication", getLogPrefix(), flowId); ActionSupport.buildEvent(profileRequestContext, authenticationContext.isPassive() ? AuthnEventIds.NO_PASSIVE : AuthnEventIds.REQUEST_UNSUPPORTED); return; authenticationContext.setAttemptedFlow(flow); ActionSupport.buildProceedEvent(profileRequestContext);
authenticationContext.setAttemptedFlow(mfaContext.getAuthenticationFlowDescriptor()); final AuthenticationResult result = authenticationContext.getAuthenticationResult(); if (result != null) { if (EventIds.PROCEED_EVENT_ID.equals(previousEvent)) { result.getAuthenticationFlowId()); authenticationContext.setAuthenticationResult(null);
/** * Add (or replace) a {@link RequestedPrincipalContext} as a child of this context using the * supplied parameters and the previously established {@link PrincipalEvalPredicateFactoryRegistry} * for comparison handling. * * @param operator matching operator * @param principals principals to request * @param replace whether to replace an existing context or simply return false * * @return true iff a new context was created */ public boolean addRequestedPrincipalContext(@Nonnull @NotEmpty final String operator, @Nonnull @NonnullElements final List<Principal> principals, final boolean replace) { RequestedPrincipalContext rpCtx = getSubcontext(RequestedPrincipalContext.class); if (rpCtx != null && !replace) { return false; } rpCtx = new RequestedPrincipalContext(); rpCtx.setOperator(operator) .setPrincipalEvalPredicateFactoryRegistry(evalRegistry) .setRequestedPrincipals(principals); addSubcontext(rpCtx, true); return true; }
if (ac != null && ac.getAttemptedFlow() != null) { final AuthenticationResult mfaResult = ac.getActiveResults().get(ac.getAttemptedFlow().getId()); if (mfaResult != null) { if (ac.isForceAuthn()) { log.debug("{} Ignoring active result due to forced authentication requirement", getLogPrefix());
/** {@inheritDoc} */ @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final AuthenticationContext authenticationContext) { if (canonicalPrincipalName != null) { final SubjectContext sc = profileRequestContext.getSubcontext(SubjectContext.class, true); // Check for an existing value. if (sc.getPrincipalName() != null && !canonicalPrincipalName.equals(sc.getPrincipalName())) { log.warn("{} Result of authentication ({}) does not match existing subject in context ({})", getLogPrefix(), canonicalPrincipalName, sc.getPrincipalName()); ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_SUBJECT_CTX); return; } sc.setPrincipalName(canonicalPrincipalName); final Map scResults = sc.getAuthenticationResults(); scResults.putAll(authenticationContext.getActiveResults()); final AuthenticationResult latest = authenticationContext.getAuthenticationResult(); if (latest != null && !scResults.containsKey(latest.getAuthenticationFlowId())) { scResults.put(latest.getAuthenticationFlowId(), latest); } } authenticationContext.setCompletionInstant(); }
authenticationContext.setPrincipalEvalPredicateFactoryRegistry(evalRegistry); final RequestedPrincipalContext rpCtx = authenticationContext.getSubcontext(RequestedPrincipalContext.class); if (rpCtx != null) { rpCtx.setPrincipalEvalPredicateFactoryRegistry(evalRegistry); authenticationContext.setFixedEventLookupStrategy(fixedEventLookupStrategy); authenticationContext.getAvailableFlows().put(desc.getId(), desc); final String flowId = desc.getId().substring(desc.getId().indexOf('/') + 1); if (activeFlows.contains(flowId)) { if (authenticationContext.getAvailableFlows().containsKey(desc.getId()) && desc.apply(profileRequestContext)) { authenticationContext.getPotentialFlows().put(desc.getId(), desc); } else { log.debug("{} Filtered out authentication flow {}", getLogPrefix(), desc.getId()); if (authenticationContext.getAvailableFlows().containsKey(desc.getId()) && desc.apply(profileRequestContext)) { authenticationContext.getPotentialFlows().put(desc.getId(), desc); } else { log.debug("{} Filtered out authentication flow {}", getLogPrefix(), desc.getId()); if (authenticationContext.getPotentialFlows().isEmpty()) { log.warn("{} No authentication flows are active for this request", getLogPrefix()); } else { log.debug("{} Installed {} potential authentication flows into AuthenticationContext", getLogPrefix(), authenticationContext.getPotentialFlows().size());