import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import edu.internet2.middleware.shibboleth.common.session.SessionManager;
import edu.internet2.middleware.shibboleth.common.util.HttpHelper;
+import edu.internet2.middleware.shibboleth.idp.authn.provider.PreviousSessionLoginHandler;
import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
if (!loginContext.getAuthenticationAttempted()) {
startUserAuthentication(loginContext, httpRequest, httpResponse);
} else {
- completeAuthenticationWithoutActiveMethod(loginContext, httpRequest, httpResponse);
+ completeAuthentication(loginContext, httpRequest, httpResponse);
}
}
HttpServletResponse httpResponse) {
LOG.debug("Beginning user authentication process");
try {
- Map<String, LoginHandler> possibleLoginHandlers = determinePossibleLoginHandlers(loginContext);
- ArrayList<AuthenticationMethodInformation> activeAuthnMethods = new ArrayList<AuthenticationMethodInformation>();
-
- Session userSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
- if (userSession != null) {
- activeAuthnMethods.addAll(userSession.getAuthenticationMethods().values());
+ Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+ if(idpSession != null){
+ LOG.debug("Existing IdP session available for principal {}", idpSession.getPrincipalName());
}
+
+ Map<String, LoginHandler> possibleLoginHandlers = determinePossibleLoginHandlers(loginContext);
+ LOG.debug("Possible authentication handlers for this request: {}", possibleLoginHandlers);
+ // Filter out possible candidate login handlers by forced and passive authentication requirements
if (loginContext.isForceAuthRequired()) {
- LOG.debug("Forced authentication is required, filtering possible login handlers accordingly");
- filterByForceAuthentication(loginContext, activeAuthnMethods, possibleLoginHandlers);
- } else {
- LOG.debug("Forced authentication not required, trying existing authentication methods");
- for (AuthenticationMethodInformation activeAuthnMethod : activeAuthnMethods) {
- if (possibleLoginHandlers.containsKey(activeAuthnMethod.getAuthenticationMethod())) {
- completeAuthenticationWithActiveMethod(loginContext, activeAuthnMethod, httpRequest,
- httpResponse);
- return;
- }
- }
- LOG.debug("No existing authentication method meets service provides requirements");
+ filterByForceAuthentication(idpSession, loginContext, possibleLoginHandlers);
}
if (loginContext.isPassiveAuthRequired()) {
- LOG.debug("Passive authentication is required, filtering poassibl login handlers accordingly.");
filterByPassiveAuthentication(loginContext, possibleLoginHandlers);
}
-
- // Since we made it this far, just pick the first remaining login handler from the list
- Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
- LOG.debug("Authenticating user with login handler of type {}", chosenLoginHandler.getValue().getClass()
- .getName());
- authenticateUser(chosenLoginHandler.getKey(), chosenLoginHandler.getValue(), loginContext, httpRequest,
- httpResponse);
+
+ // If the user already has a session and its usage is acceptable than use it
+ // otherwise just use the first candidate login handler
+ LOG.debug("Possible authentication handlers after filtering: {}", possibleLoginHandlers);
+ if (idpSession != null
+ && possibleLoginHandlers.containsKey(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD)) {
+ authenticateUserWithPreviousSession(loginContext, possibleLoginHandlers, httpRequest, httpResponse);
+ } else {
+ Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
+ authenticateUser(chosenLoginHandler.getKey(), chosenLoginHandler.getValue(), loginContext, httpRequest,
+ httpResponse);
+ }
} catch (AuthenticationException e) {
loginContext.setAuthenticationFailure(e);
returnToProfileHandler(loginContext, httpRequest, httpResponse);
}
-
}
/**
Entry<String, LoginHandler> supportedLoginHandler;
while (supportedLoginHandlerItr.hasNext()) {
supportedLoginHandler = supportedLoginHandlerItr.next();
- if (!loginContext.getRequestedAuthenticationMethods().contains(supportedLoginHandler.getKey())) {
+ if (!(supportedLoginHandler.getKey().equals(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD))
+ && !loginContext.getRequestedAuthenticationMethods().contains(supportedLoginHandler.getKey())) {
supportedLoginHandlerItr.remove();
continue;
}
/**
* Filters out any login handler based on the requirement for forced authentication.
*
- * During forced authentication any handler that has not previously been used to authenticate the the user or any
+ * During forced authentication any handler that has not previously been used to authenticate the user or any
* handlers that have been and support force re-authentication may be used. Filter out any of the other ones.
*
+ * @param idpSession user's current IdP session
* @param loginContext current login context
- * @param activeAuthnMethods currently active authentication methods, never null
* @param loginHandlers login handlers to filter
*
* @throws ForceAuthenticationException thrown if no handlers remain after filtering
*/
- protected void filterByForceAuthentication(LoginContext loginContext,
- Collection<AuthenticationMethodInformation> activeAuthnMethods, Map<String, LoginHandler> loginHandlers)
- throws ForceAuthenticationException {
+ protected void filterByForceAuthentication(Session idpSession, LoginContext loginContext,
+ Map<String, LoginHandler> loginHandlers) throws ForceAuthenticationException {
+ LOG.debug("Forced authentication is required, filtering possible login handlers accordingly");
+
+ ArrayList<AuthenticationMethodInformation> activeMethods = new ArrayList<AuthenticationMethodInformation>();
+ if (idpSession != null) {
+ activeMethods.addAll(idpSession.getAuthenticationMethods().values());
+ }
LoginHandler loginHandler;
- for (AuthenticationMethodInformation activeAuthnMethod : activeAuthnMethods) {
- loginHandler = loginHandlers.get(activeAuthnMethod.getAuthenticationMethod());
+ for (AuthenticationMethodInformation activeMethod : activeMethods) {
+ loginHandler = loginHandlers.get(activeMethod.getAuthenticationMethod());
if (loginHandler != null && !loginHandler.supportsForceAuthentication()) {
for (String handlerSupportedMethods : loginHandler.getSupportedAuthenticationMethods()) {
loginHandlers.remove(handlerSupportedMethods);
}
}
}
+
+ LOG.debug("Authentication handlers remaining after forced authentication requirement filtering: {}",
+ loginHandlers);
if (loginHandlers.isEmpty()) {
LOG.error("Force authentication required but no login handlers available to support it");
*/
protected void filterByPassiveAuthentication(LoginContext loginContext, Map<String, LoginHandler> loginHandlers)
throws PassiveAuthenticationException {
+ LOG.debug("Passive authentication is required, filtering poassible login handlers accordingly.");
+
LoginHandler loginHandler;
Iterator<Entry<String, LoginHandler>> authnMethodItr = loginHandlers.entrySet().iterator();
while (authnMethodItr.hasNext()) {
authnMethodItr.remove();
}
}
+
+ LOG.debug("Authentication handlers remaining after passive authentication requirement filtering: {}",
+ loginHandlers);
if (loginHandlers.isEmpty()) {
LOG.error("Passive authentication required but no login handlers available to support it");
}
/**
- * Authenticates the user with the given authentication method provided by the given login handler.
+ * Completes the authentication request using an existing, active, authentication method for the current user.
*
- * @param authnMethod the authentication method that will be used to authenticate the user
- * @param logingHandler login handler that will authenticate user
* @param loginContext current login context
+ * @param possibleLoginHandlers login handlers that meet the peers authentication requirements
* @param httpRequest current HTTP request
* @param httpResponse current HTTP response
*/
- protected void authenticateUser(String authnMethod, LoginHandler logingHandler, LoginContext loginContext,
- HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+ protected void authenticateUserWithPreviousSession(LoginContext loginContext,
+ Map<String, LoginHandler> possibleLoginHandlers, HttpServletRequest httpRequest,
+ HttpServletResponse httpResponse) {
+ LOG.debug("Authenticating user by way of existing session.");
+
+ Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+ PreviousSessionLoginHandler loginHandler = (PreviousSessionLoginHandler) handlerManager.getLoginHandlers().get(
+ PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD);
+
+ AuthenticationMethodInformation authenticationMethod = null;
+ for (String possibleAuthnMethod : possibleLoginHandlers.keySet()) {
+ authenticationMethod = idpSession.getAuthenticationMethods().get(possibleAuthnMethod);
+ if (authenticationMethod != null) {
+ break;
+ }
+ }
+
+ if (loginHandler.reportPreviousSessionAuthnMethod()) {
+ loginContext.setAuthenticationDuration(loginHandler.getAuthenticationDuration());
+ loginContext.setAuthenticationInstant(new DateTime());
+ loginContext.setAuthenticationMethod(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD);
+ } else {
+ loginContext.setAuthenticationDuration(authenticationMethod.getAuthenticationDuration());
+ loginContext.setAuthenticationInstant(authenticationMethod.getAuthenticationInstant());
+ loginContext.setAuthenticationMethod(authenticationMethod.getAuthenticationMethod());
+ }
+ loginContext.setPrincipalName(idpSession.getPrincipalName());
loginContext.setAuthenticationAttempted();
- loginContext.setAuthenticationDuration(logingHandler.getAuthenticationDuration());
- loginContext.setAuthenticationMethod(authnMethod);
- loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
httpRequest.getSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
- logingHandler.login(httpRequest, httpResponse);
+ loginHandler.login(httpRequest, httpResponse);
}
/**
- * Completes the authentication request using an existing, active, authentication method for the current user.
+ * Authenticates the user with the given authentication method provided by the given login handler.
*
+ * @param authnMethod the authentication method that will be used to authenticate the user
+ * @param loginHandler login handler that will authenticate user
* @param loginContext current login context
- * @param authenticationMethod authentication method to use to complete the request
* @param httpRequest current HTTP request
* @param httpResponse current HTTP response
*/
- protected void completeAuthenticationWithActiveMethod(LoginContext loginContext,
- AuthenticationMethodInformation authenticationMethod, HttpServletRequest httpRequest,
- HttpServletResponse httpResponse) {
- Session shibSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
-
- loginContext.setAuthenticationDuration(authenticationMethod.getAuthenticationDuration());
- loginContext.setAuthenticationInstant(authenticationMethod.getAuthenticationInstant());
- loginContext.setAuthenticationMethod(authenticationMethod.getAuthenticationMethod());
- loginContext.setPrincipalAuthenticated(true);
- loginContext.setPrincipalName(shibSession.getPrincipalName());
-
- ServiceInformation serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(),
- authenticationMethod);
- shibSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
+ protected void authenticateUser(String authnMethod, LoginHandler loginHandler, LoginContext loginContext,
+ HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+ LOG.debug("Authenticating user with login handler of type {}", loginHandler.getClass().getName());
- LOG.debug("Treating user {} as authenticated via existing method {}", loginContext.getPrincipalName(),
- loginContext.getAuthenticationMethod());
- returnToProfileHandler(loginContext, httpRequest, httpResponse);
+ loginContext.setAuthenticationAttempted();
+ loginContext.setAuthenticationInstant(new DateTime());
+ loginContext.setAuthenticationDuration(loginHandler.getAuthenticationDuration());
+ loginContext.setAuthenticationMethod(authnMethod);
+ loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
+ httpRequest.getSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+ loginHandler.login(httpRequest, httpResponse);
}
/**
- * Completes the authentication process when and already active authentication mechanism wasn't used, that is, when
- * the user was really authenticated.
+ * Completes the authentication process.
*
* The principal name set by the authentication handler is retrieved and pushed in to the login context, a
* Shibboleth session is created if needed, information indicating that the user has logged into the service is
* @param httpRequest current HTTP request
* @param httpResponse current HTTP response
*/
- protected void completeAuthenticationWithoutActiveMethod(LoginContext loginContext, HttpServletRequest httpRequest,
+ protected void completeAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
HttpServletResponse httpResponse) {
+ LOG.debug("Completing user authentication process");
- String principalName = DatatypeHelper.safeTrimOrNullString((String) httpRequest
- .getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
+ // We check if the principal name was already set in the login context
+ // if not attempt to pull it from where login handlers are supposed to provide it
+ String principalName = DatatypeHelper.safeTrimOrNullString(loginContext.getPrincipalName());
if (principalName == null) {
- loginContext.setPrincipalAuthenticated(false);
- loginContext.setAuthenticationFailure(new AuthenticationException(
- "No principal name returned from authentication handler."));
- LOG.error("No principal name returned from authentication method: "
- + loginContext.getAuthenticationMethod());
- returnToProfileHandler(loginContext, httpRequest, httpResponse);
- return;
+ principalName = DatatypeHelper.safeTrimOrNullString((String) httpRequest
+ .getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
+ if (principalName != null) {
+ loginContext.setPrincipalName(principalName);
+ } else {
+ loginContext.setPrincipalAuthenticated(false);
+ loginContext.setAuthenticationFailure(new AuthenticationException(
+ "No principal name returned from authentication handler."));
+ LOG.error("No principal name returned from authentication method: "
+ + loginContext.getAuthenticationMethod());
+ returnToProfileHandler(loginContext, httpRequest, httpResponse);
+ return;
+ }
}
-
loginContext.setPrincipalAuthenticated(true);
- loginContext.setPrincipalName(principalName);
- loginContext.setAuthenticationInstant(new DateTime());
// We allow a login handler to override the authentication method in the event that it supports multiple methods
String actualAuthnMethod = DatatypeHelper.safeTrimOrNullString((String) httpRequest
*/
protected void updateUserSession(LoginContext loginContext, HttpServletRequest httpRequest,
HttpServletResponse httpResponse) {
- Session shibSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
- if (shibSession == null) {
+ Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+ if (idpSession == null) {
LOG.debug("Creating shibboleth session for principal {}", loginContext.getPrincipalName());
- shibSession = (Session) sessionManager.createSession(loginContext.getPrincipalName());
- loginContext.setSessionID(shibSession.getSessionID());
- addSessionCookie(httpRequest, httpResponse, shibSession);
+ idpSession = (Session) sessionManager.createSession(loginContext.getPrincipalName());
+ loginContext.setSessionID(idpSession.getSessionID());
+ addSessionCookie(httpRequest, httpResponse, idpSession);
}
LOG.debug("Recording authentication and service information in Shibboleth session for principal: {}",
}
AuthenticationMethodInformation authnMethodInfo = new AuthenticationMethodInformationImpl(subject, authnMethod,
- new DateTime(), loginContext.getAuthenticationDuration());
+ loginContext.getAuthenticationInstant(), loginContext.getAuthenticationDuration());
- shibSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
+ idpSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
ServiceInformation serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(),
authnMethodInfo);
- shibSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
+ idpSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
}
/**