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