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