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