001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nelson Silva <nelson.silva@inevo.pt> 016 */ 017package org.nuxeo.ecm.platform.auth.saml; 018 019import org.apache.commons.lang.StringUtils; 020import org.apache.commons.logging.Log; 021import org.apache.commons.logging.LogFactory; 022import org.nuxeo.common.utils.i18n.I18NUtils; 023import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; 024import org.nuxeo.ecm.platform.auth.saml.binding.HTTPPostBinding; 025import org.nuxeo.ecm.platform.auth.saml.binding.HTTPRedirectBinding; 026import org.nuxeo.ecm.platform.auth.saml.binding.SAMLBinding; 027import org.nuxeo.ecm.platform.auth.saml.key.KeyManager; 028import org.nuxeo.ecm.platform.auth.saml.slo.SLOProfile; 029import org.nuxeo.ecm.platform.auth.saml.slo.SLOProfileImpl; 030import org.nuxeo.ecm.platform.auth.saml.sso.WebSSOProfile; 031import org.nuxeo.ecm.platform.auth.saml.sso.WebSSOProfileImpl; 032import org.nuxeo.ecm.platform.auth.saml.user.EmailBasedUserResolver; 033import org.nuxeo.ecm.platform.auth.saml.user.UserMapperBasedResolver; 034import org.nuxeo.ecm.platform.auth.saml.user.AbstractUserResolver; 035import org.nuxeo.ecm.platform.auth.saml.user.UserResolver; 036import org.nuxeo.ecm.platform.ui.web.auth.LoginScreenHelper; 037import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants; 038import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; 039import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension; 040import org.nuxeo.ecm.platform.ui.web.auth.service.LoginProviderLinkComputer; 041import org.nuxeo.runtime.api.Framework; 042import org.nuxeo.usermapper.service.UserMapperService; 043import org.opensaml.DefaultBootstrap; 044import org.opensaml.common.SAMLException; 045import org.opensaml.common.SAMLObject; 046import org.opensaml.common.binding.BasicSAMLMessageContext; 047import org.opensaml.common.binding.SAMLMessageContext; 048import org.opensaml.common.xml.SAMLConstants; 049import org.opensaml.saml2.core.AuthnRequest; 050import org.opensaml.saml2.core.LogoutRequest; 051import org.opensaml.saml2.core.LogoutResponse; 052import org.opensaml.saml2.core.NameID; 053import org.opensaml.saml2.encryption.Decrypter; 054import org.opensaml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver; 055import org.opensaml.saml2.metadata.EntityDescriptor; 056import org.opensaml.saml2.metadata.IDPSSODescriptor; 057import org.opensaml.saml2.metadata.RoleDescriptor; 058import org.opensaml.saml2.metadata.SPSSODescriptor; 059import org.opensaml.saml2.metadata.SingleLogoutService; 060import org.opensaml.saml2.metadata.SingleSignOnService; 061import org.opensaml.saml2.metadata.provider.AbstractMetadataProvider; 062import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; 063import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; 064import org.opensaml.saml2.metadata.provider.MetadataProvider; 065import org.opensaml.saml2.metadata.provider.MetadataProviderException; 066import org.opensaml.security.MetadataCredentialResolver; 067import org.opensaml.ws.message.decoder.MessageDecodingException; 068import org.opensaml.ws.transport.InTransport; 069import org.opensaml.ws.transport.http.HttpServletRequestAdapter; 070import org.opensaml.ws.transport.http.HttpServletResponseAdapter; 071import org.opensaml.xml.Configuration; 072import org.opensaml.xml.ConfigurationException; 073import org.opensaml.xml.encryption.ChainingEncryptedKeyResolver; 074import org.opensaml.xml.encryption.InlineEncryptedKeyResolver; 075import org.opensaml.xml.encryption.SimpleRetrievalMethodEncryptedKeyResolver; 076import org.opensaml.xml.parse.BasicParserPool; 077import org.opensaml.xml.security.credential.Credential; 078import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; 079import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver; 080import org.opensaml.xml.signature.SignatureTrustEngine; 081import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; 082 083import javax.servlet.ServletException; 084import javax.servlet.http.Cookie; 085import javax.servlet.http.HttpServletRequest; 086import javax.servlet.http.HttpServletResponse; 087import javax.servlet.http.HttpSession; 088 089import java.io.File; 090import java.io.IOException; 091import java.util.ArrayList; 092import java.util.HashMap; 093import java.util.List; 094import java.util.Map; 095 096import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_ERROR; 097 098/** 099 * A SAML2 authentication provider. 100 * 101 * @since 6.0 102 */ 103public class SAMLAuthenticationProvider implements NuxeoAuthenticationPlugin, LoginProviderLinkComputer, 104 NuxeoAuthenticationPluginLogoutExtension { 105 106 private static final Log log = LogFactory.getLog(SAMLAuthenticationProvider.class); 107 108 private static final String ERROR_PAGE = "saml/error.jsp"; 109 private static final String ERROR_AUTH = "error.saml.auth"; 110 private static final String ERROR_USER = "error.saml.userMapping"; 111 112 // User Resolver 113 private static final Class<? extends UserResolver> DEFAULT_USER_RESOLVER_CLASS = EmailBasedUserResolver.class; 114 private static final Class<? extends UserResolver> USERMAPPER_USER_RESOLVER_CLASS = UserMapperBasedResolver.class; 115 116 117 // SAML Constants 118 static final String SAML_SESSION_KEY = "SAML_SESSION"; 119 120 // Supported SAML Bindings 121 // TODO: Allow registering new bindings 122 static List<SAMLBinding> bindings = new ArrayList<>(); 123 static { 124 bindings.add(new HTTPPostBinding()); 125 bindings.add(new HTTPRedirectBinding()); 126 } 127 128 // Decryption key resolver 129 private static ChainingEncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver(); 130 static { 131 encryptedKeyResolver.getResolverChain().add(new InlineEncryptedKeyResolver()); 132 encryptedKeyResolver.getResolverChain().add(new EncryptedElementTypeEncryptedKeyResolver()); 133 encryptedKeyResolver.getResolverChain().add(new SimpleRetrievalMethodEncryptedKeyResolver()); 134 } 135 136 // Profiles supported by the IdP 137 private Map<String, AbstractSAMLProfile> profiles = new HashMap<>(); 138 139 private UserResolver userResolver; 140 141 private KeyManager keyManager; 142 143 private SignatureTrustEngine trustEngine; 144 145 private Decrypter decrypter; 146 147 private MetadataProvider metadataProvider; 148 149 @Override 150 public void initPlugin(Map<String, String> parameters) { 151 152 // Initialize the User Resolver 153 String userResolverClassname = parameters.get("userResolverClass"); 154 Class<? extends UserResolver> userResolverClass = null; 155 if (StringUtils.isBlank(userResolverClassname)) { 156 UserMapperService ums = Framework.getService(UserMapperService.class); 157 if (ums!=null) { 158 userResolverClass = USERMAPPER_USER_RESOLVER_CLASS; 159 } else { 160 userResolverClass = DEFAULT_USER_RESOLVER_CLASS; 161 } 162 } else { 163 try { 164 userResolverClass = Class.forName(userResolverClassname).asSubclass(AbstractUserResolver.class); 165 } catch (ClassNotFoundException e) { 166 log.error("Failed get user resolver class " + userResolverClassname); 167 } 168 169 } 170 try { 171 userResolver = userResolverClass.newInstance(); 172 userResolver.init(parameters); 173 } catch (InstantiationException | IllegalAccessException e) { 174 log.error("Failed to initialize user resolver " + userResolverClassname); 175 } 176 177 // Initialize the OpenSAML library 178 try { 179 DefaultBootstrap.bootstrap(); 180 } catch (ConfigurationException e) { 181 log.error("Failed to bootstrap OpenSAML", e); 182 } 183 184 // Read the IdP metadata and initialize the supported profiles 185 try { 186 // Read the IdP metadata 187 initializeMetadataProvider(parameters); 188 189 // Setup Signature Trust Engine 190 MetadataCredentialResolver metadataCredentialResolver = new MetadataCredentialResolver(metadataProvider); 191 trustEngine = new ExplicitKeySignatureTrustEngine( 192 metadataCredentialResolver, 193 org.opensaml.xml.Configuration.getGlobalSecurityConfiguration().getDefaultKeyInfoCredentialResolver()); 194 195 // Setup decrypter 196 Credential encryptionCredential = getKeyManager().getEncryptionCredential(); 197 if (encryptionCredential != null) { 198 KeyInfoCredentialResolver resolver = new StaticKeyInfoCredentialResolver(encryptionCredential); 199 decrypter = new Decrypter(null, resolver, encryptedKeyResolver); 200 decrypter.setRootInNewDocument(true); 201 } 202 203 // Process IdP roles 204 for (RoleDescriptor roleDescriptor : getIdPDescriptor().getRoleDescriptors()) { 205 206 // Web SSO role 207 if (roleDescriptor.getElementQName().equals(IDPSSODescriptor.DEFAULT_ELEMENT_NAME) 208 && roleDescriptor.isSupportedProtocol(org.opensaml.common.xml.SAMLConstants.SAML20P_NS)) { 209 210 IDPSSODescriptor idpSSO = (IDPSSODescriptor) roleDescriptor; 211 212 // SSO 213 for (SingleSignOnService sso : idpSSO.getSingleSignOnServices()) { 214 if (sso.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { 215 addProfile(new WebSSOProfileImpl(sso)); 216 break; 217 } 218 } 219 220 // SLO 221 for (SingleLogoutService slo : idpSSO.getSingleLogoutServices()) { 222 if (slo.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { 223 addProfile(new SLOProfileImpl(slo)); 224 break; 225 } 226 } 227 } 228 } 229 230 } catch (MetadataProviderException e) { 231 log.warn("Failed to register IdP: " + e.getMessage()); 232 } 233 234 // contribute icon and link to the Login Screen 235 if (StringUtils.isNotBlank(parameters.get("name"))) { 236 LoginScreenHelper.registerLoginProvider(parameters.get("name"), parameters.get("icon"), null, 237 parameters.get("label"), parameters.get("description"), this); 238 } 239 } 240 241 private void addProfile(AbstractSAMLProfile profile) { 242 profile.setTrustEngine(trustEngine); 243 profile.setDecrypter(decrypter); 244 profiles.put(profile.getProfileIdentifier(), profile); 245 } 246 247 private void initializeMetadataProvider(Map<String, String> parameters) throws MetadataProviderException { 248 AbstractMetadataProvider metadataProvider; 249 250 String metadataUrl = parameters.get("metadata"); 251 if (metadataUrl == null) { 252 throw new MetadataProviderException("No metadata URI set for provider " 253 + ((parameters.containsKey("name")) ? parameters.get("name") : "")); 254 } 255 256 int requestTimeout = parameters.containsKey("timeout") ? Integer.parseInt(parameters.get("timeout")) : 5; 257 258 if (metadataUrl.startsWith("http:") || metadataUrl.startsWith("https:")) { 259 metadataProvider = new HTTPMetadataProvider(metadataUrl, requestTimeout * 1000); 260 } else { // file 261 metadataProvider = new FilesystemMetadataProvider(new File(metadataUrl)); 262 } 263 264 metadataProvider.setParserPool(new BasicParserPool()); 265 metadataProvider.initialize(); 266 267 this.metadataProvider = metadataProvider; 268 } 269 270 private EntityDescriptor getIdPDescriptor() throws MetadataProviderException { 271 return (EntityDescriptor) metadataProvider.getMetadata(); 272 } 273 274 /** 275 * Returns a Login URL to use with HTTP Redirect 276 */ 277 protected String getSSOUrl(HttpServletRequest request, HttpServletResponse response) { 278 WebSSOProfile sso = (WebSSOProfile) profiles.get(WebSSOProfile.PROFILE_URI); 279 if (sso == null) { 280 return null; 281 } 282 283 // Create and populate the context 284 SAMLMessageContext context = new BasicSAMLMessageContext(); 285 populateLocalContext(context); 286 287 // Store the requested URL in the Relay State 288 String requestedUrl = getRequestedUrl(request); 289 if (requestedUrl != null) { 290 context.setRelayState(requestedUrl); 291 } 292 293 // Build Uri 294 HTTPRedirectBinding binding = (HTTPRedirectBinding) getBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); 295 String loginURL = sso.getEndpoint().getLocation(); 296 try { 297 AuthnRequest authnRequest = sso.buildAuthRequest(request); 298 authnRequest.setDestination(sso.getEndpoint().getLocation()); 299 context.setOutboundSAMLMessage(authnRequest); 300 loginURL = binding.buildRedirectURL(context, sso.getEndpoint().getLocation()); 301 } catch (SAMLException e) { 302 log.error("Failed to build redirect URL", e); 303 } 304 return loginURL; 305 } 306 307 private String getRequestedUrl(HttpServletRequest request) { 308 String requestedUrl = (String) request.getAttribute(NXAuthConstants.REQUESTED_URL); 309 if (requestedUrl == null) { 310 HttpSession session = request.getSession(false); 311 if (session != null) { 312 requestedUrl = (String) session.getAttribute(NXAuthConstants.START_PAGE_SAVE_KEY); 313 } 314 } 315 return requestedUrl; 316 } 317 318 @Override 319 public String computeUrl(HttpServletRequest request, String requestedUrl) { 320 return getSSOUrl(request, null); 321 } 322 323 @Override 324 public Boolean handleLoginPrompt(HttpServletRequest request, HttpServletResponse response, String baseURL) { 325 326 String loginError = (String) request.getAttribute(LOGIN_ERROR); 327 if (loginError != null) { 328 try { 329 request.getRequestDispatcher(ERROR_PAGE).forward(request, response); 330 return true; 331 } catch (ServletException | IOException e) { 332 log.error("Failed to redirect to error page", e); 333 return false; 334 } 335 } 336 337 String loginURL = getSSOUrl(request, response); 338 try { 339 response.sendRedirect(loginURL); 340 } catch (IOException e) { 341 String errorMessage = String.format("Unable to send redirect on %s", loginURL); 342 log.error(errorMessage, e); 343 return false; 344 } 345 return true; 346 } 347 348 // Retrieves user identification information from the request. 349 @Override 350 public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest request, HttpServletResponse response) { 351 352 HttpServletRequestAdapter inTransport = new HttpServletRequestAdapter(request); 353 SAMLBinding binding = getBinding(inTransport); 354 355 // Check if we support this binding 356 if (binding == null) { 357 return null; 358 } 359 360 HttpServletResponseAdapter outTransport = new HttpServletResponseAdapter(response, request.isSecure()); 361 362 // Create and populate the context 363 SAMLMessageContext context = new BasicSAMLMessageContext(); 364 context.setInboundMessageTransport(inTransport); 365 context.setOutboundMessageTransport(outTransport); 366 populateLocalContext(context); 367 368 // Decode the message 369 try { 370 binding.decode(context); 371 } catch (org.opensaml.xml.security.SecurityException | MessageDecodingException e) { 372 log.error("Error during SAML decoding", e); 373 return null; 374 } 375 376 // Set Peer context info if needed 377 try { 378 if (context.getPeerEntityId() == null) { 379 context.setPeerEntityId(getIdPDescriptor().getEntityID()); 380 } 381 if (context.getPeerEntityMetadata() == null) { 382 context.setPeerEntityMetadata(getIdPDescriptor()); 383 } 384 if (context.getPeerEntityRole() == null) { 385 context.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); 386 } 387 } catch (MetadataProviderException e) { 388 // 389 } 390 391 // Check for a response processor for this profile 392 AbstractSAMLProfile processor = getProcessor(context); 393 394 if (processor == null) { 395 log.warn("Unsupported profile encountered in the context " + context.getCommunicationProfileId()); 396 return null; 397 } 398 399 // Set the communication profile 400 context.setCommunicationProfileId(processor.getProfileIdentifier()); 401 402 // Delegate handling the message to the processor 403 SAMLObject message = context.getInboundSAMLMessage(); 404 405 // Handle SLO 406 // TODO - Try to handle IdP initiated SLO somewhere else 407 if (processor instanceof SLOProfile) { 408 SLOProfile slo = (SLOProfile) processor; 409 try { 410 // Handle SLO response 411 if (message instanceof LogoutResponse) { 412 slo.processLogoutResponse(context); 413 // Handle SLO request 414 } else if (message instanceof LogoutRequest) { 415 SAMLCredential credential = getSamlCredential(request); 416 slo.processLogoutRequest(context, credential); 417 } 418 } catch (SAMLException e) { 419 log.debug("Error processing SAML message", e); 420 } 421 return null; 422 } 423 424 // Handle SSO 425 SAMLCredential credential; 426 427 try { 428 credential = ((WebSSOProfile) processor).processAuthenticationResponse(context); 429 } catch (SAMLException e) { 430 log.error("Error processing SAML message", e); 431 sendError(request, ERROR_AUTH); 432 return null; 433 } 434 435 String userId = userResolver.findOrCreateNuxeoUser(credential); 436 437 if (userId == null) { 438 log.warn("Failed to resolve user with NameID \"" + credential.getNameID().getValue() + "\"."); 439 sendError(request, ERROR_USER); 440 return null; 441 } 442 443 // Store session id in a cookie 444 if (credential.getSessionIndexes() != null && !credential.getSessionIndexes().isEmpty()) { 445 String nameValue = credential.getNameID().getValue(); 446 String nameFormat = credential.getNameID().getFormat(); 447 String sessionId = credential.getSessionIndexes().get(0); 448 addCookie(response, SAML_SESSION_KEY, sessionId + "|" + nameValue + "|" + nameFormat); 449 } 450 451 // Redirect to URL in relay state if any 452 HttpSession session = request.getSession(!response.isCommitted()); 453 if (session != null) { 454 if (StringUtils.isNotEmpty(credential.getRelayState())) { 455 session.setAttribute(NXAuthConstants.START_PAGE_SAVE_KEY, credential.getRelayState()); 456 } 457 } 458 459 return new UserIdentificationInfo(userId, userId); 460 } 461 462 protected AbstractSAMLProfile getProcessor(SAMLMessageContext context) { 463 String profileId; 464 SAMLObject message = context.getInboundSAMLMessage(); 465 if (message instanceof LogoutResponse || message instanceof LogoutRequest) { 466 profileId = SLOProfile.PROFILE_URI; 467 } else { 468 profileId = WebSSOProfile.PROFILE_URI; 469 } 470 471 return profiles.get(profileId); 472 } 473 474 protected SAMLBinding getBinding(String bindingURI) { 475 for (SAMLBinding binding : bindings) { 476 if (binding.getBindingURI().equals(bindingURI)) { 477 return binding; 478 } 479 } 480 return null; 481 } 482 483 protected SAMLBinding getBinding(InTransport transport) { 484 for (SAMLBinding binding : bindings) { 485 if (binding.supports(transport)) { 486 return binding; 487 } 488 } 489 return null; 490 } 491 492 private void populateLocalContext(SAMLMessageContext context) { 493 // Set local info 494 context.setLocalEntityId(SAMLConfiguration.getEntityId()); 495 context.setLocalEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); 496 context.setMetadataProvider(metadataProvider); 497 498 // Set the signing key 499 keyManager = Framework.getLocalService(KeyManager.class); 500 if (getKeyManager().getSigningCredential() != null) { 501 context.setOutboundSAMLMessageSigningCredential(getKeyManager().getSigningCredential()); 502 } 503 } 504 505 @Override 506 public Boolean needLoginPrompt(HttpServletRequest httpRequest) { 507 return true; 508 } 509 510 @Override 511 public List<String> getUnAuthenticatedURLPrefix() { 512 return null; 513 } 514 515 /** 516 * Returns a Logout URL to use with HTTP Redirect 517 */ 518 protected String getSLOUrl(HttpServletRequest request, HttpServletResponse response) { 519 SLOProfile slo = (SLOProfile) profiles.get(SLOProfile.PROFILE_URI); 520 if (slo == null) { 521 return null; 522 } 523 524 String logoutURL = slo.getEndpoint().getLocation(); 525 526 SAMLCredential credential = getSamlCredential(request); 527 528 // Create and populate the context 529 SAMLMessageContext context = new BasicSAMLMessageContext(); 530 populateLocalContext(context); 531 532 try { 533 LogoutRequest logoutRequest = slo.buildLogoutRequest(context, credential); 534 logoutRequest.setDestination(slo.getEndpoint().getLocation()); 535 context.setOutboundSAMLMessage(logoutRequest); 536 537 HTTPRedirectBinding binding = (HTTPRedirectBinding) getBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); 538 logoutURL = binding.buildRedirectURL(context, slo.getEndpoint().getLocation()); 539 } catch (SAMLException e) { 540 log.error("Failed to get SAML Logout request", e); 541 } 542 543 return logoutURL; 544 } 545 546 private SAMLCredential getSamlCredential(HttpServletRequest request) { 547 SAMLCredential credential = null; 548 549 // Retrieve the SAMLCredential credential from cookie 550 Cookie cookie = getCookie(request, SAML_SESSION_KEY); 551 if (cookie != null) { 552 String[] parts = cookie.getValue().split("\\|"); 553 String sessionId = parts[0]; 554 String nameValue = parts[1]; 555 String nameFormat = parts[2]; 556 557 NameID nameID = (NameID) Configuration.getBuilderFactory().getBuilder(NameID.DEFAULT_ELEMENT_NAME).buildObject( 558 NameID.DEFAULT_ELEMENT_NAME); 559 nameID.setValue(nameValue); 560 nameID.setFormat(nameFormat); 561 562 List<String> sessionIndexes = new ArrayList<>(); 563 sessionIndexes.add(sessionId); 564 565 credential = new SAMLCredential(nameID, sessionIndexes); 566 } 567 568 return credential; 569 } 570 571 @Override 572 public Boolean handleLogout(HttpServletRequest request, HttpServletResponse response) { 573 String logoutURL = getSLOUrl(request, response); 574 575 if (logoutURL == null) { 576 return false; 577 } 578 579 if (log.isDebugEnabled()) { 580 log.debug("Send redirect to " + logoutURL); 581 } 582 583 try { 584 response.sendRedirect(logoutURL); 585 } catch (IOException e) { 586 String errorMessage = String.format("Unable to send redirect on %s", logoutURL); 587 log.error(errorMessage, e); 588 return false; 589 } 590 591 Cookie cookie = getCookie(request, SAML_SESSION_KEY); 592 if (cookie != null) { 593 removeCookie(response, cookie); 594 } 595 596 return true; 597 } 598 599 private void sendError(HttpServletRequest req, String key) { 600 String msg = I18NUtils.getMessageString("messages", key, null, req.getLocale()); 601 req.setAttribute(LOGIN_ERROR, msg); 602 } 603 604 private KeyManager getKeyManager() { 605 if (keyManager == null) { 606 keyManager = Framework.getLocalService(KeyManager.class); 607 } 608 return keyManager; 609 } 610 611 private void addCookie(HttpServletResponse httpResponse, String name, String value) { 612 Cookie cookie = new Cookie(name, value); 613 httpResponse.addCookie(cookie); 614 } 615 616 private Cookie getCookie(HttpServletRequest httpRequest, String cookieName) { 617 Cookie cookies[] = httpRequest.getCookies(); 618 if (cookies != null) { 619 for (Cookie cooky : cookies) { 620 if (cookieName.equals(cooky.getName())) { 621 return cooky; 622 } 623 } 624 } 625 return null; 626 } 627 628 private void removeCookie(HttpServletResponse httpResponse, Cookie cookie) { 629 log.debug(String.format("Removing cookie %s.", cookie.getName())); 630 cookie.setMaxAge(0); 631 cookie.setValue(""); 632 httpResponse.addCookie(cookie); 633 } 634}