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