Changes in Release 2.1.3
=============================================
+[SIDP-244] - Error message on invalid ACS could be improved
[SIDP-247] - Log Exception in UP LoginHandler Servlet
[SIDP-263] - Suggest adding defaultSigningCredentialRef to the AnonymousRelyingParty element in the default config
-[SIDP-261] - IPAddressLoginHandler addresses comparasion fails
+[SIDP-261] - IPAddressLoginHandler addresses comparison fails
[SIDP-265] - Distinguish requested AuthMethod and default AuthMethod
[SIDP-271] - AuthenticationEngine doesn't correctly handle passive return from login servlet
[SIDP-276] - Example RDB Connector, quote principal
[SIDP-277] - Incorrect null check for request context in UsernamePasswordServlet
[SIDP-279] - IdP should log NameID for auditing
+[SIDP-281] - Customize login.jsp appearance based on relying party
[SIDP-285] - Use $IDP_SCOPE$ to populate IdP scope in conf-tmpl\attribute-resolver.xml
[SIDP-291] - Update libs for 2.1.3 release
-[SIDP-292] - login.jsp: wrong using of the attribute rawspan within the tag <td>
+[SIDP-292] - login.jsp: wrong using of the attribute rowspan within the tag <td>
[SIDP-306] - Remove ClientCertAuth rule from SAML 2 SSO SecurityPolicy in relying-party.xml
[SIDP-310] - Change default relying-party.xml settings for SAML 2 profiles' encryptNameIds parameter from "conditional" to "never"
[SIDP-315] - Credential provided by UsernamePasswordLogin handler as attribute
[SIDP-318] - IdP erroneously logs many normal events as errors
[SIDP-322] - Exception thrown when SP requests a particular authentication method that is not configured
+[SIDP-324] - Add additional information to Status handler
Changes in Release 2.1.2
=============================================
import org.joda.time.chrono.ISOChronology;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
-import org.opensaml.xml.util.DatatypeHelper;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.util.Base64;
import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager;
+import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
-/** A servlet for displaying the status of the IdP. */
+/** A Servlet for displaying the status of the IdP. */
public class StatusServlet extends HttpServlet {
+ /** Serial version UID. */
+ private static final long serialVersionUID = 7917509317276109266L;
+
/** Formatter used when print date/times. */
private DateTimeFormatter dateFormat;
super.init(config);
dateFormat = ISODateTimeFormat.dateTimeNoMillis();
-
startTime = new DateTime(ISOChronology.getInstanceUTC());
-
- String attributeResolverId = config.getInitParameter("attributeResolverId");
- if (DatatypeHelper.isEmpty(attributeResolverId)) {
- attributeResolverId = "shibboleth.AttributeResolver";
- }
- attributeResolver = (AttributeResolver<?>) getServletContext().getAttribute(attributeResolverId);
-
- String rpConfigManagerId = config.getInitParameter("rpConfigManagerId");
- if (DatatypeHelper.isEmpty(rpConfigManagerId)) {
- rpConfigManagerId = "shibboleth.RelyingPartyConfigurationManager";
- }
- rpConfigManager = (RelyingPartyConfigurationManager) getServletContext().getAttribute(rpConfigManagerId);
+ attributeResolver = HttpServletHelper.getAttributeResolver(config.getServletContext());
+ rpConfigManager = HttpServletHelper.getRelyingPartyConfirmationManager(config.getServletContext());
}
/** {@inheritDoc} */
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/plain");
PrintWriter output = resp.getWriter();
printOperatingEnvironmentInformation(output);
protected void printRelyingPartyConfigurationInformation(PrintWriter out, RelyingPartyConfiguration config) {
out.println("relying_party_id: " + config.getRelyingPartyId());
out.println("idp_entity_id: " + config.getProviderId());
-
+
if (config.getDefaultAuthenticationMethod() != null) {
out.println("default_authentication_method: " + config.getDefaultAuthenticationMethod());
} else {
out.println("default_authentication_method: none");
}
+ try{
+ X509Credential signingCredential = (X509Credential) config.getDefaultSigningCredential();
+ out.println("default_signing_tls_key: " + Base64.encodeBytes(signingCredential.getEntityCertificate().getEncoded(), Base64.DONT_BREAK_LINES));
+ }catch(Throwable t){
+ // swallow error
+ }
+
for (String profileId : config.getProfileConfigurations().keySet()) {
out.println("configured_communication_profile: " + profileId);
}
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import javax.security.auth.Subject;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.joda.time.DateTime;
-import org.opensaml.common.IdentifierGenerator;
-import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.saml2.core.AuthnContext;
import org.opensaml.util.storage.StorageService;
import org.opensaml.ws.transport.http.HTTPTransportUtils;
import edu.internet2.middleware.shibboleth.idp.session.Session;
import edu.internet2.middleware.shibboleth.idp.session.impl.AuthenticationMethodInformationImpl;
import edu.internet2.middleware.shibboleth.idp.session.impl.ServiceInformationImpl;
+import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
/** Manager responsible for handling authentication requests. */
public class AuthenticationEngine extends HttpServlet {
/** Class logger. */
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationEngine.class);
+
+ //TODO remove once HttpServletHelper does redirects
+ private static ServletContext context;
/** Storage service used to store {@link LoginContext}s while authentication is in progress. */
private static StorageService<String, LoginContextEntry> storageService;
- /** Name of the storage service partition used to store login contexts. */
- private static String loginContextPartitionName;
-
- /** Lifetime of stored login contexts. */
- private static long loginContextEntryLifetime;
-
- /** ID generator. */
- private static IdentifierGenerator idGen;
-
/** Whether the public credentials of a {@link Subject} are retained after authentication. */
private boolean retainSubjectsPublicCredentials;
retainSubjectsPublicCredentials = false;
}
- String handlerManagerId = config.getInitParameter("handlerManagerId");
- if (DatatypeHelper.isEmpty(handlerManagerId)) {
- handlerManagerId = "shibboleth.HandlerManager";
- }
- handlerManager = (IdPProfileHandlerManager) getServletContext().getAttribute(handlerManagerId);
-
- String sessionManagerId = config.getInitParameter("sessionManagedId");
- if (DatatypeHelper.isEmpty(sessionManagerId)) {
- sessionManagerId = "shibboleth.SessionManager";
- }
- sessionManager = (SessionManager<Session>) getServletContext().getAttribute(sessionManagerId);
-
- String storageServiceId = config.getInitParameter("storageServiceId");
- if (DatatypeHelper.isEmpty(storageServiceId)) {
- storageServiceId = "shibboleth.StorageService";
- }
- storageService = (StorageService<String, LoginContextEntry>) getServletContext().getAttribute(storageServiceId);
-
- String partitionName = DatatypeHelper.safeTrimOrNullString(config
- .getInitParameter(LOGIN_CONTEXT_PARTITION_NAME_INIT_PARAM_NAME));
- if (partitionName != null) {
- loginContextPartitionName = partitionName;
- } else {
- loginContextPartitionName = "loginContexts";
- }
-
- String lifetime = DatatypeHelper.safeTrimOrNullString(config
- .getInitParameter(LOGIN_CONTEXT_LIFETIME_INIT_PARAM_NAME));
- if (lifetime != null) {
- loginContextEntryLifetime = Long.parseLong(lifetime);
- } else {
- loginContextEntryLifetime = 1000 * 60 * 30;
- }
-
- try {
- idGen = new SecureRandomIdentifierGenerator();
- } catch (NoSuchAlgorithmException e) {
- throw new ServletException("Error create random number generator", e);
- }
- }
-
- /**
- * Retrieves a login context.
- *
- * @param httpRequest current HTTP request
- * @param removeFromStorageService whether the login context should be removed from the storage service as it is
- * retrieved
- *
- * @return the login context or null if one is not available (e.g. because it has expired)
- */
- protected static LoginContext retrieveLoginContext(HttpServletRequest httpRequest, boolean removeFromStorageService) {
- // When the login context comes from the profile handlers its attached to the request
- // Prior to the authentication engine handing control over to a login handler it stores
- // the login context into the storage service so that the login handlers do not have to
- // maintain a reference to the context and return it to the engine.
- LoginContext loginContext = (LoginContext) httpRequest.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
- if (loginContext != null) {
- LOG.trace("Login context retrieved from HTTP request attribute");
- return loginContext;
- }
-
- String contextId = DatatypeHelper.safeTrimOrNullString((String) httpRequest
- .getAttribute(LOGIN_CONTEXT_KEY_NAME));
-
- if (contextId == null) {
- Cookie[] requestCookies = httpRequest.getCookies();
- if (requestCookies != null) {
- for (Cookie requestCookie : requestCookies) {
- if (DatatypeHelper.safeEquals(requestCookie.getName(), LOGIN_CONTEXT_KEY_NAME)) {
- LOG.trace("Located cookie with login context key");
- contextId = requestCookie.getValue();
- break;
- }
- }
- }
- }
-
- LOG.trace("Using login context key {} to look up login context", contextId);
- LoginContextEntry entry;
- if (removeFromStorageService) {
- entry = storageService.remove(loginContextPartitionName, contextId);
- } else {
- entry = storageService.get(loginContextPartitionName, contextId);
- }
- if (entry == null) {
- LOG.trace("No entry for login context found in storage service.");
- return null;
- } else if (entry.isExpired()) {
- LOG.trace("Login context entry found in storage service but it was expired.");
- return null;
- } else {
- LOG.trace("Login context entry found in storage service.");
- return entry.getLoginContext();
- }
+ handlerManager = HttpServletHelper.getProfileHandlerManager(config.getServletContext());
+ sessionManager = HttpServletHelper.getSessionManager(config.getServletContext());
+ storageService = (StorageService<String, LoginContextEntry>) HttpServletHelper.getStorageService(config.getServletContext());
+
+ context = config.getServletContext();
}
/**
*/
public static void returnToAuthenticationEngine(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
LOG.debug("Returning control to authentication engine");
- LoginContext loginContext = retrieveLoginContext(httpRequest, false);
+ LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, context, httpRequest);
if (loginContext == null) {
LOG.warn("No login context available, unable to return to authentication engine");
forwardRequest("/idp-error.jsp", httpRequest, httpResponse);
* @param httpRequest current HTTP request
* @param httpResponse current HTTP response
*/
- public static void returnToProfileHandler(LoginContext loginContext, HttpServletRequest httpRequest,
+ public static void returnToProfileHandler(HttpServletRequest httpRequest,
HttpServletResponse httpResponse) {
+ LOG.debug("Returning control to login handler");
+ LoginContext loginContext = HttpServletHelper.unbindLoginContext(storageService, context, httpRequest, httpResponse);
+ if (loginContext == null) {
+ LOG.warn("No login context available, unable to return to profile handler");
+ forwardRequest("/idp-error.jsp", httpRequest, httpResponse);
+ }
+
+ HttpServletHelper.bindLoginContext(loginContext, httpRequest);
LOG.debug("Returning control to profile handler at: {}", loginContext.getProfileHandlerURL());
- httpRequest.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
-
- // Cleanup this cookie
- Cookie lcKeyCookie = new Cookie(LOGIN_CONTEXT_KEY_NAME, "");
- lcKeyCookie.setMaxAge(0);
- httpResponse.addCookie(lcKeyCookie);
-
forwardRequest(loginContext.getProfileHandlerURL(), httpRequest, httpResponse);
}
LOG.error("HTTP Response already committed");
}
- LoginContext loginContext = retrieveLoginContext(httpRequest, true);
+ LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, getServletContext(), httpRequest);
if (loginContext == null) {
LOG.error("Incoming request does not have attached login context");
throw new ServletException("Incoming request does not have attached login context");
}
}
- // Send the request to the login handler
LOG.debug("Authenticating user with login handler of type {}", loginHandler.getClass().getName());
loginContext.setAuthenticationAttempted();
loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
- storeLoginContext(loginContext, httpRequest, httpResponse);
+
+ // Send the request to the login handler
+ HttpServletHelper.bindLoginContext(loginContext, storageService, getServletContext(), httpRequest, httpResponse);
loginHandler.login(httpRequest, httpResponse);
} catch (AuthenticationException e) {
loginContext.setAuthenticationFailure(e);
- returnToProfileHandler(loginContext, httpRequest, httpResponse);
+ returnToProfileHandler(httpRequest, httpResponse);
}
}
}
/**
- * Stores the login context in the storage service. The key for the stored login context is then bound to an HTTP
- * request attribute and set a cookie.
- *
- * @param loginContext login context to store
- * @param httpRequest current HTTP request
- * @param httpResponse current HTTP response
- */
- protected void storeLoginContext(LoginContext loginContext, HttpServletRequest httpRequest,
- HttpServletResponse httpResponse) {
- String contextId = idGen.generateIdentifier();
-
- storageService.put(loginContextPartitionName, contextId, new LoginContextEntry(loginContext,
- loginContextEntryLifetime));
-
- httpRequest.setAttribute(LOGIN_CONTEXT_KEY_NAME, contextId);
-
- Cookie cookie = new Cookie(LOGIN_CONTEXT_KEY_NAME, contextId);
- String contextPath = httpRequest.getContextPath();
- if (DatatypeHelper.isEmpty(contextPath)) {
- cookie.setPath("/");
- } else {
- cookie.setPath(contextPath);
- }
- cookie.setSecure(httpRequest.isSecure());
- cookie.setMaxAge(-1);
- httpResponse.addCookie(cookie);
- }
-
- /**
* Completes the authentication process.
*
* The principal name set by the authentication handler is retrieved and pushed in to the login context, a
loginContext.setAuthenticationFailure(e);
}
- returnToProfileHandler(loginContext, httpRequest, httpResponse);
+ returnToProfileHandler(httpRequest, httpResponse);
}
/**
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(IPAddressLoginHandler.class);
- /** The URI of the AuthnContextDeclRef or the AuthnContextClass. */
- private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol";
-
/** The username to use for IP-address "authenticated" users. */
private String username;
import edu.internet2.middleware.shibboleth.common.util.HttpHelper;
import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
import edu.internet2.middleware.shibboleth.idp.authn.ShibbolethSSOLoginContext;
+import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
/** Shibboleth SSO request profile handler. */
public class ShibbolethSSOProfileHandler extends AbstractSAML1ProfileHandler {
log.debug("Processing incoming request");
HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
- LoginContext loginContext = (LoginContext) httpRequest.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+ LoginContext loginContext = HttpServletHelper.getLoginContext(httpRequest);
if (loginContext == null) {
log.debug("Incoming request does not contain a login context, processing as first leg of request");
loginContext.setDefaultAuthenticationMethod(rpConfig.getDefaultAuthenticationMethod());
ProfileConfiguration ssoConfig = rpConfig.getProfileConfiguration(ShibbolethSSOConfiguration.PROFILE_ID);
if (ssoConfig == null) {
- String msg = MessageFormatter.format("Shibboleth SSO profile is not configured for relying party '{}'", loginContext.getRelyingPartyId());
+ String msg = MessageFormatter.format("Shibboleth SSO profile is not configured for relying party '{}'",
+ loginContext.getRelyingPartyId());
log.warn(msg);
throw new ProfileException(msg);
}
- httpRequest.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+ HttpServletHelper.bindLoginContext(loginContext, httpRequest);
try {
RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(authenticationManagerPath);
dispatcher.forward(httpRequest, httpResponse);
return;
} catch (IOException e) {
- String msg = "Error forwarding Shibboleth SSO request to AuthenticationManager";
+ String msg = "Error forwarding Shibboleth SSO request to AuthenticationManager";
log.error(msg, e);
throw new ProfileException(msg, e);
} catch (ServletException e) {
requestContext.setMessageDecoder(decoder);
try {
decoder.decode(requestContext);
- log.debug("Decoded Shibboleth SSO request from relying party '{}'", requestContext.getInboundMessageIssuer());
+ log.debug("Decoded Shibboleth SSO request from relying party '{}'", requestContext
+ .getInboundMessageIssuer());
} catch (MessageDecodingException e) {
- String msg = "Error decoding Shibboleth SSO request";
+ String msg = "Error decoding Shibboleth SSO request";
log.warn(msg, e);
throw new ProfileException(msg, e);
} catch (SecurityException e) {
protected void completeAuthenticationRequest(HTTPInTransport inTransport, HTTPOutTransport outTransport)
throws ProfileException {
HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
- ShibbolethSSOLoginContext loginContext = (ShibbolethSSOLoginContext) httpRequest
- .getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+ ShibbolethSSOLoginContext loginContext = (ShibbolethSSOLoginContext) HttpServletHelper.getLoginContext(httpRequest);
ShibbolethSSORequestContext requestContext = buildRequestContext(loginContext, inTransport, outTransport);
import edu.internet2.middleware.shibboleth.idp.authn.PassiveAuthenticationException;
import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
import edu.internet2.middleware.shibboleth.idp.session.Session;
+import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
/** SAML 2.0 SSO request profile handler. */
public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
/** Builder of Endpoint objects. */
private SAMLObjectBuilder<Endpoint> endpointBuilder;
- /** URL of the authentication manager servlet. */
+ /** URL of the authentication manager Servlet. */
private String authenticationManagerPath;
/**
* Constructor.
*
- * @param authnManagerPath path to the authentication manager servlet
+ * @param authnManagerPath path to the authentication manager Servlet
*/
@SuppressWarnings("unchecked")
public SSOProfileHandler(String authnManagerPath) {
/** {@inheritDoc} */
public void processRequest(HTTPInTransport inTransport, HTTPOutTransport outTransport) throws ProfileException {
- HttpServletRequest servletRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
+ HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
- LoginContext loginContext = (LoginContext) servletRequest.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+ LoginContext loginContext = HttpServletHelper.getLoginContext(httpRequest);
if (loginContext == null) {
log.debug("Incoming request does not contain a login context, processing as first leg of request");
performAuthentication(inTransport, outTransport);
loginContext.setProfileHandlerURL(HttpHelper.getRequestUriWithoutContext(servletRequest));
loginContext.setDefaultAuthenticationMethod(rpConfig.getDefaultAuthenticationMethod());
- servletRequest.setAttribute(Saml2LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+ HttpServletHelper.bindLoginContext(loginContext, servletRequest);
RequestDispatcher dispatcher = servletRequest.getRequestDispatcher(authenticationManagerPath);
dispatcher.forward(servletRequest, ((HttpServletResponseAdapter) outTransport).getWrappedResponse());
} catch (MarshallingException e) {
*/
protected void completeAuthenticationRequest(HTTPInTransport inTransport, HTTPOutTransport outTransport)
throws ProfileException {
- HttpServletRequest servletRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
-
- Saml2LoginContext loginContext = (Saml2LoginContext) servletRequest
- .getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+ HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
+ Saml2LoginContext loginContext = (Saml2LoginContext) HttpServletHelper.getLoginContext(httpRequest);
+
SSORequestContext requestContext = buildRequestContext(loginContext, inTransport, outTransport);
checkSamlVersion(requestContext);
--- /dev/null
+/*
+ * Copyright 2009 University Corporation for Advanced Internet Development, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.util;
+
+import java.util.UUID;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.opensaml.util.storage.StorageService;
+import org.opensaml.xml.util.DatatypeHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.AttributeFilteringEngine;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager;
+import edu.internet2.middleware.shibboleth.common.relyingparty.provider.SAMLMDRelyingPartyConfigurationManager;
+import edu.internet2.middleware.shibboleth.common.session.SessionManager;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContextEntry;
+import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
+
+/** A helper class that provides access to internal state from Servlets and hence also JSPs. */
+public class HttpServletHelper {
+
+ /** Name of the cookie containing the IdP session ID: {@value} . */
+ public static final String IDP_SESSION_COOKIE = "_idp_session";
+
+ /** Name of the key to the current authentication login context: {@value} . */
+ public static final String LOGIN_CTX_KEY_NAME = "_idp_authn_lc_key";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link AttributeFilteringEngine} service: {@value} . */
+ public static final String ATTRIBUTE_FILTER_ENGINE_SID_CTX_PARAM = "AttributeFilterEngineId";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link AttributeResolver} service: {@value} . */
+ public static final String ATTRIBUTE_RESOLVER_SID_CTX_PARAM = "AttributeResolverId";
+
+ /**
+ * {@link ServletContext} parameter name bearing the name of the {@link StorageService} partition into which
+ * {@link LoginContext}s are stored: {@value} .
+ */
+ public static final String LOGIN_CTX_PARTITION_CTX_PARAM = "loginContextPartitionName";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link IdPProfileHandlerManager} service: {@value} . */
+ public static final String PROFILE_HANDLER_MNGR_SID_CTX_PARAM = "ProfileHandlerMngrId";
+
+ /**
+ * {@link ServletContext} parameter name bearing the ID of the {@link RelyingPartyConfigurationManager} service: * *
+ * * {@value} .
+ */
+ public static final String RP_CONFIG_MNGR_SID_CTX_PARAM = "RelyingPartyConfigurationManagerId";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link SAML1AttributeAuthority} service: {@value} . */
+ public static final String SAML1_AA_SID_CTX_PARAM = "SAML1AttributeAuthorityId";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link SAML2AttributeAuthority} service: {@value} . */
+ public static final String SAML2_AA_SID_CTX_PARAM = "SAML2AttributeAuthorityId";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link SessionManager} service: {@value} . */
+ public static final String SESSION_MNGR_SID_CTX_PARAM = "SessionManagerId";
+
+ /** {@link ServletContext} parameter name bearing the ID of the {@link SAML1AttributeAuthority} service: {@value} . */
+ public static final String STORAGE_SERVICE_SID_CTX_PARAM = "StorageServiceId";
+
+ /** Default ID by which the {@link AttributeFilteringEngine} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_ATTRIBUTE_FILTER_ENGINE_SID = "shibboleth.AttributeFilterEngine";
+
+ /** Default ID by which the {@link AttributeResolver} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_ATTRIBUTE_RESOLVER_SID = "shibboleth.AttributeResolver";
+
+ /** Default name for the {@link StorageService} partition which holds {@link LoginContext}s: {@value} . */
+ public static final String DEFAULT_LOGIN_CTX_PARITION = "loginContexts";
+
+ /** Default ID by which the {@link IdPProfileHandlerManager} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_PROFILE_HANDLER_MNGR_SID = "shibboleth.HandlerManager";
+
+ /** Default ID by which the {@link RelyingPartyConfigurationManager} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_RP_CONFIG_MNGR_SID = "shibboleth.RelyingPartyConfigurationManager";
+
+ /** Default ID by which the {@link SAML1AttributeAuthority} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_SAML1_AA_SID = "shibboleth.SAML1AttributeAuthority";
+
+ /** Default ID by which the {@link SAML2AttributeAuthority} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_SAML2_AA_SID = "shibboleth.SAML2AttributeAuthority";
+
+ /** Default ID by which the {@link SessionManager} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_SESSION_MNGR_SID = "shibboleth.SessionManager";
+
+ /** Default ID by which the {@link StorageService} is know within the Servlet context: {@value} . */
+ public static final String DEFAULT_STORAGE_SERVICE_SID = "shibboleth.StorageService";
+
+ /** Class logger. */
+ private static final Logger log = LoggerFactory.getLogger(HttpServletHelper.class);
+
+ /**
+ * Binds a {@link LoginContext} to the current request.
+ *
+ * @param loginContext login context to be bound
+ * @param request current HTTP request
+ */
+ public static void bindLoginContext(LoginContext loginContext, HttpServletRequest request) {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ request.setAttribute(LOGIN_CTX_KEY_NAME, loginContext);
+ }
+
+ /**
+ * Binds a {@link LoginContext} to the issuer of the current request. The binding is done by creating a random UUID,
+ * placing that in a cookie in the request, and storing the context in to the storage service under that key.
+ *
+ * @param loginContext the login context to be bound
+ * @param storageService the storage service which will hold the context
+ * @param context the Servlet context
+ * @param httpRequest the current HTTP request
+ * @param httpResponse the current HTTP response
+ */
+ public static void bindLoginContext(LoginContext loginContext,
+ StorageService storageService, ServletContext context,
+ HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+ if (storageService == null) {
+ throw new IllegalArgumentException("Storage service may not be null");
+ }
+ if (httpRequest == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ if (loginContext == null) {
+ return;
+ }
+
+ String parition = getContextParam(context, LOGIN_CTX_PARTITION_CTX_PARAM, DEFAULT_LOGIN_CTX_PARITION);
+ log.debug("LoginContext parition: {}", parition);
+
+ String contextKey = UUID.randomUUID().toString();
+ while (storageService.contains(parition, contextKey)) {
+ contextKey = UUID.randomUUID().toString();
+ }
+ log.debug("LoginContext key: {}", contextKey);
+
+ LoginContextEntry entry = new LoginContextEntry(loginContext, 1800000);
+ storageService.put(parition, contextKey, entry);
+
+ Cookie contextKeyCookie = new Cookie(LOGIN_CTX_KEY_NAME, contextKey);
+ contextKeyCookie.setPath("/");
+ contextKeyCookie.setSecure(httpRequest.isSecure());
+ contextKeyCookie.setMaxAge(31556926);
+ httpResponse.addCookie(contextKeyCookie);
+ }
+
+ /**
+ * Gets the {@link AttributeFilteringEngine} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static AttributeFilteringEngine<?> getAttributeFilterEnginer(ServletContext context) {
+ return getAttributeFilterEnginer(context, getContextParam(context, ATTRIBUTE_FILTER_ENGINE_SID_CTX_PARAM,
+ DEFAULT_ATTRIBUTE_FILTER_ENGINE_SID));
+ }
+
+ /**
+ * Gets the {@link AttributeFilteringEngine} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static AttributeFilteringEngine<?> getAttributeFilterEnginer(ServletContext context, String serviceId) {
+ return (AttributeFilteringEngine<?>) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the {@link AttributeResolver} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static AttributeResolver<?> getAttributeResolver(ServletContext context) {
+ return getAttributeResolver(context, getContextParam(context, ATTRIBUTE_RESOLVER_SID_CTX_PARAM,
+ DEFAULT_ATTRIBUTE_RESOLVER_SID));
+ }
+
+ /**
+ * Gets the {@link AttributeResolver} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static AttributeResolver<?> getAttributeResolver(ServletContext context, String serviceId) {
+ return (AttributeResolver<?>) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets a value for a given context parameter. If no value is present the default value is used.
+ *
+ * @param context the Servlet context
+ * @param name name of the context parameter
+ * @param defaultValue default value of the parameter
+ *
+ * @return the value of the context parameter or the default value if the parameter is not set or does not contain a
+ * value
+ */
+ public static String getContextParam(ServletContext context, String name, String defaultValue) {
+ String value = DatatypeHelper.safeTrimOrNullString(context.getInitParameter(name));
+ if (value == null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ /**
+ * Gets the first {@link Cookie} whose name matches the given name.
+ *
+ * @param cookieName the cookie name
+ * @param httpRequest HTTP request from which the cookie should be extracted
+ *
+ * @return the cookie or null if no cookie with that name was given
+ */
+ public static Cookie getCookie(HttpServletRequest httpRequest, String cookieName) {
+ Cookie[] requestCookies = httpRequest.getCookies();
+ if (requestCookies != null) {
+ for (Cookie requestCookie : requestCookies) {
+ if (requestCookie != null && DatatypeHelper.safeEquals(requestCookie.getName(), cookieName)) {
+ return requestCookie;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the login context from the current request. The login context is only in this location while the request is
+ * being transferred from the authentication engine back to the profile handler.
+ *
+ * @param httpRequest current HTTP request
+ *
+ * @return the login context or null if no login context is bound to the request
+ */
+ public static LoginContext getLoginContext(HttpServletRequest httpRequest) {
+ return (LoginContext) httpRequest.getAttribute(LOGIN_CTX_KEY_NAME);
+ }
+
+ /**
+ * Gets the {@link LoginContext} for the user issuing the HTTP request. Note, login contexts are only available
+ * during the authentication process.
+ *
+ * @param context the Servlet context
+ * @param storageService storage service to use when retrieving the login context
+ * @param httpRequest current HTTP request
+ *
+ * @return the login context or null if none is available
+ */
+ public static LoginContext getLoginContext(StorageService storageService,
+ ServletContext context, HttpServletRequest httpRequest) {
+ if (storageService == null) {
+ throw new IllegalArgumentException("Storage service may not be null");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("Servlet context may not be null");
+ }
+ if (httpRequest == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+
+ LoginContext loginContext = getLoginContext(httpRequest);
+ if (loginContext == null) {
+ log.debug("LoginContext not bound to HTTP request, retrieving it from storage service");
+ Cookie loginContextKeyCookie = getCookie(httpRequest, LOGIN_CTX_KEY_NAME);
+ if (loginContextKeyCookie == null) {
+ log.debug("LoginContext key cookie was not present in request");
+ return null;
+ }
+
+ String loginContextKey = DatatypeHelper.safeTrimOrNullString(loginContextKeyCookie.getValue());
+ if (loginContextKey == null) {
+ log.warn("Corrupted LoginContext Key cookie, it did not contain a value");
+ }
+ log.debug("LoginContext key is '{}'", loginContextKey);
+
+ String partition = getContextParam(context, LOGIN_CTX_PARTITION_CTX_PARAM, DEFAULT_LOGIN_CTX_PARITION);
+ log.debug("parition: {}", partition);
+ LoginContextEntry entry = (LoginContextEntry) storageService.get(partition, loginContextKey);
+ if (entry != null) {
+ if (entry.isExpired()) {
+ log.debug("LoginContext found but it was expired");
+ } else {
+ loginContext = entry.getLoginContext();
+ }
+ } else {
+ log.debug("No login context in storage service");
+ }
+ }
+
+ return loginContext;
+ }
+
+ /**
+ * Gets the {@link IdPProfileHandlerManager} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static IdPProfileHandlerManager getProfileHandlerManager(ServletContext context) {
+ return getProfileHandlerManager(context, getContextParam(context, PROFILE_HANDLER_MNGR_SID_CTX_PARAM,
+ DEFAULT_PROFILE_HANDLER_MNGR_SID));
+ }
+
+ /**
+ * Gets the {@link IdPProfileHandlerManager} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static IdPProfileHandlerManager getProfileHandlerManager(ServletContext context, String serviceId) {
+ return (IdPProfileHandlerManager) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the {@link RelyingPartyConfigurationManager} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static RelyingPartyConfigurationManager getRelyingPartyConfirmationManager(ServletContext context) {
+ return getRelyingPartyConfirmationManager(context, getContextParam(context, RP_CONFIG_MNGR_SID_CTX_PARAM,
+ DEFAULT_RP_CONFIG_MNGR_SID));
+ }
+
+ /**
+ * Gets the {@link RelyingPartyConfigurationManager} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static RelyingPartyConfigurationManager getRelyingPartyConfirmationManager(ServletContext context,
+ String serviceId) {
+ return (RelyingPartyConfigurationManager) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the metatdata for a given relying party.
+ *
+ * @param relyingPartyEntityId the ID of the relying party
+ * @param rpConfigMngr relying party configuration manager
+ *
+ * @return the metadata for the relying party or null if no SAML metadata exists for the given relying party
+ */
+ public static EntityDescriptor getRelyingPartyMetadata(String relyingPartyEntityId,
+ RelyingPartyConfigurationManager rpConfigMngr) {
+ if (rpConfigMngr instanceof SAMLMDRelyingPartyConfigurationManager) {
+ SAMLMDRelyingPartyConfigurationManager samlRpConfigMngr = (SAMLMDRelyingPartyConfigurationManager) rpConfigMngr;
+ try {
+ return samlRpConfigMngr.getMetadataProvider().getEntityDescriptor(relyingPartyEntityId);
+ } catch (MetadataProviderException e) {
+
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the {@link SAML1AttributeAuthority} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SAML1AttributeAuthority getSAML1AttributeAuthority(ServletContext context) {
+ return getSAML1AttributeAuthority(context, getContextParam(context, SAML1_AA_SID_CTX_PARAM,
+ DEFAULT_SAML1_AA_SID));
+ }
+
+ /**
+ * Gets the {@link SAML1AttributeAuthority} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SAML1AttributeAuthority getSAML1AttributeAuthority(ServletContext context, String serviceId) {
+ return (SAML1AttributeAuthority) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the {@link SAML2AttributeAuthority} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SAML2AttributeAuthority getSAML2AttributeAuthority(ServletContext context) {
+ return getSAML2AttributeAuthority(context, getContextParam(context, SAML2_AA_SID_CTX_PARAM,
+ DEFAULT_SAML2_AA_SID));
+ }
+
+ /**
+ * Gets the {@link SAML2AttributeAuthority} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SAML2AttributeAuthority getSAML2AttributeAuthority(ServletContext context, String serviceId) {
+ return (SAML2AttributeAuthority) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the {@link SessionManager} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SessionManager<Session> getSessionManager(ServletContext context) {
+ return getSessionManager(context,
+ getContextParam(context, SESSION_MNGR_SID_CTX_PARAM, DEFAULT_SESSION_MNGR_SID));
+ }
+
+ /**
+ * Gets the {@link SessionManager} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static SessionManager<Session> getSessionManager(ServletContext context, String serviceId) {
+ return (SessionManager<Session>) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Gets the {@link StorageService} service bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static StorageService<?, ?> getStorageService(ServletContext context) {
+ return getStorageService(context, getContextParam(context, STORAGE_SERVICE_SID_CTX_PARAM,
+ DEFAULT_STORAGE_SERVICE_SID));
+ }
+
+ /**
+ * Gets the {@link StorageService} bound to the Servlet context.
+ *
+ * @param context the Servlet context
+ * @param serviceId the ID under which the service bound
+ *
+ * @return the service or null if there is no such service bound to the context
+ */
+ public static StorageService<?, ?> getStorageService(ServletContext context, String serviceId) {
+ return (StorageService<?, ?>) context.getAttribute(serviceId);
+ }
+
+ /**
+ * Unbinds a {@link LoginContext} from the current request. The unbinding results in the destruction of the
+ * associated context key cookie and removes the context from the storage service.
+ *
+ * @param storageService storage service holding the context
+ * @param context the Servlet context
+ * @param httpRequest current HTTP request
+ * @param httpResponse current HTTP response
+ *
+ * @return the login context that was unbound or null if there was no bound context
+ */
+ public static LoginContext unbindLoginContext(StorageService storageService,
+ ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+ if (storageService == null || context == null || httpRequest == null || httpResponse == null) {
+ return null;
+ }
+
+ Cookie loginContextKeyCookie = getCookie(httpRequest, LOGIN_CTX_KEY_NAME);
+ if (loginContextKeyCookie == null) {
+ return null;
+ }
+
+ String loginContextKey = DatatypeHelper.safeTrimOrNullString(loginContextKeyCookie.getValue());
+ if (loginContextKey == null) {
+ log.warn("Corrupted LoginContext Key cookie, it did not contain a value");
+ }
+
+ loginContextKeyCookie.setMaxAge(0);
+ httpResponse.addCookie(loginContextKeyCookie);
+
+ LoginContextEntry entry = (LoginContextEntry) storageService.remove(getContextParam(context,
+ LOGIN_CTX_PARTITION_CTX_PARAM, DEFAULT_LOGIN_CTX_PARITION), loginContextKey);
+ if (entry != null && !entry.isExpired()) {
+ return entry.getLoginContext();
+ }
+ return null;
+ }
+
+ // public static Session getUserSession(ServletContext context, HttpServletRequest request) {
+ //
+ // }
+ //
+ // public static Session getUserSession(ServletContext context, String sessionId) {
+ //
+ // }
+}
\ No newline at end of file
+<%@ page import="edu.internet2.middleware.shibboleth.idp.authn.LoginContext" %>
+<%@ page import="edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper" %>
+<%@ page import="org.opensaml.saml2.metadata.*" %>
+
+<%
+ LoginContext loginContext = HttpServletHelper.getLoginContext(HttpServletHelper.getStorageService(application),
+ application, request);
+ EntityDescriptor entityDescriptor = HttpServletHelper.getRelyingPartyMetadata(loginContext.getRelyingPartyId(),
+ HttpServletHelper.getRelyingPartyConfirmationManager(application));
+%>
+
<html>
<head>
<body>
<img src="<%= request.getContextPath() %>/images/logo.jpg" />
- <h2>Shibboleth Identity Provider Login</h2>
+ <h2>Shibboleth Identity Provider Login to <%= entityDescriptor.getEntityID() %></h2>
<% if ("true".equals(request.getAttribute("loginFailed"))) { %>
<p><font color="red">Authentication Failed</font></p>