View Javadoc

    1   /*
    2    * Copyright 2009 University Corporation for Advanced Internet Development, Inc.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    * http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package edu.internet2.middleware.shibboleth.idp.util;
    18
    19  import java.util.UUID;
    20
    21  import javax.servlet.ServletContext;
    22  import javax.servlet.http.Cookie;
    23  import javax.servlet.http.HttpServletRequest;
    24  import javax.servlet.http.HttpServletResponse;
    25
    26  import org.opensaml.saml2.metadata.EntityDescriptor;
    27  import org.opensaml.saml2.metadata.provider.MetadataProviderException;
    28  import org.opensaml.util.URLBuilder;
    29  import org.opensaml.util.storage.StorageService;
    30  import org.opensaml.xml.util.DatatypeHelper;
    31  import org.slf4j.Logger;
    32  import org.slf4j.LoggerFactory;
    33
    34  import sun.security.action.GetLongAction;
    35
    36  import edu.internet2.middleware.shibboleth.common.attribute.filtering.AttributeFilteringEngine;
    37  import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
    38  import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML2AttributeAuthority;
    39  import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
    40  import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager;
    41  import edu.internet2.middleware.shibboleth.common.relyingparty.provider.SAMLMDRelyingPartyConfigurationManager;
    42  import edu.internet2.middleware.shibboleth.common.session.SessionManager;
    43  import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
    44  import edu.internet2.middleware.shibboleth.idp.authn.LoginContextEntry;
    45  import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
    46  import edu.internet2.middleware.shibboleth.idp.session.Session;
    47
    48  /** A helper class that provides access to internal state from Servlets and hence also JSPs. */
    49  public class HttpServletHelper {
    50
    51      /** Name of the context initialization parameter that stores the domain to use for all cookies. */
    52      public static final String COOKIE_DOMAIN_PARAM = "cookieDomain";
    53
    54      /** Name of the cookie containing the IdP session ID: {@value} . */
    55      public static final String IDP_SESSION_COOKIE = "_idp_session";
    56
    57      /** Name of the key to the current authentication login context: {@value} . */
    58      public static final String LOGIN_CTX_KEY_NAME = "_idp_authn_lc_key";
    59
    60      /** {@link ServletContext} parameter name bearing the ID of the {@link AttributeFilteringEngine} service: {@value} . */
    61      public static final String ATTRIBUTE_FILTER_ENGINE_SID_CTX_PARAM = "AttributeFilterEngineId";
    62
    63      /** {@link ServletContext} parameter name bearing the ID of the {@link AttributeResolver} service: {@value} . */
    64      public static final String ATTRIBUTE_RESOLVER_SID_CTX_PARAM = "AttributeResolverId";
    65
    66      /**
    67       * {@link ServletContext} parameter name bearing the name of the {@link StorageService} partition into which
    68       * {@link LoginContext}s are stored: {@value} .
    69       */
    70      public static final String LOGIN_CTX_PARTITION_CTX_PARAM = "loginContextPartitionName";
    71
    72      /** {@link ServletContext} parameter name bearing the ID of the {@link IdPProfileHandlerManager} service: {@value} . */
    73      public static final String PROFILE_HANDLER_MNGR_SID_CTX_PARAM = "ProfileHandlerMngrId";
    74
    75      /**
    76       * {@link ServletContext} parameter name bearing the ID of the {@link RelyingPartyConfigurationManager} service: * *
    77       * * {@value} .
    78       */
    79      public static final String RP_CONFIG_MNGR_SID_CTX_PARAM = "RelyingPartyConfigurationManagerId";
    80
    81      /** {@link ServletContext} parameter name bearing the ID of the {@link SAML1AttributeAuthority} service: {@value} . */
    82      public static final String SAML1_AA_SID_CTX_PARAM = "SAML1AttributeAuthorityId";
    83
    84      /** {@link ServletContext} parameter name bearing the ID of the {@link SAML2AttributeAuthority} service: {@value} . */
    85      public static final String SAML2_AA_SID_CTX_PARAM = "SAML2AttributeAuthorityId";
    86
    87      /** {@link ServletContext} parameter name bearing the ID of the {@link SessionManager} service: {@value} . */
    88      public static final String SESSION_MNGR_SID_CTX_PARAM = "SessionManagerId";
    89
    90      /** {@link ServletContext} parameter name bearing the ID of the {@link SAML1AttributeAuthority} service: {@value} . */
    91      public static final String STORAGE_SERVICE_SID_CTX_PARAM = "StorageServiceId";
    92
    93      /** Default ID by which the {@link AttributeFilteringEngine} is know within the Servlet context: {@value} . */
    94      public static final String DEFAULT_ATTRIBUTE_FILTER_ENGINE_SID = "shibboleth.AttributeFilterEngine";
    95
    96      /** Default ID by which the {@link AttributeResolver} is know within the Servlet context: {@value} . */
    97      public static final String DEFAULT_ATTRIBUTE_RESOLVER_SID = "shibboleth.AttributeResolver";
    98
    99      /** Default name for the {@link StorageService} partition which holds {@link LoginContext}s: {@value} . */
    100     public static final String DEFAULT_LOGIN_CTX_PARITION = "loginContexts";
    101
    102     /** Default ID by which the {@link IdPProfileHandlerManager} is know within the Servlet context: {@value} . */
    103     public static final String DEFAULT_PROFILE_HANDLER_MNGR_SID = "shibboleth.HandlerManager";
    104
    105     /** Default ID by which the {@link RelyingPartyConfigurationManager} is know within the Servlet context: {@value} . */
    106     public static final String DEFAULT_RP_CONFIG_MNGR_SID = "shibboleth.RelyingPartyConfigurationManager";
    107
    108     /** Default ID by which the {@link SAML1AttributeAuthority} is know within the Servlet context: {@value} . */
    109     public static final String DEFAULT_SAML1_AA_SID = "shibboleth.SAML1AttributeAuthority";
    110
    111     /** Default ID by which the {@link SAML2AttributeAuthority} is know within the Servlet context: {@value} . */
    112     public static final String DEFAULT_SAML2_AA_SID = "shibboleth.SAML2AttributeAuthority";
    113
    114     /** Default ID by which the {@link SessionManager} is know within the Servlet context: {@value} . */
    115     public static final String DEFAULT_SESSION_MNGR_SID = "shibboleth.SessionManager";
    116
    117     /** Default ID by which the {@link StorageService} is know within the Servlet context: {@value} . */
    118     public static final String DEFAULT_STORAGE_SERVICE_SID = "shibboleth.StorageService";
    119
    120     /** Class logger. */
    121     private static final Logger log = LoggerFactory.getLogger(HttpServletHelper.class);
    122
    123     /**
    124      * Binds a {@link LoginContext} to the current request.
    125      *
    126      * @param loginContext login context to be bound
    127      * @param httpRequest current HTTP request
    128      *
    129      * @deprecated
    130      */
    131     public static void bindLoginContext(LoginContext loginContext, HttpServletRequest httpRequest) {
    132         if (httpRequest == null) {
    133             throw new IllegalArgumentException("HTTP request may not be null");
    134         }
    135         httpRequest.setAttribute(LOGIN_CTX_KEY_NAME, loginContext);
    136     }
    137
    138     /**
    139      * Binds a {@link LoginContext} to the issuer of the current request. The binding is done by creating a random UUID,
    140      * placing that in a cookie in the request, and storing the context in to the storage service under that key.
    141      *
    142      * @param loginContext the login context to be bound
    143      * @param storageService the storage service which will hold the context
    144      * @param context the Servlet context
    145      * @param httpRequest the current HTTP request
    146      * @param httpResponse the current HTTP response
    147      */
    148     public static void bindLoginContext(LoginContext loginContext, StorageService storageService,
    149             ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
    150         if (storageService == null) {
    151             throw new IllegalArgumentException("Storage service may not be null");
    152         }
    153         if (httpRequest == null) {
    154             throw new IllegalArgumentException("HTTP request may not be null");
    155         }
    156         if (loginContext == null) {
    157             return;
    158         }
    159
    160         String parition = getContextParam(context, LOGIN_CTX_PARTITION_CTX_PARAM, DEFAULT_LOGIN_CTX_PARITION);
    161
    162         String contextKey = UUID.randomUUID().toString();
    163         while (storageService.contains(parition, contextKey)) {
    164             contextKey = UUID.randomUUID().toString();
    165         }
    166
    167         LoginContextEntry entry = new LoginContextEntry(loginContext, 1800000);
    168         log.debug("Storing LoginContext to StorageService partition {}, key {}", parition, contextKey);
    169         storageService.put(parition, contextKey, entry);
    170
    171         String cookieDomain = getCookieDomain(context);
    172
    173         Cookie contextKeyCookie = new Cookie(LOGIN_CTX_KEY_NAME, contextKey);
    174         contextKeyCookie.setVersion(1);
    175         if (cookieDomain != null) {
    176             contextKeyCookie.setDomain(cookieDomain);
    177         }
    178         contextKeyCookie.setPath("".equals(httpRequest.getContextPath()) ? "/" : httpRequest.getContextPath());
    179         contextKeyCookie.setSecure(httpRequest.isSecure());
    180         httpResponse.addCookie(contextKeyCookie);
    181
    182         httpRequest.setAttribute(LOGIN_CTX_KEY_NAME, loginContext);
    183     }
    184
    185     /**
    186      * Gets the domain to use for all cookies.
    187      *
    188      * @param context web application context
    189      *
    190      * @return domain to use for all cookies
    191      */
    192     public static String getCookieDomain(ServletContext context) {
    193         return context.getInitParameter(COOKIE_DOMAIN_PARAM);
    194     }
    195
    196     /**
    197      * Gets the {@link AttributeFilteringEngine} service bound to the Servlet context.
    198      *
    199      * @param context the Servlet context
    200      *
    201      * @return the service or null if there is no such service bound to the context
    202      */
    203     public static AttributeFilteringEngine<?> getAttributeFilterEnginer(ServletContext context) {
    204         return getAttributeFilterEnginer(context,
    205                 getContextParam(context, ATTRIBUTE_FILTER_ENGINE_SID_CTX_PARAM, DEFAULT_ATTRIBUTE_FILTER_ENGINE_SID));
    206     }
    207
    208     /**
    209      * Gets the {@link AttributeFilteringEngine} bound to the Servlet context.
    210      *
    211      * @param context the Servlet context
    212      * @param serviceId the ID under which the service bound
    213      *
    214      * @return the service or null if there is no such service bound to the context
    215      */
    216     public static AttributeFilteringEngine<?> getAttributeFilterEnginer(ServletContext context, String serviceId) {
    217         return (AttributeFilteringEngine<?>) context.getAttribute(serviceId);
    218     }
    219
    220     /**
    221      * Gets the {@link AttributeResolver} service bound to the Servlet context.
    222      *
    223      * @param context the Servlet context
    224      *
    225      * @return the service or null if there is no such service bound to the context
    226      */
    227     public static AttributeResolver<?> getAttributeResolver(ServletContext context) {
    228         return getAttributeResolver(context,
    229                 getContextParam(context, ATTRIBUTE_RESOLVER_SID_CTX_PARAM, DEFAULT_ATTRIBUTE_RESOLVER_SID));
    230     }
    231
    232     /**
    233      * Gets the {@link AttributeResolver} bound to the Servlet context.
    234      *
    235      * @param context the Servlet context
    236      * @param serviceId the ID under which the service bound
    237      *
    238      * @return the service or null if there is no such service bound to the context
    239      */
    240     public static AttributeResolver<?> getAttributeResolver(ServletContext context, String serviceId) {
    241         return (AttributeResolver<?>) context.getAttribute(serviceId);
    242     }
    243
    244     /**
    245      * Gets a value for a given context parameter. If no value is present the default value is used.
    246      *
    247      * @param context the Servlet context
    248      * @param name name of the context parameter
    249      * @param defaultValue default value of the parameter
    250      *
    251      * @return the value of the context parameter or the default value if the parameter is not set or does not contain a
    252      *         value
    253      */
    254     public static String getContextParam(ServletContext context, String name, String defaultValue) {
    255         String value = DatatypeHelper.safeTrimOrNullString(context.getInitParameter(name));
    256         if (value == null) {
    257             value = defaultValue;
    258         }
    259         return value;
    260     }
    261
    262     /**
    263      * Gets the first {@link Cookie} whose name matches the given name.
    264      *
    265      * @param cookieName the cookie name
    266      * @param httpRequest HTTP request from which the cookie should be extracted
    267      *
    268      * @return the cookie or null if no cookie with that name was given
    269      */
    270     public static Cookie getCookie(HttpServletRequest httpRequest, String cookieName) {
    271         Cookie[] requestCookies = httpRequest.getCookies();
    272         if (requestCookies != null) {
    273             for (Cookie requestCookie : requestCookies) {
    274                 if (requestCookie != null && DatatypeHelper.safeEquals(requestCookie.getName(), cookieName)) {
    275                     return requestCookie;
    276                 }
    277             }
    278         }
    279
    280         return null;
    281     }
    282
    283     /**
    284      * Gets the login context from the current request. The login context is only in this location while the request is
    285      * being transferred from the authentication engine back to the profile handler.
    286      *
    287      * This method only works during the first hand-off from the authentication engine to the login handler. Afterwords
    288      * you must use {@link #getLoginContext(StorageService, ServletContext, HttpServletRequest)}.
    289      *
    290      * @param httpRequest current HTTP request
    291      *
    292      * @return the login context or null if no login context is bound to the request
    293      */
    294     public static LoginContext getLoginContext(HttpServletRequest httpRequest) {
    295         return (LoginContext) httpRequest.getAttribute(LOGIN_CTX_KEY_NAME);
    296     }
    297
    298     /**
    299      * Gets the {@link LoginContext} for the user issuing the HTTP request. Note, login contexts are only available
    300      * during the authentication process.
    301      *
    302      * @param context the Servlet context
    303      * @param storageService storage service to use when retrieving the login context
    304      * @param httpRequest current HTTP request
    305      *
    306      * @return the login context or null if none is available
    307      */
    308     public static LoginContext getLoginContext(StorageService storageService, ServletContext context,
    309             HttpServletRequest httpRequest) {
    310         if (storageService == null) {
    311             throw new IllegalArgumentException("Storage service may not be null");
    312         }
    313         if (context == null) {
    314             throw new IllegalArgumentException("Servlet context may not be null");
    315         }
    316         if (httpRequest == null) {
    317             throw new IllegalArgumentException("HTTP request may not be null");
    318         }
    319
    320         Cookie loginContextKeyCookie = getCookie(httpRequest, LOGIN_CTX_KEY_NAME);
    321         if (loginContextKeyCookie == null) {
    322             log.debug("LoginContext key cookie was not present in request");
    323             return null;
    324         }
    325
    326         String loginContextKey = DatatypeHelper.safeTrimOrNullString(loginContextKeyCookie.getValue());
    327         if (loginContextKey == null) {
    328             log.warn("Corrupted LoginContext Key cookie, it did not contain a value");
    329         }
    330
    331         String partition = getContextParam(context, LOGIN_CTX_PARTITION_CTX_PARAM, DEFAULT_LOGIN_CTX_PARITION);
    332         log.trace("Looking up LoginContext with key {} from StorageService parition: {}", loginContextKey, partition);
    333         LoginContextEntry entry = (LoginContextEntry) storageService.get(partition, loginContextKey);
    334         if (entry != null) {
    335             if (entry.isExpired()) {
    336                 log.debug("LoginContext found but it was expired");
    337             } else {
    338                 log.trace("Retrieved LoginContext with key {} from StorageService parition: {}", loginContextKey,
    339                         partition);
    340                 return entry.getLoginContext();
    341             }
    342         } else {
    343             log.debug("No login context in storage service");
    344         }
    345
    346         return null;
    347     }
    348
    349     /**
    350      * Gets the {@link IdPProfileHandlerManager} service bound to the Servlet context.
    351      *
    352      * @param context the Servlet context
    353      *
    354      * @return the service or null if there is no such service bound to the context
    355      */
    356     public static IdPProfileHandlerManager getProfileHandlerManager(ServletContext context) {
    357         return getProfileHandlerManager(context,
    358                 getContextParam(context, PROFILE_HANDLER_MNGR_SID_CTX_PARAM, DEFAULT_PROFILE_HANDLER_MNGR_SID));
    359     }
    360
    361     /**
    362      * Gets the {@link IdPProfileHandlerManager} bound to the Servlet context.
    363      *
    364      * @param context the Servlet context
    365      * @param serviceId the ID under which the service bound
    366      *
    367      * @return the service or null if there is no such service bound to the context
    368      */
    369     public static IdPProfileHandlerManager getProfileHandlerManager(ServletContext context, String serviceId) {
    370         return (IdPProfileHandlerManager) context.getAttribute(serviceId);
    371     }
    372
    373     /**
    374      * Gets the {@link RelyingPartyConfigurationManager} service bound to the Servlet context.
    375      *
    376      * @param context the Servlet context
    377      *
    378      * @return the service or null if there is no such service bound to the context
    379      */
    380     public static RelyingPartyConfigurationManager getRelyingPartyConfigurationManager(ServletContext context) {
    381         return getRelyingPartyConfigurationManager(context,
    382                 getContextParam(context, RP_CONFIG_MNGR_SID_CTX_PARAM, DEFAULT_RP_CONFIG_MNGR_SID));
    383     }
    384
    385     /**
    386      * Gets the {@link RelyingPartyConfigurationManager} bound to the Servlet context.
    387      *
    388      * @param context the Servlet context
    389      * @param serviceId the ID under which the service bound
    390      *
    391      * @return the service or null if there is no such service bound to the context
    392      */
    393     public static RelyingPartyConfigurationManager getRelyingPartyConfigurationManager(ServletContext context,
    394             String serviceId) {
    395         return (RelyingPartyConfigurationManager) context.getAttribute(serviceId);
    396     }
    397
    398     /**
    399      * Gets the {@link RelyingPartyConfigurationManager} service bound to the Servlet context.
    400      *
    401      * @param context the Servlet context
    402      *
    403      * @return the service or null if there is no such service bound to the context
    404      *
    405      * @deprecated use {@link #getRelyingPartyConfigurationManager(ServletContext)}
    406      */
    407     public static RelyingPartyConfigurationManager getRelyingPartyConfirmationManager(ServletContext context) {
    408         return getRelyingPartyConfirmationManager(context,
    409                 getContextParam(context, RP_CONFIG_MNGR_SID_CTX_PARAM, DEFAULT_RP_CONFIG_MNGR_SID));
    410     }
    411
    412     /**
    413      * Gets the {@link RelyingPartyConfigurationManager} bound to the Servlet context.
    414      *
    415      * @param context the Servlet context
    416      * @param serviceId the ID under which the service bound
    417      *
    418      * @return the service or null if there is no such service bound to the context
    419      *
    420      * @deprecated use {@link #getRelyingPartyConfigurationManager(ServletContext, String)}
    421
    422      */
    423     public static RelyingPartyConfigurationManager getRelyingPartyConfirmationManager(ServletContext context,
    424             String serviceId) {
    425         return (RelyingPartyConfigurationManager) context.getAttribute(serviceId);
    426     }
    427
    428     /**
    429      * Gets the metatdata for a given relying party.
    430      *
    431      * @param relyingPartyEntityId the ID of the relying party
    432      * @param rpConfigMngr relying party configuration manager
    433      *
    434      * @return the metadata for the relying party or null if no SAML metadata exists for the given relying party
    435      */
    436     public static EntityDescriptor getRelyingPartyMetadata(String relyingPartyEntityId,
    437             RelyingPartyConfigurationManager rpConfigMngr) {
    438         if (rpConfigMngr instanceof SAMLMDRelyingPartyConfigurationManager) {
    439             SAMLMDRelyingPartyConfigurationManager samlRpConfigMngr = (SAMLMDRelyingPartyConfigurationManager) rpConfigMngr;
    440             try {
    441                 return samlRpConfigMngr.getMetadataProvider().getEntityDescriptor(relyingPartyEntityId);
    442             } catch (MetadataProviderException e) {
    443
    444             }
    445         }
    446
    447         return null;
    448     }
    449
    450     /**
    451      * Gets the {@link SAML1AttributeAuthority} service bound to the Servlet context.
    452      *
    453      * @param context the Servlet context
    454      *
    455      * @return the service or null if there is no such service bound to the context
    456      */
    457     public static SAML1AttributeAuthority getSAML1AttributeAuthority(ServletContext context) {
    458         return getSAML1AttributeAuthority(context,
    459                 getContextParam(context, SAML1_AA_SID_CTX_PARAM, DEFAULT_SAML1_AA_SID));
    460     }
    461
    462     /**
    463      * Gets the {@link SAML1AttributeAuthority} bound to the Servlet context.
    464      *
    465      * @param context the Servlet context
    466      * @param serviceId the ID under which the service bound
    467      *
    468      * @return the service or null if there is no such service bound to the context
    469      */
    470     public static SAML1AttributeAuthority getSAML1AttributeAuthority(ServletContext context, String serviceId) {
    471         return (SAML1AttributeAuthority) context.getAttribute(serviceId);
    472     }
    473
    474     /**
    475      * Gets the {@link SAML2AttributeAuthority} service bound to the Servlet context.
    476      *
    477      * @param context the Servlet context
    478      *
    479      * @return the service or null if there is no such service bound to the context
    480      */
    481     public static SAML2AttributeAuthority getSAML2AttributeAuthority(ServletContext context) {
    482         return getSAML2AttributeAuthority(context,
    483                 getContextParam(context, SAML2_AA_SID_CTX_PARAM, DEFAULT_SAML2_AA_SID));
    484     }
    485
    486     /**
    487      * Gets the {@link SAML2AttributeAuthority} bound to the Servlet context.
    488      *
    489      * @param context the Servlet context
    490      * @param serviceId the ID under which the service bound
    491      *
    492      * @return the service or null if there is no such service bound to the context
    493      */
    494     public static SAML2AttributeAuthority getSAML2AttributeAuthority(ServletContext context, String serviceId) {
    495         return (SAML2AttributeAuthority) context.getAttribute(serviceId);
    496     }
    497
    498     /**
    499      * Gets the {@link SessionManager} service bound to the Servlet context.
    500      *
    501      * @param context the Servlet context
    502      *
    503      * @return the service or null if there is no such service bound to the context
    504      */
    505     public static SessionManager<Session> getSessionManager(ServletContext context) {
    506         return getSessionManager(context,
    507                 getContextParam(context, SESSION_MNGR_SID_CTX_PARAM, DEFAULT_SESSION_MNGR_SID));
    508     }
    509
    510     /**
    511      * Gets the {@link SessionManager} bound to the Servlet context.
    512      *
    513      * @param context the Servlet context
    514      * @param serviceId the ID under which the service bound
    515      *
    516      * @return the service or null if there is no such service bound to the context
    517      */
    518     public static SessionManager<Session> getSessionManager(ServletContext context, String serviceId) {
    519         return (SessionManager<Session>) context.getAttribute(serviceId);
    520     }
    521
    522     /**
    523      * Gets the {@link StorageService} service bound to the Servlet context.
    524      *
    525      * @param context the Servlet context
    526      *
    527      * @return the service or null if there is no such service bound to the context
    528      */
    529     public static StorageService<?, ?> getStorageService(ServletContext context) {
    530         return getStorageService(context,
    531                 getContextParam(context, STORAGE_SERVICE_SID_CTX_PARAM, DEFAULT_STORAGE_SERVICE_SID));
    532     }
    533
    534     /**
    535      * Gets the {@link StorageService} bound to the Servlet context.
    536      *
    537      * @param context the Servlet context
    538      * @param serviceId the ID under which the service bound
    539      *
    540      * @return the service or null if there is no such service bound to the context
    541      */
    542     public static StorageService<?, ?> getStorageService(ServletContext context, String serviceId) {
    543         return (StorageService<?, ?>) context.getAttribute(serviceId);
    544     }
    545
    546     /**
    547      * Gets the user session from the request. Retrieving the session in this manner does NOT update the last activity
    548      * time of the session.
    549      *
    550      * @param httpRequest current request
    551      *
    552      * @return the users session, if one exists
    553      */
    554     public static Session getUserSession(HttpServletRequest httpRequest) {
    555         return (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
    556     }
    557
    558     /**
    559      * Unbinds a {@link LoginContext} from the current request. The unbinding results in the destruction of the
    560      * associated context key cookie and removes the context from the storage service.
    561      *
    562      * @param storageService storage service holding the context
    563      * @param context the Servlet context
    564      * @param httpRequest current HTTP request
    565      * @param httpResponse current HTTP response
    566      *
    567      * @return the login context that was unbound or null if there was no bound context
    568      */
    569     public static LoginContext unbindLoginContext(StorageService storageService, ServletContext context,
    570             HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
    571         log.debug("Unbinding LoginContext");
    572         if (storageService == null) {
    573             throw new IllegalArgumentException("Storage service may not be null");
    574         }
    575         if (context == null) {
    576             throw new IllegalArgumentException("Servlet context may not be null");
    577         }
    578         if (httpRequest == null) {
    579             throw new IllegalArgumentException("HTTP request may not be null");
    580         }
    581         if (httpResponse == null) {
    582             throw new IllegalArgumentException("HTTP request may not be null");
    583         }
    584
    585         Cookie loginContextKeyCookie = getCookie(httpRequest, LOGIN_CTX_KEY_NAME);
    586         if (loginContextKeyCookie == null) {
    587             log.debug("No LoginContext cookie available, no unbinding necessary.");
    588             return null;
    589         }
    590
    591         String loginContextKey = DatatypeHelper.safeTrimOrNullString(loginContextKeyCookie.getValue());
    592         if (loginContextKey == null) {
    593             log.warn("Corrupted LoginContext Key cookie, it did not contain a value");
    594             return null;
    595         }
    596
    597         log.debug("Expiring LoginContext cookie");
    598         loginContextKeyCookie.setMaxAge(0);
    599         loginContextKeyCookie.setPath("".equals(httpRequest.getContextPath()) ? "/" : httpRequest.getContextPath());
    600         loginContextKeyCookie.setVersion(1);
    601         httpResponse.addCookie(loginContextKeyCookie);
    602
    603         String storageServicePartition = getContextParam(context, LOGIN_CTX_PARTITION_CTX_PARAM,
    604                 DEFAULT_LOGIN_CTX_PARITION);
    605
    606         log.debug("Removing LoginContext, with key {}, from StorageService partition {}", loginContextKey,
    607                 storageServicePartition);
    608         LoginContextEntry entry = (LoginContextEntry) storageService.remove(storageServicePartition, loginContextKey);
    609         if (entry != null && !entry.isExpired()) {
    610             return entry.getLoginContext();
    611         }
    612
    613         return null;
    614     }
    615
    616     /**
    617      * Builds a URL, up to and including the servlet context path. URL does not include a trailing "/".
    618      *
    619      * @param httpRequest httpRequest made to the servlet in question
    620      *
    621      * @return URL builder containing the scheme, server name, server port, and context path
    622      */
    623     public static URLBuilder getServletContextUrl(HttpServletRequest httpRequest) {
    624         URLBuilder urlBuilder = new URLBuilder();
    625         urlBuilder.setScheme(httpRequest.getScheme());
    626         urlBuilder.setHost(httpRequest.getServerName());
    627         urlBuilder.setPort(httpRequest.getServerPort());
    628         urlBuilder.setPath(httpRequest.getContextPath());
    629         return urlBuilder;
    630     }
    631
    632     /**
    633      * Builds a URL to a path that is meant to be relative to the Servlet context.
    634      *
    635      * @param httpRequest current HTTP request
    636      * @param path path relative to the context, may start with a "/"
    637      *
    638      * @return URL builder containing the scheme, server name, server port, and full path
    639      */
    640     public static URLBuilder getContextRelativeUrl(HttpServletRequest httpRequest, String path) {
    641         URLBuilder urlBuilder = new URLBuilder();
    642         urlBuilder.setScheme(httpRequest.getScheme());
    643         urlBuilder.setHost(httpRequest.getServerName());
    644         urlBuilder.setPort(httpRequest.getServerPort());
    645
    646         StringBuilder pathBuilder = new StringBuilder();
    647         if (!"".equals(httpRequest.getContextPath())) {
    648             pathBuilder.append(httpRequest.getContextPath());
    649         }
    650         if (!path.startsWith("/")) {
    651             pathBuilder.append("/");
    652         }
    653         pathBuilder.append(DatatypeHelper.safeTrim(path));
    654         urlBuilder.setPath(pathBuilder.toString());
    655
    656         return urlBuilder;
    657     }
    658 }