1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.idp.authn;
18
19 import java.io.IOException;
20 import java.security.GeneralSecurityException;
21 import java.security.MessageDigest;
22 import java.security.Principal;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.Map.Entry;
30
31 import javax.security.auth.Subject;
32 import javax.servlet.RequestDispatcher;
33 import javax.servlet.ServletConfig;
34 import javax.servlet.ServletContext;
35 import javax.servlet.ServletException;
36 import javax.servlet.http.Cookie;
37 import javax.servlet.http.HttpServlet;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40
41 import org.joda.time.DateTime;
42 import org.opensaml.saml2.core.AuthnContext;
43 import org.opensaml.util.storage.StorageService;
44 import org.opensaml.ws.transport.http.HTTPTransportUtils;
45 import org.opensaml.xml.util.Base64;
46 import org.opensaml.xml.util.DatatypeHelper;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.slf4j.helpers.MessageFormatter;
50
51 import edu.internet2.middleware.shibboleth.common.session.SessionManager;
52 import edu.internet2.middleware.shibboleth.common.util.HttpHelper;
53 import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
54 import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
55 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
56 import edu.internet2.middleware.shibboleth.idp.session.Session;
57 import edu.internet2.middleware.shibboleth.idp.session.impl.AuthenticationMethodInformationImpl;
58 import edu.internet2.middleware.shibboleth.idp.session.impl.ServiceInformationImpl;
59 import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
60
61
62 public class AuthenticationEngine extends HttpServlet {
63
64
65
66
67
68 public static final String RETAIN_PUBLIC_CREDENTIALS = "retainSubjectsPublicCredentials";
69
70
71
72
73
74 public static final String RETAIN_PRIVATE_CREDENTIALS = "retainSubjectsPrivateCredentials";
75
76
77 public static final String LOGIN_CONTEXT_PARTITION_NAME_INIT_PARAM_NAME = "loginContextPartitionName";
78
79
80 public static final String LOGIN_CONTEXT_LIFETIME_INIT_PARAM_NAME = "loginContextEntryLifetime";
81
82
83 public static final String IDP_SESSION_COOKIE_NAME = "_idp_session";
84
85
86 public static final String LOGIN_CONTEXT_KEY_NAME = "_idp_authn_lc_key";
87
88
89 private static final long serialVersionUID = -8479060989001890156L;
90
91
92 private static final Logger LOG = LoggerFactory.getLogger(AuthenticationEngine.class);
93
94
95 private static ServletContext context;
96
97
98 private static StorageService<String, LoginContextEntry> storageService;
99
100
101 private boolean retainSubjectsPublicCredentials;
102
103
104 private boolean retainSubjectsPrivateCredentials;
105
106
107 private IdPProfileHandlerManager handlerManager;
108
109
110 private SessionManager<Session> sessionManager;
111
112
113 public void init(ServletConfig config) throws ServletException {
114 super.init(config);
115
116 String retain = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(RETAIN_PRIVATE_CREDENTIALS));
117 if (retain != null) {
118 retainSubjectsPrivateCredentials = Boolean.parseBoolean(retain);
119 } else {
120 retainSubjectsPrivateCredentials = false;
121 }
122
123 retain = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(RETAIN_PUBLIC_CREDENTIALS));
124 if (retain != null) {
125 retainSubjectsPublicCredentials = Boolean.parseBoolean(retain);
126 } else {
127 retainSubjectsPublicCredentials = false;
128 }
129
130 handlerManager = HttpServletHelper.getProfileHandlerManager(config.getServletContext());
131 sessionManager = HttpServletHelper.getSessionManager(config.getServletContext());
132 storageService = (StorageService<String, LoginContextEntry>) HttpServletHelper.getStorageService(config
133 .getServletContext());
134
135 context = config.getServletContext();
136 }
137
138
139
140
141
142
143
144 public static void returnToAuthenticationEngine(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
145 LOG.debug("Returning control to authentication engine");
146 LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, context, httpRequest);
147 if (loginContext == null) {
148 LOG.warn("No login context available, unable to return to authentication engine");
149 forwardRequest("/error.jsp", httpRequest, httpResponse);
150 } else {
151 forwardRequest(loginContext.getAuthenticationEngineURL(), httpRequest, httpResponse);
152 }
153 }
154
155
156
157
158
159
160
161 public static void returnToProfileHandler(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
162 LOG.debug("Returning control to profile handler");
163 LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, context, httpRequest);
164 if (loginContext == null) {
165 LOG.warn("No login context available, unable to return to profile handler");
166 forwardRequest("/error.jsp", httpRequest, httpResponse);
167 }
168
169 HttpServletHelper.bindLoginContext(loginContext, httpRequest);
170 LOG.debug("Returning control to profile handler at: {}", loginContext.getProfileHandlerURL());
171 forwardRequest(loginContext.getProfileHandlerURL(), httpRequest, httpResponse);
172 }
173
174
175
176
177
178
179
180
181 protected static void forwardRequest(String forwardPath, HttpServletRequest httpRequest,
182 HttpServletResponse httpResponse) {
183 try {
184 RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(forwardPath);
185 dispatcher.forward(httpRequest, httpResponse);
186 return;
187 } catch (IOException e) {
188 LOG.error("Unable to return control back to authentication engine", e);
189 } catch (ServletException e) {
190 LOG.error("Unable to return control back to authentication engine", e);
191 }
192 }
193
194
195 @SuppressWarnings("unchecked")
196 protected void service(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException,
197 IOException {
198 LOG.debug("Processing incoming request");
199
200 if (httpResponse.isCommitted()) {
201 LOG.error("HTTP Response already committed");
202 }
203
204 LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, getServletContext(), httpRequest);
205 if (loginContext == null) {
206 LOG.error("Incoming request does not have attached login context");
207 throw new ServletException("Incoming request does not have attached login context");
208 }
209
210 if (!loginContext.getAuthenticationAttempted()) {
211 startUserAuthentication(loginContext, httpRequest, httpResponse);
212 } else {
213 completeAuthentication(loginContext, httpRequest, httpResponse);
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226 protected void startUserAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
227 HttpServletResponse httpResponse) {
228 LOG.debug("Beginning user authentication process.");
229 try {
230 Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
231 if (idpSession != null) {
232 LOG.debug("Existing IdP session available for principal {}", idpSession.getPrincipalName());
233 }
234
235 Map<String, LoginHandler> possibleLoginHandlers = determinePossibleLoginHandlers(idpSession, loginContext);
236 LOG.debug("Possible authentication handlers for this request: {}", possibleLoginHandlers);
237
238
239 if (loginContext.isForceAuthRequired()) {
240 filterByForceAuthentication(idpSession, loginContext, possibleLoginHandlers);
241 }
242
243 if (loginContext.isPassiveAuthRequired()) {
244 filterByPassiveAuthentication(idpSession, loginContext, possibleLoginHandlers);
245 }
246
247
248
249 LOG.debug("Possible authentication handlers after filtering: {}", possibleLoginHandlers);
250 LoginHandler loginHandler;
251 if (idpSession != null && possibleLoginHandlers.containsKey(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX)) {
252 loginContext.setAttemptedAuthnMethod(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
253 loginHandler = possibleLoginHandlers.get(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
254 } else {
255 possibleLoginHandlers.remove(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
256 if (possibleLoginHandlers.isEmpty()) {
257 LOG.info("No authentication mechanism available for use with relying party '{}'", loginContext
258 .getRelyingPartyId());
259 throw new AuthenticationException();
260 }
261
262 if (loginContext.getDefaultAuthenticationMethod() != null
263 && possibleLoginHandlers.containsKey(loginContext.getDefaultAuthenticationMethod())) {
264 loginHandler = possibleLoginHandlers.get(loginContext.getDefaultAuthenticationMethod());
265 loginContext.setAttemptedAuthnMethod(loginContext.getDefaultAuthenticationMethod());
266 } else {
267 Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
268 loginContext.setAttemptedAuthnMethod(chosenLoginHandler.getKey());
269 loginHandler = chosenLoginHandler.getValue();
270 }
271 }
272
273 LOG.debug("Authenticating user with login handler of type {}", loginHandler.getClass().getName());
274 loginContext.setAuthenticationAttempted();
275 loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
276
277
278 HttpServletHelper.bindLoginContext(loginContext, storageService, getServletContext(), httpRequest,
279 httpResponse);
280 loginHandler.login(httpRequest, httpResponse);
281 } catch (AuthenticationException e) {
282 loginContext.setAuthenticationFailure(e);
283 returnToProfileHandler(httpRequest, httpResponse);
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296
297 protected Map<String, LoginHandler> determinePossibleLoginHandlers(Session idpSession, LoginContext loginContext)
298 throws AuthenticationException {
299 Map<String, LoginHandler> supportedLoginHandlers = new HashMap<String, LoginHandler>(handlerManager
300 .getLoginHandlers());
301 LOG.debug("Filtering configured login handlers by requested athentication methods.");
302 LOG.debug("Configured LoginHandlers: {}", supportedLoginHandlers);
303 LOG.debug("Requested authentication methods: {}", loginContext.getRequestedAuthenticationMethods());
304
305
306 if (loginContext.getRequestedAuthenticationMethods().isEmpty()) {
307 LOG.trace("No preference given for authentication methods");
308 return supportedLoginHandlers;
309 }
310
311
312
313
314 if (supportedLoginHandlers.containsKey(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX) && idpSession != null
315 && loginContext.getRequestedAuthenticationMethods() != null) {
316 boolean retainPreviousSession = false;
317
318 Map<String, AuthenticationMethodInformation> currentAuthnMethods = idpSession.getAuthenticationMethods();
319 for (String currentAuthnMethod : currentAuthnMethods.keySet()) {
320 if (loginContext.getRequestedAuthenticationMethods().contains(currentAuthnMethod)) {
321 retainPreviousSession = true;
322 break;
323 }
324 }
325
326 if (!retainPreviousSession) {
327 supportedLoginHandlers.remove(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
328 }
329 }
330
331
332
333 Iterator<Entry<String, LoginHandler>> supportedLoginHandlerItr = supportedLoginHandlers.entrySet().iterator();
334 Entry<String, LoginHandler> supportedLoginHandler;
335 while (supportedLoginHandlerItr.hasNext()) {
336 supportedLoginHandler = supportedLoginHandlerItr.next();
337 if (!supportedLoginHandler.getKey().equals(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX)
338 && !loginContext.getRequestedAuthenticationMethods().contains(supportedLoginHandler.getKey())) {
339 supportedLoginHandlerItr.remove();
340 continue;
341 }
342 }
343
344 if (supportedLoginHandlers.isEmpty()) {
345 LOG.warn("No authentication method, requested by the service provider, is supported");
346 throw new AuthenticationException(
347 "No authentication method, requested by the service provider, is supported");
348 }
349
350 return supportedLoginHandlers;
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364
365 protected void filterByForceAuthentication(Session idpSession, LoginContext loginContext,
366 Map<String, LoginHandler> loginHandlers) throws ForceAuthenticationException {
367 LOG.debug("Forced authentication is required, filtering possible login handlers accordingly");
368
369 ArrayList<AuthenticationMethodInformation> activeMethods = new ArrayList<AuthenticationMethodInformation>();
370 if (idpSession != null) {
371 activeMethods.addAll(idpSession.getAuthenticationMethods().values());
372 }
373
374 loginHandlers.remove(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
375
376 LoginHandler loginHandler;
377 for (AuthenticationMethodInformation activeMethod : activeMethods) {
378 loginHandler = loginHandlers.get(activeMethod.getAuthenticationMethod());
379 if (loginHandler != null && !loginHandler.supportsForceAuthentication()) {
380 for (String handlerSupportedMethods : loginHandler.getSupportedAuthenticationMethods()) {
381 loginHandlers.remove(handlerSupportedMethods);
382 }
383 }
384 }
385
386 LOG.debug("Authentication handlers remaining after forced authentication requirement filtering: {}",
387 loginHandlers);
388
389 if (loginHandlers.isEmpty()) {
390 LOG.info("Force authentication requested but no login handlers available to support it");
391 throw new ForceAuthenticationException();
392 }
393 }
394
395
396
397
398
399
400
401
402
403
404
405 protected void filterByPassiveAuthentication(Session idpSession, LoginContext loginContext,
406 Map<String, LoginHandler> loginHandlers) throws PassiveAuthenticationException {
407 LOG.debug("Passive authentication is required, filtering poassible login handlers accordingly.");
408
409 if (idpSession == null) {
410 loginHandlers.remove(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
411 }
412
413 LoginHandler loginHandler;
414 Iterator<Entry<String, LoginHandler>> authnMethodItr = loginHandlers.entrySet().iterator();
415 while (authnMethodItr.hasNext()) {
416 loginHandler = authnMethodItr.next().getValue();
417 if (!loginHandler.supportsPassive()) {
418 authnMethodItr.remove();
419 }
420 }
421
422 LOG.debug("Authentication handlers remaining after passive authentication requirement filtering: {}",
423 loginHandlers);
424
425 if (loginHandlers.isEmpty()) {
426 LOG.warn("Passive authentication required but no login handlers available to support it");
427 throw new PassiveAuthenticationException();
428 }
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442 protected void completeAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
443 HttpServletResponse httpResponse) {
444 LOG.debug("Completing user authentication process");
445
446 Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
447
448 try {
449
450
451 String actualAuthnMethod = DatatypeHelper.safeTrimOrNullString((String) httpRequest
452 .getAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY));
453 if (actualAuthnMethod != null) {
454 if (!loginContext.getRequestedAuthenticationMethods().isEmpty()
455 && !loginContext.getRequestedAuthenticationMethods().contains(actualAuthnMethod)) {
456 String msg = MessageFormatter.format(
457 "Relying patry required an authentication method of '{}' but the login handler performed '{}'",
458 loginContext.getRequestedAuthenticationMethods(), actualAuthnMethod);
459 LOG.error(msg);
460 throw new AuthenticationException(msg);
461 }
462 } else {
463 actualAuthnMethod = loginContext.getAttemptedAuthnMethod();
464 }
465
466
467 validateSuccessfulAuthentication(loginContext, httpRequest, actualAuthnMethod);
468
469
470
471 Subject subject = getLoginHandlerSubject(httpRequest);
472 if (loginContext.isForceAuthRequired()) {
473 validateForcedReauthentication(idpSession, actualAuthnMethod, subject);
474 }
475
476 loginContext.setPrincipalAuthenticated(true);
477 updateUserSession(loginContext, subject, actualAuthnMethod, httpRequest, httpResponse);
478 LOG.debug("User {} authenticated with method {}", loginContext.getPrincipalName(), loginContext
479 .getAuthenticationMethod());
480 } catch (AuthenticationException e) {
481 LOG.error("Authentication failed with the error:", e);
482 loginContext.setPrincipalAuthenticated(false);
483 loginContext.setAuthenticationFailure(e);
484 }
485
486 returnToProfileHandler(httpRequest, httpResponse);
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500
501 protected void validateSuccessfulAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
502 String authenticationMethod) throws AuthenticationException {
503 LOG.debug("Validating authentication was performed successfully");
504
505 String errorMessage = DatatypeHelper.safeTrimOrNullString((String) httpRequest
506 .getAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY));
507 if (errorMessage != null) {
508 LOG.error("Error returned from login handler for authentication method {}:\n{}", loginContext
509 .getAttemptedAuthnMethod(), errorMessage);
510 throw new AuthenticationException(errorMessage);
511 }
512
513 AuthenticationException authnException = (AuthenticationException) httpRequest
514 .getAttribute(LoginHandler.AUTHENTICATION_EXCEPTION_KEY);
515 if (authnException != null) {
516 throw authnException;
517 }
518
519 Subject subject = (Subject) httpRequest.getAttribute(LoginHandler.SUBJECT_KEY);
520 Principal principal = (Principal) httpRequest.getAttribute(LoginHandler.PRINCIPAL_KEY);
521 String principalName = DatatypeHelper.safeTrimOrNullString((String) httpRequest
522 .getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
523
524 if (subject == null && principal == null && principalName == null) {
525 LOG.error("No user identified by login handler.");
526 throw new AuthenticationException("No user identified by login handler.");
527 }
528 }
529
530
531
532
533
534
535
536
537
538
539 protected Subject getLoginHandlerSubject(HttpServletRequest httpRequest) throws AuthenticationException {
540 Subject subject = (Subject) httpRequest.getAttribute(LoginHandler.SUBJECT_KEY);
541 Principal principal = (Principal) httpRequest.getAttribute(LoginHandler.PRINCIPAL_KEY);
542 String principalName = DatatypeHelper.safeTrimOrNullString((String) httpRequest
543 .getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
544
545 if (subject == null && (principal != null || principalName != null)) {
546 subject = new Subject();
547 if (principal == null) {
548 principal = new UsernamePrincipal(principalName);
549 }
550 subject.getPrincipals().add(principal);
551 }
552
553 return subject;
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567 protected void validateForcedReauthentication(Session idpSession, String authnMethod, Subject subject)
568 throws AuthenticationException {
569 if (idpSession != null) {
570 AuthenticationMethodInformation authnMethodInfo = idpSession.getAuthenticationMethods().get(authnMethod);
571 if (authnMethodInfo != null) {
572 boolean princpalMatch = false;
573 for (Principal princpal : subject.getPrincipals()) {
574 if (authnMethodInfo.getAuthenticationPrincipal().equals(princpal)) {
575 princpalMatch = true;
576 break;
577 }
578 }
579
580 if (!princpalMatch) {
581 throw new ForceAuthenticationException(
582 "Authenticated principal does not match previously authenticated principal");
583 }
584 }
585 }
586 }
587
588
589
590
591
592
593
594
595
596
597
598 protected void updateUserSession(LoginContext loginContext, Subject authenticationSubject,
599 String authenticationMethod, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
600 Principal authenticationPrincipal = authenticationSubject.getPrincipals().iterator().next();
601 LOG.debug("Updating session information for principal {}", authenticationPrincipal.getName());
602
603 Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
604 if (idpSession == null) {
605 LOG.debug("Creating shibboleth session for principal {}", authenticationPrincipal.getName());
606 idpSession = (Session) sessionManager.createSession();
607 loginContext.setSessionID(idpSession.getSessionID());
608 addSessionCookie(httpRequest, httpResponse, idpSession);
609 }
610
611
612
613 idpSession.setSubject(mergeSubjects(idpSession.getSubject(), authenticationSubject));
614
615 LOG.debug("Recording authentication and service information in Shibboleth session for principal: {}",
616 authenticationPrincipal.getName());
617 LoginHandler loginHandler = handlerManager.getLoginHandlers().get(loginContext.getAttemptedAuthnMethod());
618 AuthenticationMethodInformation authnMethodInfo = new AuthenticationMethodInformationImpl(idpSession
619 .getSubject(), authenticationPrincipal, authenticationMethod, new DateTime(), loginHandler
620 .getAuthenticationDuration());
621
622 loginContext.setAuthenticationMethodInformation(authnMethodInfo);
623 idpSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
624 sessionManager.indexSession(idpSession, authnMethodInfo.getAuthenticationPrincipal().getName());
625
626 ServiceInformation serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(),
627 authnMethodInfo);
628 idpSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
629 }
630
631
632
633
634
635
636
637
638
639
640
641
642
643 protected Subject mergeSubjects(Subject subject1, Subject subject2) {
644 if (subject1 == null && subject2 == null) {
645 return new Subject();
646 }
647
648 if (subject1 == null) {
649 return subject2;
650 }
651
652 if (subject2 == null) {
653 return subject1;
654 }
655
656 Set<Principal> principals = new HashSet<Principal>(3);
657 principals.addAll(subject1.getPrincipals());
658 principals.addAll(subject2.getPrincipals());
659
660 Set<Object> publicCredentials = new HashSet<Object>(3);
661 if (retainSubjectsPublicCredentials) {
662 LOG.debug("Merging in subjects public credentials");
663 publicCredentials.addAll(subject1.getPublicCredentials());
664 publicCredentials.addAll(subject2.getPublicCredentials());
665 }
666
667 Set<Object> privateCredentials = new HashSet<Object>(3);
668 if (retainSubjectsPrivateCredentials) {
669 LOG.debug("Merging in subjects private credentials");
670 privateCredentials.addAll(subject1.getPrivateCredentials());
671 privateCredentials.addAll(subject2.getPrivateCredentials());
672 }
673
674 return new Subject(false, principals, publicCredentials, privateCredentials);
675 }
676
677
678
679
680
681
682
683
684 protected void addSessionCookie(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
685 Session userSession) {
686 httpRequest.setAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE, userSession);
687
688 byte[] remoteAddress = httpRequest.getRemoteAddr().getBytes();
689 byte[] sessionId = userSession.getSessionID().getBytes();
690
691 String signature = null;
692 try {
693 MessageDigest digester = MessageDigest.getInstance("SHA");
694 digester.update(userSession.getSessionSecret());
695 digester.update(remoteAddress);
696 digester.update(sessionId);
697 signature = Base64.encodeBytes(digester.digest());
698 } catch (GeneralSecurityException e) {
699 LOG.error("Unable to compute signature over session cookie material", e);
700 }
701
702 LOG.debug("Adding IdP session cookie to HTTP response");
703 StringBuilder cookieValue = new StringBuilder();
704 cookieValue.append(Base64.encodeBytes(remoteAddress, Base64.DONT_BREAK_LINES)).append("|");
705 cookieValue.append(Base64.encodeBytes(sessionId, Base64.DONT_BREAK_LINES)).append("|");
706 cookieValue.append(signature);
707
708 Cookie sessionCookie = new Cookie(IDP_SESSION_COOKIE_NAME, HTTPTransportUtils.urlEncode(cookieValue.toString()));
709 sessionCookie.setVersion(1);
710 sessionCookie.setPath(httpRequest.getContextPath() == "" ? "/" : httpRequest.getContextPath());
711 sessionCookie.setSecure(httpRequest.isSecure());
712 httpResponse.addCookie(sessionCookie);
713 }
714 }