001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: SPACSUtils.java,v 1.48 2009/11/20 21:41:16 exu Exp $ 026 * 027 * Portions Copyrighted 2010-2014 ForgeRock AS. 028 */ 029package com.sun.identity.saml2.profile; 030 031import java.io.ByteArrayInputStream; 032import java.io.IOException; 033import java.io.PrintWriter; 034import java.util.ArrayList; 035import java.util.Date; 036import java.util.HashSet; 037import java.util.Iterator; 038import java.util.Map; 039import java.util.HashMap; 040import java.util.List; 041import java.util.logging.Level; 042import java.util.Set; 043 044import javax.servlet.http.HttpServletResponse; 045import javax.servlet.http.HttpServletRequest; 046import javax.servlet.ServletException; 047import java.security.cert.X509Certificate; 048 049import javax.xml.soap.SOAPConnection; 050import javax.xml.soap.SOAPException; 051import javax.xml.soap.SOAPMessage; 052 053import com.sun.identity.saml2.common.*; 054import org.w3c.dom.Document; 055import org.w3c.dom.Element; 056import com.sun.identity.common.SystemConfigurationUtil; 057import com.sun.identity.liberty.ws.soapbinding.Message; 058import com.sun.identity.liberty.ws.soapbinding.SOAPBindingException; 059import com.sun.identity.liberty.ws.soapbinding.SOAPFaultException; 060import com.sun.identity.shared.xml.XMLUtils; 061import com.sun.identity.shared.encode.Base64; 062import com.sun.identity.shared.encode.URLEncDec; 063import com.sun.identity.saml.common.SAMLConstants; 064import com.sun.identity.saml.common.SAMLUtils; 065import com.sun.identity.saml.xmlsig.KeyProvider; 066import com.sun.identity.saml2.assertion.Advice; 067import com.sun.identity.saml2.assertion.AssertionFactory; 068import com.sun.identity.saml2.assertion.Issuer; 069import com.sun.identity.saml2.assertion.Assertion; 070import com.sun.identity.saml2.assertion.AttributeStatement; 071import com.sun.identity.saml2.assertion.NameID; 072import com.sun.identity.saml2.assertion.EncryptedID; 073import com.sun.identity.saml2.assertion.EncryptedAttribute; 074 075import com.sun.identity.saml2.ecp.ECPFactory; 076import com.sun.identity.saml2.ecp.ECPRelayState; 077import com.sun.identity.saml2.jaxb.entityconfig.IDPSSOConfigElement; 078import com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement; 079import com.sun.identity.saml2.jaxb.metadata.AffiliationDescriptorType; 080import com.sun.identity.saml2.jaxb.metadata.ArtifactResolutionServiceElement; 081import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement; 082import com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement; 083import com.sun.identity.saml2.key.KeyUtil; 084import com.sun.identity.saml2.logging.LogUtil; 085import com.sun.identity.saml2.meta.SAML2MetaException; 086import com.sun.identity.saml2.meta.SAML2MetaManager; 087import com.sun.identity.saml2.meta.SAML2MetaUtils; 088import com.sun.identity.saml2.protocol.Artifact; 089import com.sun.identity.saml2.protocol.ArtifactResolve; 090import com.sun.identity.saml2.protocol.ArtifactResponse; 091import com.sun.identity.saml2.protocol.AuthnRequest; 092import com.sun.identity.saml2.protocol.ProtocolFactory; 093import com.sun.identity.saml2.protocol.Response; 094import com.sun.identity.saml2.protocol.Status; 095import com.sun.identity.saml2.plugins.SAML2ServiceProviderAdapter; 096import com.sun.identity.saml2.plugins.SPAccountMapper; 097import com.sun.identity.saml2.plugins.SPAttributeMapper; 098 099import com.sun.identity.plugin.monitoring.FedMonAgent; 100import com.sun.identity.plugin.monitoring.FedMonSAML2Svc; 101import com.sun.identity.plugin.monitoring.MonitorManager; 102import com.sun.identity.plugin.session.SessionException; 103import com.sun.identity.plugin.session.SessionManager; 104import com.sun.identity.plugin.session.SessionProvider; 105 106import org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException; 107import org.forgerock.openam.utils.ClientUtils; 108 109import java.security.PrivateKey; 110 111/** 112 * This class is used by a service provider (SP) to process the response from 113 * an identity provider for the SP's Assertion Consumer Service. 114 * 115 * @supported.api 116 */ 117public class SPACSUtils { 118 119 private static FedMonAgent agent = MonitorManager.getAgent(); 120 private static FedMonSAML2Svc saml2Svc = MonitorManager.getSAML2Svc(); 121 122 private SPACSUtils() {} 123 124 /** 125 * Retrieves <code>SAML</code> <code>Response</code> from http request. 126 * It handles three cases: 127 * <pre> 128 * 1. using http method get using request parameter "resID". 129 * This is the case after local login is done. 130 * 2. using http method get using request parameter "SAMLart". 131 * This is the case for artifact profile. 132 * 3. using http method post. This is the case for post profile. 133 * </pre> 134 * 135 * @param request http servlet request 136 * @param response http servlet response 137 * @param orgName realm or organization name the service provider resides in 138 * @param hostEntityId Entity ID of the hosted service provider 139 * @param metaManager <code>SAML2MetaManager</code> instance. 140 * @return <code>ResponseInfo</code> instance. 141 * @throws SAML2Exception,IOException if it fails in the process. 142 */ 143 public static ResponseInfo getResponse( 144 HttpServletRequest request, 145 HttpServletResponse response, 146 String orgName, 147 String hostEntityId, 148 SAML2MetaManager metaManager) 149 throws SAML2Exception,IOException 150 { 151 ResponseInfo respInfo = null; 152 153 String method = request.getMethod(); 154 if (method.equals("GET")) { 155 if (!SAML2Utils.isSPProfileBindingSupported( 156 orgName, hostEntityId, SAML2Constants.ACS_SERVICE, 157 SAML2Constants.HTTP_ARTIFACT)) 158 { 159 SAMLUtils.sendError(request, response, 160 response.SC_BAD_REQUEST, 161 "unsupportedBinding", 162 SAML2Utils.bundle.getString("unsupportedBinding")); 163 throw new SAML2Exception( 164 SAML2Utils.bundle.getString("unsupportedBinding")); 165 } 166 respInfo = getResponseFromGet(request, response, orgName, 167 hostEntityId, metaManager); 168 } else if (method.equals("POST")) { 169 String pathInfo = request.getPathInfo(); 170 if ((pathInfo != null) && (pathInfo.startsWith("/ECP"))) { 171 if (!SAML2Utils.isSPProfileBindingSupported( 172 orgName, hostEntityId, SAML2Constants.ACS_SERVICE, 173 SAML2Constants.PAOS)) 174 { 175 SAMLUtils.sendError(request, response, 176 response.SC_BAD_REQUEST, 177 "unsupportedBinding", 178 SAML2Utils.bundle.getString("unsupportedBinding")); 179 throw new SAML2Exception( 180 SAML2Utils.bundle.getString("unsupportedBinding")); 181 } 182 respInfo = getResponseFromPostECP(request, response, orgName, 183 hostEntityId, metaManager); 184 } else { 185 if (!SAML2Utils.isSPProfileBindingSupported( 186 orgName, hostEntityId, SAML2Constants.ACS_SERVICE, 187 SAML2Constants.HTTP_POST)) 188 { 189 SAMLUtils.sendError(request, response, 190 response.SC_BAD_REQUEST, 191 "unsupportedBinding", 192 SAML2Utils.bundle.getString("unsupportedBinding")); 193 throw new SAML2Exception( 194 SAML2Utils.bundle.getString("unsupportedBinding")); 195 } 196 respInfo = getResponseFromPost(request, response, orgName, 197 hostEntityId, metaManager); 198 } 199 } else { 200 // not supported 201 SAMLUtils.sendError(request, response, 202 response.SC_METHOD_NOT_ALLOWED, 203 "notSupportedHTTPMethod", 204 SAML2Utils.bundle.getString("notSupportedHTTPMethod")); 205 throw new SAML2Exception( 206 SAML2Utils.bundle.getString("notSupportedHTTPMethod")); 207 } 208 if (SAML2Utils.debug.messageEnabled()) { 209 SAML2Utils.debug.message("SPACSUtils.getResponse: got response=" 210 + respInfo.getResponse().toXMLString(true, true)); 211 } 212 return respInfo; 213 } 214 215 /** 216 * Retrieves <code>SAML Response</code> from http Get. 217 * It first uses parameter resID to retrieve <code>Response</code>. This is 218 * the case after local login; 219 * If resID is not defined, it then uses <code>SAMLart</code> http 220 * parameter to retrieve <code>Response</code>. 221 */ 222 private static ResponseInfo getResponseFromGet( 223 HttpServletRequest request, 224 HttpServletResponse response, 225 String orgName, 226 String hostEntityId, 227 SAML2MetaManager metaManager) 228 throws SAML2Exception,IOException 229 { 230 ResponseInfo respInfo = null; 231 String resID = request.getParameter("resID"); 232 if (resID != null && resID.length() != 0) { 233 if (SAML2Utils.debug.messageEnabled()) { 234 SAML2Utils.debug.message("SPACSUtils.getResponseFromGet: resID=" 235 + resID); 236 } 237 synchronized (SPCache.responseHash) { 238 respInfo = (ResponseInfo) SPCache.responseHash.remove(resID); 239 } 240 if (respInfo == null) { 241 if (SAML2Utils.debug.messageEnabled()) { 242 SAML2Utils.debug.message("SPACSUtils.getResponseFromGet: " 243 + "couldn't find Response from resID."); 244 } 245 String[] data = {resID}; 246 LogUtil.error(Level.INFO, 247 LogUtil.RESPONSE_NOT_FOUND_FROM_CACHE, 248 data, 249 null); 250 SAMLUtils.sendError(request, response, 251 response.SC_INTERNAL_SERVER_ERROR, "SSOFailed", 252 SAML2Utils.bundle.getString("SSOFailed")); 253 throw new SAML2Exception( 254 SAML2Utils.bundle.getString("SSOFailed")); 255 } 256 return respInfo; 257 } 258 259 String samlArt = request.getParameter(SAML2Constants.SAML_ART); 260 if (samlArt == null || samlArt.trim().length() == 0) { 261 SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: Artifact " 262 + "string is empty."); 263 LogUtil.error(Level.INFO, 264 LogUtil.MISSING_ARTIFACT, 265 null, 266 null); 267 SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST, 268 "missingArtifact", 269 SAML2Utils.bundle.getString("missingArtifact")); 270 throw new SAML2Exception( 271 SAML2Utils.bundle.getString("missingArtifact")); 272 } 273 274 return new ResponseInfo(getResponseFromArtifact(samlArt, hostEntityId, 275 request, response, orgName, metaManager), 276 SAML2Constants.HTTP_ARTIFACT, null); 277 } 278 279 // Retrieves response using artifact profile. 280 private static Response getResponseFromArtifact(String samlArt, 281 String hostEntityId, HttpServletRequest request, 282 HttpServletResponse response, String orgName, 283 SAML2MetaManager sm) throws SAML2Exception,IOException 284 { 285 286 // Try to get source ID and endpointIndex, and then 287 // decide which IDP and which artifact resolution service 288 if (SAML2Utils.debug.messageEnabled()) { 289 SAML2Utils.debug.message("SPACSUtils.getResponseFromArtifact: " + 290 "samlArt = " + samlArt); 291 } 292 293 Artifact art = null; 294 try { 295 art = ProtocolFactory.getInstance().createArtifact(samlArt.trim()); 296 String[] data = {samlArt.trim()}; 297 LogUtil.access(Level.INFO, 298 LogUtil.RECEIVED_ARTIFACT, 299 data, 300 null); 301 } catch (SAML2Exception se) { 302 SAML2Utils.debug.error("SPACSUtils.getResponseFromArtifact: " 303 + "Unable to decode and parse artifact string:" + samlArt); 304 SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST, 305 "errorObtainArtifact", 306 SAML2Utils.bundle.getString("errorObtainArtifact")); 307 throw se; 308 } 309 310 String idpEntityID = getIDPEntityID(art, request, response, orgName, sm); 311 IDPSSODescriptorElement idp = null; 312 try { 313 idp = sm.getIDPSSODescriptor(orgName, idpEntityID); 314 } catch (SAML2MetaException se) { 315 String[] data = {orgName, idpEntityID}; 316 LogUtil.error(Level.INFO, 317 LogUtil.IDP_META_NOT_FOUND, 318 data, 319 null); 320 SAMLUtils.sendError(request, response, 321 response.SC_INTERNAL_SERVER_ERROR, 322 "failedToGetIDPSSODescriptor", se.getMessage()); 323 throw se; 324 } 325 326 String location = getIDPArtifactResolutionServiceUrl( 327 art.getEndpointIndex(), idpEntityID, idp, request, response); 328 329 // create ArtifactResolve message 330 ArtifactResolve resolve = null; 331 SOAPMessage resMsg = null; 332 try { 333 resolve = ProtocolFactory.getInstance().createArtifactResolve(); 334 resolve.setID(SAML2Utils.generateID()); 335 resolve.setVersion(SAML2Constants.VERSION_2_0); 336 resolve.setIssueInstant(new Date()); 337 resolve.setArtifact(art); 338 resolve.setDestination(XMLUtils.escapeSpecialCharacters(location)); 339 Issuer issuer = AssertionFactory.getInstance().createIssuer(); 340 issuer.setValue(hostEntityId); 341 resolve.setIssuer(issuer); 342 String needArtiResolveSigned = 343 SAML2Utils.getAttributeValueFromSSOConfig( 344 orgName, 345 idpEntityID, 346 SAML2Constants.IDP_ROLE, 347 SAML2Constants.WANT_ARTIFACT_RESOLVE_SIGNED); 348 349 if (needArtiResolveSigned != null && 350 needArtiResolveSigned.equals("true")) { 351 // or save it somewhere? 352 String signAlias = getAttributeValueFromSPSSOConfig( 353 orgName, 354 hostEntityId, 355 sm, 356 SAML2Constants.SIGNING_CERT_ALIAS); 357 if (signAlias == null) { 358 throw new SAML2Exception( 359 SAML2Utils.bundle.getString("missingSigningCertAlias")); 360 } 361 KeyProvider kp = KeyUtil.getKeyProviderInstance(); 362 if (kp == null) { 363 throw new SAML2Exception( 364 SAML2Utils.bundle.getString("nullKeyProvider")); 365 } 366 resolve.sign(kp.getPrivateKey(signAlias), 367 kp.getX509Certificate(signAlias)); 368 } 369 370 String resolveString = resolve.toXMLString(true, true); 371 if (SAML2Utils.debug.messageEnabled()) { 372 SAML2Utils.debug.message("SPACSUtils.getResponseFromArtifact: " 373 + "ArtifactResolve=" + resolveString); 374 } 375 376 SOAPConnection con = SAML2Utils.scf.createConnection(); 377 SOAPMessage msg = SAML2Utils.createSOAPMessage(resolveString, true); 378 379 IDPSSOConfigElement config = null; 380 config = sm.getIDPSSOConfig(orgName, idpEntityID); 381 location = SAML2Utils.fillInBasicAuthInfo( 382 config, location); 383 resMsg = con.call(msg, location); 384 } catch (SAML2Exception s2e) { 385 SAML2Utils.debug.error("SPACSUtils.getResponseFromArtifact: " 386 + "couldn't create ArtifactResolve:", s2e); 387 String[] data = {hostEntityId, art.getArtifactValue()}; 388 LogUtil.error(Level.INFO, 389 LogUtil.CANNOT_CREATE_ARTIFACT_RESOLVE, 390 data, 391 null); 392 SAMLUtils.sendError(request, response, 393 response.SC_INTERNAL_SERVER_ERROR, 394 "errorCreateArtifactResolve", 395 SAML2Utils.bundle.getString("errorCreateArtifactResolve")); 396 throw s2e; 397 } catch (SOAPException se) { 398 SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: " 399 + "couldn't get ArtifactResponse. SOAP error:",se); 400 String[] data = {hostEntityId, location}; 401 LogUtil.error(Level.INFO, 402 LogUtil.CANNOT_GET_SOAP_RESPONSE, 403 data, 404 null); 405 SAMLUtils.sendError(request, response, 406 response.SC_INTERNAL_SERVER_ERROR, 407 "errorInSOAPCommunication", 408 SAML2Utils.bundle.getString("errorInSOAPCommunication")); 409 throw new SAML2Exception(se.getMessage()); 410 } 411 412 Response result = getResponseFromSOAP(resMsg, resolve, request, 413 response, idpEntityID, idp, orgName, hostEntityId, sm); 414 String[] data = {hostEntityId, idpEntityID, 415 art.getArtifactValue(), ""}; 416 if (LogUtil.isAccessLoggable(Level.FINE)) { 417 data[3] = result.toXMLString(); 418 } 419 LogUtil.access(Level.INFO, 420 LogUtil.GOT_RESPONSE_FROM_ARTIFACT, 421 data, 422 null); 423 return result; 424 } 425 426 // Finds the IDP who sends the artifact; 427 private static String getIDPEntityID( 428 Artifact art, 429 HttpServletRequest request, 430 HttpServletResponse response, 431 String orgName, 432 SAML2MetaManager metaManager) 433 throws SAML2Exception,IOException 434 { 435 String sourceID = art.getSourceID(); 436 // find the idp 437 String idpEntityID = null; 438 try { 439 Iterator iter = 440 metaManager.getAllRemoteIdentityProviderEntities(orgName). 441 iterator(); 442 String tmpSourceID = null; 443 while (iter.hasNext()) { 444 idpEntityID = (String) iter.next(); 445 tmpSourceID = SAML2Utils.generateSourceID(idpEntityID); 446 if (sourceID.equals(tmpSourceID)) { 447 break; 448 } 449 idpEntityID = null; 450 } 451 if (idpEntityID == null) { 452 SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: Unable " 453 + "to find the IDP based on the SourceID in the artifact"); 454 String[] data = {art.getArtifactValue(), orgName}; 455 LogUtil.error(Level.INFO, 456 LogUtil.IDP_NOT_FOUND, 457 data, 458 null); 459 throw new SAML2Exception( 460 SAML2Utils.bundle.getString("cannotFindIDP")); 461 } 462 } catch (SAML2Exception se) { 463 String[] data = {art.getArtifactValue(), orgName}; 464 LogUtil.error(Level.INFO, 465 LogUtil.IDP_NOT_FOUND, 466 data, 467 null); 468 SAMLUtils.sendError(request, response, 469 response.SC_INTERNAL_SERVER_ERROR, 470 "cannotFindIDP", se.getMessage()); 471 throw se; 472 } 473 return idpEntityID; 474 } 475 476 // Retrieves the ArtifactResolutionServiceURL for an IDP. 477 private static String getIDPArtifactResolutionServiceUrl( 478 int endpointIndex, 479 String idpEntityID, 480 IDPSSODescriptorElement idp, 481 HttpServletRequest request, 482 HttpServletResponse response) 483 throws SAML2Exception,IOException 484 { 485 // find the artifact resolution service url 486 List arsList=idp.getArtifactResolutionService(); 487 ArtifactResolutionServiceElement ars = null; 488 String location = null; 489 String defaultLocation = null; 490 String firstLocation = null; 491 int index; 492 boolean isDefault = false; 493 for (int i=0; i<arsList.size(); i++) { 494 ars = (ArtifactResolutionServiceElement)arsList.get(i); 495 location = ars.getLocation(); 496 //String binding = ars.getBinding(); 497 index = ars.getIndex(); 498 isDefault = ars.isIsDefault(); 499 if (index == endpointIndex) { 500 break; 501 } 502 if (isDefault) { 503 defaultLocation = location; 504 } 505 if (i==0) { 506 firstLocation = location; 507 } 508 location = null; 509 } 510 if (location == null || location.length() == 0) { 511 location = defaultLocation; 512 if (location == null || location.length() == 0) { 513 location = firstLocation; 514 if (location == null || location.length() == 0) { 515 SAML2Utils.debug.error("SPACSUtils: Unable to get the " 516 + "location of artifact resolution service for " 517 + idpEntityID); 518 String[] data = {idpEntityID}; 519 LogUtil.error(Level.INFO, 520 LogUtil.ARTIFACT_RESOLUTION_URL_NOT_FOUND, 521 data, 522 null); 523 SAMLUtils.sendError(request, response, 524 response.SC_INTERNAL_SERVER_ERROR, 525 "cannotFindArtifactResolutionUrl", 526 SAML2Utils.bundle.getString( 527 "cannotFindArtifactResolutionUrl")); 528 throw new SAML2Exception( 529 SAML2Utils.bundle.getString( 530 "cannotFindArtifactResolutionUrl")); 531 } 532 } 533 } 534 if (SAML2Utils.debug.messageEnabled()) { 535 SAML2Utils.debug.message("SPACSUtils: IDP artifact resolution " 536 + "service url =" + location); 537 } 538 return location; 539 } 540 541 /** 542 * Obtains <code>SAML Response</code> from <code>SOAPBody</code>. 543 * Used by Artifact profile. 544 */ 545 private static Response getResponseFromSOAP(SOAPMessage resMsg, 546 ArtifactResolve resolve, 547 HttpServletRequest request, 548 HttpServletResponse response, 549 String idpEntityID, 550 IDPSSODescriptorElement idp, 551 String orgName, 552 String hostEntityId, 553 SAML2MetaManager sm) 554 throws SAML2Exception,IOException 555 { 556 String method = "SPACSUtils.getResponseFromSOAP:"; 557 Element resElem = null; 558 try { 559 resElem = SAML2Utils.getSamlpElement(resMsg, "ArtifactResponse"); 560 } catch (SAML2Exception se) { 561 String[] data = {idpEntityID}; 562 LogUtil.error(Level.INFO, 563 LogUtil.SOAP_ERROR, 564 data, 565 null); 566 SAMLUtils.sendError(request, response, 567 response.SC_INTERNAL_SERVER_ERROR, 568 "soapError", se.getMessage()); 569 throw se; 570 } 571 ArtifactResponse artiResp = null; 572 try { 573 artiResp = ProtocolFactory.getInstance(). 574 createArtifactResponse(resElem); 575 } catch (SAML2Exception se) { 576 if (SAML2Utils.debug.messageEnabled()) { 577 SAML2Utils.debug.message(method + "Couldn't create " 578 + "ArtifactResponse:", se); 579 } 580 String[] data = {idpEntityID}; 581 LogUtil.error(Level.INFO, 582 LogUtil.CANNOT_INSTANTIATE_ARTIFACT_RESPONSE, 583 data, 584 null); 585 SAMLUtils.sendError(request, response, 586 response.SC_INTERNAL_SERVER_ERROR, 587 "failedToCreateArtifactResponse", se.getMessage()); 588 throw se; 589 } 590 591 if (artiResp == null) { 592 String[] data = {idpEntityID}; 593 LogUtil.error(Level.INFO, 594 LogUtil.MISSING_ARTIFACT_RESPONSE, 595 data, 596 null); 597 SAMLUtils.sendError(request, response, 598 response.SC_INTERNAL_SERVER_ERROR, 599 "missingArtifactResponse", 600 SAML2Utils.bundle.getString("missingArtifactResponse")); 601 throw new SAML2Exception( 602 SAML2Utils.bundle.getString("missingArtifactResponse")); 603 } else { 604 if (SAML2Utils.debug.messageEnabled()) { 605 SAML2Utils.debug.message(method + "Received ArtifactResponse:" 606 + artiResp.toXMLString(true, true)); 607 } 608 } 609 610 // verify ArtifactResponse 611 String wantArtiRespSigned = getAttributeValueFromSPSSOConfig( 612 orgName, 613 hostEntityId, 614 sm, 615 SAML2Constants.WANT_ARTIFACT_RESPONSE_SIGNED); 616 if (wantArtiRespSigned != null && wantArtiRespSigned.equals("true")) { 617 X509Certificate cert = KeyUtil.getVerificationCert( 618 idp, idpEntityID, SAML2Constants.IDP_ROLE); 619 if (!artiResp.isSigned() || !artiResp.isSignatureValid(cert)) { 620 if (SAML2Utils.debug.messageEnabled()) { 621 SAML2Utils.debug.message(method 622 + "ArtifactResponse's signature is invalid."); 623 } 624 String[] data = {idpEntityID}; 625 LogUtil.error(Level.INFO, 626 LogUtil.ARTIFACT_RESPONSE_INVALID_SIGNATURE, 627 data, 628 null); 629 SAMLUtils.sendError(request, response, 630 response.SC_INTERNAL_SERVER_ERROR, "invalidSignature", 631 SAML2Utils.bundle.getString("invalidSignature")); 632 throw new SAML2Exception( 633 SAML2Utils.bundle.getString("invalidSignature")); 634 } 635 } 636 637 String inResponseTo = artiResp.getInResponseTo(); 638 if (inResponseTo == null || !inResponseTo.equals(resolve.getID())) { 639 if (SAML2Utils.debug.messageEnabled()) { 640 SAML2Utils.debug.message(method 641 + "ArtifactResponse's InResponseTo is invalid."); 642 } 643 String[] data = {idpEntityID}; 644 LogUtil.error(Level.INFO, 645 LogUtil.ARTIFACT_RESPONSE_INVALID_INRESPONSETO, 646 data, 647 null); 648 SAMLUtils.sendError(request, response, 649 response.SC_INTERNAL_SERVER_ERROR, "invalidInResponseTo", 650 SAML2Utils.bundle.getString("invalidInResponseTo")); 651 throw new SAML2Exception( 652 SAML2Utils.bundle.getString("invalidInResponseTo")); 653 } 654 655 Issuer idpIssuer = artiResp.getIssuer(); 656 if (idpIssuer == null || !idpIssuer.getValue().equals(idpEntityID)) { 657 if (SAML2Utils.debug.messageEnabled()) { 658 SAML2Utils.debug.message(method 659 + "ArtifactResponse's Issuer is invalid."); 660 } 661 String[] data = {idpEntityID}; 662 LogUtil.error(Level.INFO, 663 LogUtil.ARTIFACT_RESPONSE_INVALID_ISSUER, 664 data, 665 null); 666 SAMLUtils.sendError(request, response, 667 response.SC_INTERNAL_SERVER_ERROR, "invalidIssuer", 668 SAML2Utils.bundle.getString("invalidIssuer")); 669 throw new SAML2Exception( 670 SAML2Utils.bundle.getString("invalidIssuer")); 671 } 672 673 // check time? 674 675 Status status = artiResp.getStatus(); 676 if (status == null || !status.getStatusCode().getValue().equals( 677 SAML2Constants.SUCCESS)) 678 { 679 String statusCode = 680 (status == null)?"":status.getStatusCode().getValue(); 681 if (SAML2Utils.debug.messageEnabled()) { 682 SAML2Utils.debug.message(method 683 + "ArtifactResponse's status code is not success." 684 + statusCode); 685 } 686 String[] data = {idpEntityID, ""}; 687 if (LogUtil.isErrorLoggable(Level.FINE)) { 688 data[1] = statusCode; 689 } 690 LogUtil.error(Level.INFO, 691 LogUtil.ARTIFACT_RESPONSE_INVALID_STATUS_CODE, 692 data, 693 null); 694 SAMLUtils.sendError(request, response, 695 response.SC_INTERNAL_SERVER_ERROR, "invalidStatusCode", 696 SAML2Utils.bundle.getString("invalidStatusCode")); 697 throw new SAML2Exception( 698 SAML2Utils.bundle.getString("invalidStatusCode")); 699 } 700 701 try { 702 return ProtocolFactory.getInstance().createResponse( 703 artiResp.getAny()); 704 } catch (SAML2Exception se) { 705 if (SAML2Utils.debug.messageEnabled()) { 706 SAML2Utils.debug.message(method 707 + "couldn't instantiate Response:", se); 708 } 709 String[] data = {idpEntityID}; 710 LogUtil.error(Level.INFO, 711 LogUtil.CANNOT_INSTANTIATE_RESPONSE_ARTIFACT, 712 data, 713 null); 714 SAMLUtils.sendError(request, response, 715 response.SC_INTERNAL_SERVER_ERROR, 716 "failedToCreateResponse", se.getMessage()); 717 throw se; 718 } 719 } 720 721 /** 722 * Obtains <code>SAML Response</code> from <code>SOAPBody</code>. 723 * Used by ECP profile. 724 */ 725 private static ResponseInfo getResponseFromPostECP( 726 HttpServletRequest request, HttpServletResponse response, 727 String orgName, String hostEntityId, SAML2MetaManager metaManager) 728 throws SAML2Exception,IOException 729 { 730 Message message = null; 731 try { 732 message = new Message(SAML2Utils.getSOAPMessage(request)); 733 } catch (SOAPException soapex) { 734 String[] data = { hostEntityId } ; 735 LogUtil.error(Level.INFO, 736 LogUtil.CANNOT_INSTANTIATE_SOAP_MESSAGE_ECP, data, null); 737 SAMLUtils.sendError(request, response, 738 response.SC_INTERNAL_SERVER_ERROR, 739 "failedToCreateSOAPMessage", soapex.getMessage()); 740 throw new SAML2Exception(soapex.getMessage()); 741 } catch (SOAPBindingException soapex) { 742 String[] data = { hostEntityId } ; 743 LogUtil.error(Level.INFO, 744 LogUtil.CANNOT_INSTANTIATE_SOAP_MESSAGE_ECP, data, null); 745 SAMLUtils.sendError(request, response, 746 response.SC_INTERNAL_SERVER_ERROR, 747 "failedToCreateSOAPMessage", soapex.getMessage()); 748 throw new SAML2Exception(soapex.getMessage()); 749 } catch(SOAPFaultException sfex) { 750 String[] data = { hostEntityId } ; 751 LogUtil.error(Level.INFO, LogUtil.RECEIVE_SOAP_FAULT_ECP, 752 data, null); 753 String faultString = 754 sfex.getSOAPFaultMessage().getSOAPFault().getFaultString(); 755 SAMLUtils.sendError(request, response, 756 response.SC_INTERNAL_SERVER_ERROR, 757 "failedToCreateSOAPMessage", faultString); 758 throw new SAML2Exception(faultString); 759 } 760 761 List soapHeaders = message.getOtherSOAPHeaders(); 762 ECPRelayState ecpRelayState = null; 763 if ((soapHeaders != null) && (!soapHeaders.isEmpty())) { 764 for(Iterator iter = soapHeaders.iterator(); iter.hasNext();) { 765 Element headerEle = (Element)iter.next(); 766 try { 767 ecpRelayState = 768 ECPFactory.getInstance().createECPRelayState(headerEle); 769 break; 770 } catch (SAML2Exception saml2ex) { 771 // not ECP RelayState 772 } 773 } 774 } 775 String relayState = null; 776 if (ecpRelayState != null) { 777 relayState = ecpRelayState.getValue(); 778 } 779 780 List soapBodies = message.getBodies(); 781 if ((soapBodies == null) || (soapBodies.isEmpty())) { 782 String[] data = { hostEntityId } ; 783 LogUtil.error(Level.INFO, 784 LogUtil.CANNOT_INSTANTIATE_SAML_RESPONSE_FROM_ECP, data, null); 785 SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST, 786 "missingSAMLResponse", 787 SAML2Utils.bundle.getString("missingSAMLResponse")); 788 throw new SAML2Exception( 789 SAML2Utils.bundle.getString("missingSAMLResponse")); 790 } 791 792 Element resElem = (Element)soapBodies.get(0); 793 794 Response resp = null; 795 try { 796 resp = ProtocolFactory.getInstance().createResponse(resElem); 797 } catch (SAML2Exception se) { 798 if (SAML2Utils.debug.messageEnabled()) { 799 SAML2Utils.debug.message("SPACSUtils.getResponseFromPostECP:" + 800 "Couldn't create Response:", se); 801 } 802 String[] data = { hostEntityId } ; 803 LogUtil.error(Level.INFO, 804 LogUtil.CANNOT_INSTANTIATE_SAML_RESPONSE_FROM_ECP, data, null); 805 SAMLUtils.sendError(request, response, 806 response.SC_INTERNAL_SERVER_ERROR, 807 "failedToCreateResponse", se.getMessage()); 808 throw se; 809 } 810 811 String idpEntityID = resp.getIssuer().getValue(); 812 IDPSSODescriptorElement idpDesc = null; 813 try { 814 idpDesc = metaManager.getIDPSSODescriptor(orgName, idpEntityID); 815 } catch (SAML2MetaException se) { 816 String[] data = { orgName, idpEntityID }; 817 LogUtil.error(Level.INFO, LogUtil.IDP_META_NOT_FOUND, data, null); 818 SAMLUtils.sendError(request, response, 819 response.SC_INTERNAL_SERVER_ERROR, 820 "failedToGetIDPSSODescriptor", se.getMessage()); 821 throw se; 822 } 823 824 X509Certificate cert = KeyUtil.getVerificationCert(idpDesc, 825 idpEntityID, SAML2Constants.IDP_ROLE); 826 List assertions = resp.getAssertion(); 827 if ((assertions != null) && (!assertions.isEmpty())) { 828 for(Iterator iter = assertions.iterator(); iter.hasNext(); ) { 829 Assertion assertion = (Assertion)iter.next(); 830 if (!assertion.isSigned()) { 831 if (SAML2Utils.debug.messageEnabled()) { 832 SAML2Utils.debug.message( 833 "SPACSUtils.getResponseFromPostECP: " + 834 " Assertion is not signed."); 835 } 836 String[] data = { idpEntityID }; 837 LogUtil.error(Level.INFO, 838 LogUtil.ECP_ASSERTION_NOT_SIGNED, data, null); 839 SAMLUtils.sendError(request, response, 840 response.SC_INTERNAL_SERVER_ERROR, 841 "assertionNotSigned", 842 SAML2Utils.bundle.getString("assertionNotSigned")); 843 throw new SAML2Exception( 844 SAML2Utils.bundle.getString("assertionNotSigned")); 845 } else if (!assertion.isSignatureValid(cert)) { 846 if (SAML2Utils.debug.messageEnabled()) { 847 SAML2Utils.debug.message( 848 "SPACSUtils.getResponseFromPostECP: " + 849 " Assertion signature is invalid."); 850 } 851 String[] data = { idpEntityID }; 852 LogUtil.error(Level.INFO, 853 LogUtil.ECP_ASSERTION_INVALID_SIGNATURE, data, null); 854 SAMLUtils.sendError(request, response, 855 response.SC_INTERNAL_SERVER_ERROR, 856 "invalidSignature", 857 SAML2Utils.bundle.getString("invalidSignature")); 858 throw new SAML2Exception( 859 SAML2Utils.bundle.getString("invalidSignature")); 860 } 861 } 862 } 863 864 return new ResponseInfo(resp, SAML2Constants.PAOS, relayState); 865 } 866 867 // Obtains SAML Response from POST. 868 private static ResponseInfo getResponseFromPost(HttpServletRequest request, 869 HttpServletResponse response, String orgName, String hostEntityId, 870 SAML2MetaManager metaManager) throws SAML2Exception,IOException 871 { 872 String classMethod = "SPACSUtils:getResponseFromPost"; 873 SAML2Utils.debug.message("SPACSUtils:getResponseFromPost"); 874 875 String samlArt = request.getParameter(SAML2Constants.SAML_ART); 876 if ((samlArt != null) && (samlArt.trim().length() != 0)) { 877 return new ResponseInfo(getResponseFromArtifact(samlArt, 878 hostEntityId, request, response, orgName, metaManager), 879 SAML2Constants.HTTP_ARTIFACT, null); 880 } 881 882 String samlResponse = request.getParameter( 883 SAML2Constants.SAML_RESPONSE); 884 if (samlResponse == null) { 885 LogUtil.error(Level.INFO, 886 LogUtil.MISSING_SAML_RESPONSE_FROM_POST, 887 null, 888 null); 889 SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST, 890 "missingSAMLResponse", 891 SAML2Utils.bundle.getString("missingSAMLResponse")); 892 throw new SAML2Exception( 893 SAML2Utils.bundle.getString("missingSAMLResponse")); 894 } 895 896 // Get Response back 897 // decode the Response 898 Response resp = null; 899 ByteArrayInputStream bis = null; 900 try { 901 byte[] raw = Base64.decode(samlResponse); 902 if (raw != null) { 903 bis = new ByteArrayInputStream(raw); 904 Document doc = XMLUtils.toDOMDocument(bis, SAML2Utils.debug); 905 if (doc != null) { 906 resp = ProtocolFactory.getInstance(). 907 createResponse(doc.getDocumentElement()); 908 } 909 } 910 } catch (SAML2Exception se) { 911 SAML2Utils.debug.error("SPACSUtils.getResponse: Exception " 912 + "when instantiating SAMLResponse:", se); 913 LogUtil.error(Level.INFO, 914 LogUtil.CANNOT_INSTANTIATE_RESPONSE_POST, 915 null, 916 null); 917 SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST, 918 "errorObtainResponse", 919 SAML2Utils.bundle.getString("errorObtainResponse")); 920 throw new SAML2Exception( 921 SAML2Utils.bundle.getString("errorObtainResponse")); 922 923 } catch (Exception e) { 924 SAML2Utils.debug.error("SPACSUtils.getResponse: Exception " 925 + "when decoding SAMLResponse:", e); 926 LogUtil.error(Level.INFO, 927 LogUtil.CANNOT_DECODE_RESPONSE, 928 null, 929 null); 930 SAMLUtils.sendError(request, response, 931 response.SC_INTERNAL_SERVER_ERROR, "errorDecodeResponse", 932 SAML2Utils.bundle.getString("errorDecodeResponse")); 933 throw new SAML2Exception( 934 SAML2Utils.bundle.getString("errorDecodeResponse")); 935 } finally { 936 if (bis != null) { 937 try { 938 bis.close(); 939 } catch (Exception ie) { 940 if (SAML2Utils.debug.messageEnabled()) { 941 SAML2Utils.debug.message("SPACSUtils.getResponse: " 942 + "Exception when close the input stream:", ie); 943 } 944 } 945 } 946 } 947 948 if (resp != null) { 949 // verify signature in Response 950 boolean needPOSTResponseSigned = 951 SAML2Utils.wantPOSTResponseSigned( 952 orgName,hostEntityId,SAML2Constants.SP_ROLE); 953 String idpEntityID = null; 954 Issuer issuer = resp.getIssuer(); 955 if (issuer != null) { 956 idpEntityID = issuer.getValue(); 957 } else { 958 List assertions = resp.getAssertion(); 959 if ((assertions != null) && (!assertions.isEmpty())) { 960 for (Iterator iter = assertions.iterator(); 961 iter.hasNext(); ) { 962 Assertion assertion = (Assertion)iter.next(); 963 idpEntityID = assertion.getIssuer().getValue(); 964 break; 965 } 966 } 967 } 968 IDPSSODescriptorElement idp = null; 969 try { 970 idp = metaManager.getIDPSSODescriptor(orgName,idpEntityID); 971 } catch (SAML2MetaException se) { 972 String[] data = {orgName,hostEntityId,idpEntityID}; 973 LogUtil.error(Level.INFO, 974 LogUtil.IDP_META_NOT_FOUND, 975 data, 976 null); 977 SAMLUtils.sendError(request, response, 978 response.SC_INTERNAL_SERVER_ERROR, 979 "failedToGetIDPSSODescriptor", se.getMessage()); 980 throw se; 981 } 982 if (needPOSTResponseSigned) { 983 X509Certificate cert = KeyUtil.getVerificationCert( 984 idp, idpEntityID, SAML2Constants.IDP_ROLE); 985 if (!resp.isSigned() || !resp.isSignatureValid(cert)) { 986 SAML2Utils.debug.error(classMethod + 987 " Signature in Response is invalid "); 988 String[] data = { orgName , hostEntityId , idpEntityID }; 989 LogUtil.error(Level.INFO, 990 LogUtil.POST_RESPONSE_INVALID_SIGNATURE,data,null); 991 SAMLUtils.sendError(request, response, 992 response.SC_INTERNAL_SERVER_ERROR, "invalidSignature", 993 SAML2Utils.bundle.getString("invalidSignature")); 994 throw new SAML2Exception( 995 SAML2Utils.bundle.getString("invalidSignInResponse")); 996 } 997 } 998 String[] data = {""}; 999 if (LogUtil.isAccessLoggable(Level.FINE)) { 1000 data[0] = resp.toXMLString(); 1001 } 1002 LogUtil.access(Level.INFO, 1003 LogUtil.GOT_RESPONSE_FROM_POST, 1004 data, 1005 null); 1006 return (new ResponseInfo(resp, SAML2Constants.HTTP_POST, null)); 1007 } 1008 if (SAML2Utils.debug.messageEnabled()) { 1009 SAML2Utils.debug.message("SPACSUtils.getResponse: Decoded response, " + 1010 "resp is null"); 1011 } 1012 return null; 1013 } 1014 1015 /** 1016 * Authenticates user with <code>Response</code>. 1017 * Auth session upgrade will be called if input session is 1018 * not null. 1019 * Otherwise, saml2 auth module is called. The name of the auth module 1020 * is retrieved from <code>SPSSOConfig</code>. If not found, "SAML2" will 1021 * be used. 1022 * 1023 * @param request HTTP Servlet request 1024 * @param response HTTP Servlet response. 1025 * @param out the print writer for writing out presentation 1026 * @param metaAlias metaAlias for the service provider 1027 * @param session input session object. It could be null. 1028 * @param respInfo <code>ResponseInfo</code> to be verified. 1029 * @param realm realm or organization name of the service provider. 1030 * @param hostEntityId hosted service provider Entity ID. 1031 * @param metaManager <code>SAML2MetaManager</code> instance for meta 1032 * operation. 1033 * @return <code>Object</code> which holds result of the session. 1034 * @throws SAML2Exception if the processing failed. 1035 */ 1036 public static Object processResponse( 1037 HttpServletRequest request, HttpServletResponse response, PrintWriter out, 1038 String metaAlias, Object session, ResponseInfo respInfo, 1039 String realm, String hostEntityId, SAML2MetaManager metaManager 1040 ) throws SAML2Exception { 1041 1042 String classMethod = "SPACSUtils.processResponse: "; 1043 if (SAML2Utils.debug.messageEnabled()) { 1044 SAML2Utils.debug.message(classMethod + "Response : " + 1045 respInfo.getResponse()); 1046 } 1047 Map smap = null; 1048 try { 1049 // check Response/Assertion and get back a Map of relevant data 1050 smap = SAML2Utils.verifyResponse(request, response, 1051 respInfo.getResponse(), realm, hostEntityId, 1052 respInfo.getProfileBinding()); 1053 } catch (SAML2Exception se) { 1054 // invoke SPAdapter for failure 1055 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1056 request, response, smap, respInfo, 1057 SAML2ServiceProviderAdapter.INVALID_RESPONSE, se); 1058 throw se; 1059 } 1060 1061 com.sun.identity.saml2.assertion.Subject assertionSubject = 1062 (com.sun.identity.saml2.assertion.Subject) 1063 smap.get(SAML2Constants.SUBJECT); 1064 NameID nameId = assertionSubject.getNameID(); 1065 EncryptedID encId = assertionSubject.getEncryptedID(); 1066 Assertion authnAssertion = 1067 (Assertion) smap.get(SAML2Constants.POST_ASSERTION); 1068 String sessionIndex = (String)smap.get(SAML2Constants.SESSION_INDEX); 1069 respInfo.setSessionIndex(sessionIndex); 1070 Integer authLevel = (Integer) smap.get(SAML2Constants.AUTH_LEVEL); 1071 Long maxSessionTime = (Long) smap.get(SAML2Constants.MAX_SESSION_TIME); 1072 String inRespToResp = (String) smap.get(SAML2Constants.IN_RESPONSE_TO); 1073 List assertions = (List) smap.get(SAML2Constants.ASSERTIONS); 1074 1075 if (SAML2Utils.debug.messageEnabled()) { 1076 SAML2Utils.debug.message(classMethod + "Assertions : " + 1077 assertions); 1078 } 1079 1080 SPSSOConfigElement spssoconfig = 1081 metaManager.getSPSSOConfig(realm, hostEntityId); 1082 1083 // get mappers 1084 SPAccountMapper acctMapper = SAML2Utils.getSPAccountMapper(realm, hostEntityId); 1085 SPAttributeMapper attrMapper = SAML2Utils.getSPAttributeMapper(realm, hostEntityId); 1086 1087 boolean needAttributeEncrypted = false; 1088 boolean needNameIDEncrypted = false; 1089 String assertionEncryptedAttr = 1090 SAML2Utils.getAttributeValueFromSPSSOConfig( 1091 spssoconfig, 1092 SAML2Constants.WANT_ASSERTION_ENCRYPTED); 1093 if (assertionEncryptedAttr == null || 1094 !assertionEncryptedAttr.equals("true")) 1095 { 1096 String attrEncryptedStr = 1097 SAML2Utils.getAttributeValueFromSPSSOConfig( 1098 spssoconfig, 1099 SAML2Constants.WANT_ATTRIBUTE_ENCRYPTED); 1100 if (attrEncryptedStr != null && 1101 attrEncryptedStr.equals("true")) 1102 { 1103 needAttributeEncrypted = true; 1104 } 1105 String idEncryptedStr = 1106 SAML2Utils.getAttributeValueFromSPSSOConfig( 1107 spssoconfig, 1108 SAML2Constants.WANT_NAMEID_ENCRYPTED); 1109 if (idEncryptedStr != null && 1110 idEncryptedStr.equals("true")) 1111 { 1112 needNameIDEncrypted = true; 1113 } 1114 } 1115 PrivateKey decryptionKey = KeyUtil.getDecryptionKey(spssoconfig); 1116 if (needNameIDEncrypted && encId == null) { 1117 SAML2Utils.debug.error(classMethod + 1118 "process: NameID was not encrypted."); 1119 SAML2Exception se = new SAML2Exception(SAML2Utils.bundle.getString( 1120 "nameIDNotEncrypted")); 1121 // invoke SPAdapter for failure 1122 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1123 request, response, smap, respInfo, 1124 SAML2ServiceProviderAdapter.INVALID_RESPONSE, se); 1125 throw se; 1126 } 1127 if (encId != null) { 1128 try { 1129 nameId = encId.decrypt(decryptionKey); 1130 } catch (SAML2Exception se) { 1131 // invoke SPAdapter for failure 1132 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1133 request, response, smap, respInfo, 1134 SAML2ServiceProviderAdapter.INVALID_RESPONSE, se); 1135 throw se; 1136 } 1137 } 1138 respInfo.setNameId(nameId); 1139 1140 SPSSODescriptorElement spDesc = null; 1141 try { 1142 spDesc = metaManager.getSPSSODescriptor(realm, hostEntityId); 1143 } catch (SAML2MetaException ex) { 1144 SAML2Utils.debug.error(classMethod, ex); 1145 } 1146 if (spDesc == null) { 1147 SAML2Exception se = new SAML2Exception(SAML2Utils.bundle.getString( 1148 "metaDataError")); 1149 invokeSPAdapterForSSOFailure(hostEntityId, realm, request, 1150 response, smap, respInfo, 1151 SAML2ServiceProviderAdapter.SSO_FAILED_META_DATA_ERROR, se); 1152 throw se; 1153 } 1154 String nameIDFormat = nameId.getFormat(); 1155 if (nameIDFormat != null) { 1156 List spNameIDFormatList = spDesc.getNameIDFormat(); 1157 1158 if ((spNameIDFormatList != null) && (!spNameIDFormatList.isEmpty()) 1159 && (!spNameIDFormatList.contains(nameIDFormat))) { 1160 1161 Object[] args = { nameIDFormat }; 1162 SAML2Exception se = new SAML2Exception(SAML2Utils.BUNDLE_NAME, 1163 "unsupportedNameIDFormatSP", args); 1164 1165 invokeSPAdapterForSSOFailure(hostEntityId, realm, request, 1166 response, smap, respInfo, 1167 SAML2ServiceProviderAdapter.INVALID_RESPONSE, se); 1168 throw se; 1169 } 1170 } 1171 1172 boolean ignoreProfile = false; 1173 String existUserName = null; 1174 SessionProvider sessionProvider = null; 1175 try { 1176 sessionProvider = SessionManager.getProvider(); 1177 ignoreProfile = SAML2Utils.isIgnoreProfileSet(session); 1178 } catch (SessionException se) { 1179 // invoke SPAdapter for failure 1180 SAML2Exception se2 = new SAML2Exception(se); 1181 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1182 request, response, smap, respInfo, 1183 SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2); 1184 throw se2; 1185 } 1186 if (session != null) { 1187 try { 1188 existUserName = sessionProvider. 1189 getPrincipalName(session); 1190 } catch (SessionException se) { 1191 // invoke SPAdapter for failure 1192 SAML2Exception se2 = new SAML2Exception(se); 1193 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1194 request, response, smap, respInfo, 1195 SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2); 1196 throw se2; 1197 } 1198 } 1199 String userName; 1200 try { 1201 userName = acctMapper.getIdentity( 1202 authnAssertion, hostEntityId, realm); 1203 } catch (SAML2Exception se) { 1204 // invoke SPAdapter for failure 1205 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1206 request, response, smap, respInfo, 1207 SAML2ServiceProviderAdapter.SSO_FAILED_NO_USER_MAPPING, se); 1208 throw se; 1209 } 1210 if (userName == null) { 1211 userName = existUserName; 1212 } 1213 if (SAML2Utils.debug.messageEnabled()) { 1214 SAML2Utils.debug.message( 1215 classMethod + "process: userName =[" + userName + "]"); 1216 } 1217 List attrs = null; 1218 String remoteHostId = null; 1219 for (Iterator it = assertions.iterator(); it.hasNext(); ) { 1220 Assertion assertion = (Assertion)it.next(); 1221 remoteHostId = assertion.getIssuer().getValue(); 1222 List origAttrs = getSAMLAttributes(assertion, 1223 needAttributeEncrypted, 1224 decryptionKey); 1225 if (origAttrs != null && !origAttrs.isEmpty()) { 1226 if (attrs == null) { 1227 attrs = new ArrayList(); 1228 } 1229 attrs.addAll(origAttrs); 1230 } 1231 } 1232 Map attrMap = null; 1233 if (attrs != null) { 1234 try { 1235 attrMap = attrMapper.getAttributes(attrs, userName, 1236 hostEntityId, remoteHostId, realm); 1237 } catch (SAML2Exception se) { 1238 // invoke SPAdapter for failure 1239 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1240 request, response, smap, respInfo, 1241 SAML2ServiceProviderAdapter.SSO_FAILED_ATTRIBUTE_MAPPING, 1242 se); 1243 throw se; 1244 } 1245 } 1246 if (SAML2Utils.debug.messageEnabled()) { 1247 SAML2Utils.debug.message( 1248 classMethod + "process: remoteHostId = " + remoteHostId); 1249 SAML2Utils.debug.message( 1250 classMethod + "process: attrMap = " + attrMap); 1251 } 1252 respInfo.setAttributeMap(attrMap); 1253 1254 // return error code for local user login 1255 if ((userName == null) || (userName.length() == 0)) { 1256 throw new SAML2Exception( 1257 SAML2Utils.bundle.getString("noUserMapping")); 1258 } 1259 1260 // Even if the user profile is set to ignore, we must attempt to persist 1261 // if the NameIDFormat is set to persistent. 1262 if (ignoreProfile && SAML2Constants.PERSISTENT.equals(nameIDFormat)) { 1263 ignoreProfile = false; 1264 SAML2Utils.debug.warning(classMethod 1265 + "ignoreProfile was true but NameIDFormat is Persistent => setting ignoreProfile to false"); } 1266 1267 boolean isTransient = SAML2Constants.NAMEID_TRANSIENT_FORMAT.equals( 1268 nameId.getFormat()); 1269 boolean spDoNotWriteFedInfo = isSPDoNotWriteFedInfo(realm, hostEntityId, metaManager) && 1270 SAML2Constants.UNSPECIFIED.equals(nameId.getFormat()); 1271 boolean writeFedInfo = ( (!ignoreProfile && !isTransient && !spDoNotWriteFedInfo) && 1272 (!SAML2Utils.isFedInfoExists( 1273 userName, hostEntityId, remoteHostId, nameId))); 1274 // TODO: check if this few lines are needed 1275 /* 1276 DN dnObject = new DN(userName); 1277 String [] array = dnObject.explodeDN(true); 1278 userName = array[0]; 1279 */ 1280 1281 if (SAML2Utils.debug.messageEnabled()) { 1282 SAML2Utils.debug.message( 1283 classMethod + "userName : " + userName); 1284 SAML2Utils.debug.message( 1285 classMethod + "writeFedInfo : " + writeFedInfo); 1286 } 1287 AuthnRequest authnRequest = null; 1288 if (smap != null) { 1289 authnRequest = (AuthnRequest) 1290 smap.get(SAML2Constants.AUTHN_REQUEST); 1291 } 1292 if (inRespToResp != null && inRespToResp.length() != 0) { 1293 SPCache.requestHash.remove(inRespToResp); 1294 } 1295 Map sessionInfoMap = new HashMap(); 1296 sessionInfoMap.put(SessionProvider.REALM, realm); 1297 sessionInfoMap.put(SessionProvider.PRINCIPAL_NAME, userName); 1298 // set client info. always use client IP address to prevent 1299 // reverse host lookup 1300 String clientAddr = ClientUtils.getClientIPAddress(request); 1301 sessionInfoMap.put(SessionProvider.HOST, clientAddr); 1302 sessionInfoMap.put(SessionProvider.HOST_NAME, clientAddr); 1303 sessionInfoMap.put(SessionProvider.AUTH_LEVEL, 1304 String.valueOf(authLevel)); 1305 request.setAttribute(SessionProvider.ATTR_MAP, attrMap); 1306 try { 1307 session = sessionProvider.createSession( 1308 sessionInfoMap, request, response, null); 1309 } catch (SessionException se) { 1310 // invoke SPAdapter for failure 1311 int failureCode = 1312 SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_GENERATION; 1313 int sessCode = se.getErrCode(); 1314 if (sessCode == SessionException.AUTH_USER_INACTIVE) { 1315 failureCode = 1316 SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_USER_INACTIVE; 1317 } else if (sessCode == SessionException.AUTH_USER_LOCKED) { 1318 failureCode = 1319 SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_USER_LOCKED; 1320 } else if (sessCode == SessionException.AUTH_ACCOUNT_EXPIRED) { 1321 failureCode = 1322 SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_ACCOUNT_EXPIRED; 1323 } 1324 if (SAML2Utils.debug.messageEnabled()) { 1325 SAML2Utils.debug.message( 1326 "SPACSUtils.processResponse : error code=" + sessCode, se); 1327 } 1328 SAML2Exception se2 = new SAML2Exception(se); 1329 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1330 request, response, smap, respInfo, failureCode, se2); 1331 throw se2; 1332 } 1333 1334 // set metaAlias 1335 String[] values = { metaAlias }; 1336 try { 1337 setAttrMapInSession(sessionProvider, attrMap, session); 1338 setDiscoBootstrapCredsInSSOToken(sessionProvider, authnAssertion, 1339 session); 1340 sessionProvider.setProperty( 1341 session, SAML2Constants.SP_METAALIAS, values); 1342 } catch (SessionException se) { 1343 // invoke SPAdapter for failure 1344 SAML2Exception se2 = new SAML2Exception(se); 1345 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1346 request, response, smap, respInfo, 1347 SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2); 1348 throw se2; 1349 } 1350 1351 NameIDInfo info = null; 1352 String affiID = nameId.getSPNameQualifier(); 1353 boolean isDualRole = SAML2Utils.isDualRole(hostEntityId, realm); 1354 AffiliationDescriptorType affiDesc = null; 1355 if (affiID != null && !affiID.isEmpty()) { 1356 affiDesc = metaManager.getAffiliationDescriptor(realm, affiID); 1357 } 1358 1359 if (affiDesc != null) { 1360 if (!affiDesc.getAffiliateMember().contains(hostEntityId)) { 1361 throw new SAML2Exception(SAML2Utils.bundle.getString( 1362 "spNotAffiliationMember")); 1363 } 1364 if (isDualRole) { 1365 info = new NameIDInfo(affiID, remoteHostId, nameId, 1366 SAML2Constants.DUAL_ROLE, true); 1367 } else { 1368 info = new NameIDInfo(affiID, remoteHostId, nameId, 1369 SAML2Constants.SP_ROLE, true); 1370 } 1371 } else { 1372 if (isDualRole) { 1373 info = new NameIDInfo(hostEntityId, remoteHostId, nameId, 1374 SAML2Constants.DUAL_ROLE, false); 1375 } else { 1376 info = new NameIDInfo(hostEntityId, remoteHostId, nameId, 1377 SAML2Constants.SP_ROLE, false); 1378 } 1379 } 1380 Map props = new HashMap(); 1381 String nameIDValueString = info.getNameIDValue(); 1382 props.put(LogUtil.NAME_ID, info.getNameIDValue()); 1383 try { 1384 userName = sessionProvider.getPrincipalName(session); 1385 } catch (SessionException se) { 1386 // invoke SPAdapter for failure 1387 SAML2Exception se2 = new SAML2Exception(se); 1388 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1389 request, response, smap, respInfo, 1390 SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2); 1391 throw se2; 1392 } 1393 String[] data1 = {userName, nameIDValueString}; 1394 LogUtil.access(Level.INFO, LogUtil.SUCCESS_FED_SSO, data1, session, 1395 props); 1396 // write fed info into data store 1397 if (writeFedInfo) { 1398 try { 1399 AccountUtils.setAccountFederation(info, userName); 1400 } catch (SAML2Exception se) { 1401 // invoke SPAdapter for failure 1402 invokeSPAdapterForSSOFailure(hostEntityId, realm, 1403 request, response, smap, respInfo, 1404 SAML2ServiceProviderAdapter.FEDERATION_FAILED_WRITING_ACCOUNT_INFO, se); 1405 throw se; 1406 } 1407 String[] data = {userName, ""}; 1408 if (LogUtil.isAccessLoggable(Level.FINE)) { 1409 data[1] = info.toValueString(); 1410 } 1411 LogUtil.access(Level.INFO, 1412 LogUtil.FED_INFO_WRITTEN, 1413 data, 1414 session, 1415 props); 1416 } 1417 String requestID = respInfo.getResponse().getInResponseTo(); 1418 // save info in memory for logout 1419 saveInfoInMemory(sessionProvider, session, sessionIndex, metaAlias, 1420 info, IDPProxyUtil.isIDPProxyEnabled(requestID), isTransient); 1421 1422 // invoke SP Adapter 1423 SAML2ServiceProviderAdapter spAdapter = 1424 SAML2Utils.getSPAdapterClass(hostEntityId, realm); 1425 if (spAdapter != null) { 1426 boolean redirected = spAdapter.postSingleSignOnSuccess( 1427 hostEntityId, realm, request, 1428 response, out, session, authnRequest, respInfo.getResponse(), 1429 respInfo.getProfileBinding(), writeFedInfo); 1430 String[] value = null; 1431 if (redirected) { 1432 value = new String[] {"true"}; 1433 } else { 1434 value = new String[] {"false"}; 1435 } 1436 try { 1437 sessionProvider.setProperty(session, 1438 SAML2Constants.RESPONSE_REDIRECTED, value); 1439 } catch (SessionException ex) { 1440 SAML2Utils.debug.warning("SPSingleLogout.processResp", ex); 1441 } catch (UnsupportedOperationException ex) { 1442 SAML2Utils.debug.warning("SPSingleLogout.processResp", ex); 1443 } 1444 } 1445 1446 String assertionID=authnAssertion.getID(); 1447 if (respInfo.getProfileBinding().equals(SAML2Constants.HTTP_POST)) { 1448 SPCache.assertionByIDCache.put(assertionID, SAML2Constants.ONETIME); 1449 try { 1450 if (SAML2FailoverUtils.isSAML2FailoverEnabled()) { 1451 SAML2FailoverUtils.saveSAML2TokenWithoutSecondaryKey( 1452 assertionID, 1453 SAML2Constants.ONETIME, 1454 ((Long) smap.get(SAML2Constants.NOTONORAFTER)).longValue() / 1000); 1455 } 1456 } catch (SAML2TokenRepositoryException se) { 1457 SAML2Utils.debug.error(classMethod + 1458 "There was a problem saving the assertionID to the SAML2 Token Repository for assertionID:" 1459 + assertionID, se); 1460 } 1461 } 1462 respInfo.setAssertion(authnAssertion); 1463 1464 return session; 1465 } 1466 1467 1468 private static void invokeSPAdapterForSSOFailure(String hostEntityId, 1469 String realm, HttpServletRequest request, HttpServletResponse response, 1470 Map smap, ResponseInfo respInfo, int errorCode, 1471 SAML2Exception se) { 1472 SAML2ServiceProviderAdapter spAdapter = null; 1473 try { 1474 spAdapter = SAML2Utils.getSPAdapterClass(hostEntityId, realm); 1475 } catch (SAML2Exception e) { 1476 if (SAML2Utils.debug.messageEnabled()) { 1477 SAML2Utils.debug.message( 1478 "SPACSUtils.invokeSPAdapterForSSOFailure", e); 1479 } 1480 } 1481 if (spAdapter != null) { 1482 AuthnRequest authnRequest = null; 1483 if (smap != null) { 1484 authnRequest = (AuthnRequest) 1485 smap.get(SAML2Constants.AUTHN_REQUEST); 1486 } 1487 boolean redirected = spAdapter.postSingleSignOnFailure( 1488 hostEntityId, realm, request, response, authnRequest, 1489 respInfo.getResponse(), respInfo.getProfileBinding(), 1490 errorCode); 1491 se.setRedirectionDone(redirected); 1492 } 1493 } 1494 1495 private static void saveInfoInMemory(SessionProvider sessionProvider, 1496 Object session, String sessionIndex, String metaAlias, 1497 NameIDInfo info, boolean isIDPProxy, boolean isTransient) 1498 throws SAML2Exception { 1499 1500 String infoKeyString = (new NameIDInfoKey( 1501 info.getNameIDValue(), 1502 info.getHostEntityID(), 1503 info.getRemoteEntityID())).toValueString(); 1504 String infoKeyAttribute = 1505 AccountUtils.getNameIDInfoKeyAttribute(); 1506 String[] fromToken = null; 1507 try { 1508 fromToken = sessionProvider. 1509 getProperty(session, infoKeyAttribute); 1510 if (fromToken == null || fromToken.length == 0 || 1511 fromToken[0] == null || fromToken[0].length() == 0) { 1512 String[] values = { infoKeyString }; 1513 sessionProvider.setProperty( 1514 session, infoKeyAttribute, values); 1515 } else { 1516 if (fromToken[0].indexOf(infoKeyString) == -1) { 1517 String[] values = { fromToken[0] + 1518 SAML2Constants.SECOND_DELIM + 1519 infoKeyString }; 1520 sessionProvider.setProperty( 1521 session, infoKeyAttribute, values); 1522 } 1523 } 1524 if (isTransient) { 1525 String nameIDInfoStr = info.toValueString(); 1526 String infoAttribute = AccountUtils.getNameIDInfoAttribute(); 1527 String[] nameIDInfoStrs = sessionProvider.getProperty(session, 1528 infoAttribute); 1529 if (nameIDInfoStrs == null) { 1530 nameIDInfoStrs = new String[1]; 1531 nameIDInfoStrs[0] = nameIDInfoStr; 1532 } else { 1533 Set nameIDInfoStrSet = new HashSet(); 1534 for(int i=0; i<nameIDInfoStrs.length; i++) { 1535 nameIDInfoStrSet.add(nameIDInfoStrs[i]); 1536 } 1537 nameIDInfoStrSet.add(nameIDInfoStr); 1538 nameIDInfoStrs = (String[])nameIDInfoStrSet.toArray( 1539 new String[nameIDInfoStrSet.size()]); 1540 } 1541 sessionProvider.setProperty(session, infoAttribute, 1542 nameIDInfoStrs); 1543 } 1544 } catch (SessionException sessE) { 1545 throw new SAML2Exception(sessE); 1546 } 1547 String tokenID = sessionProvider.getSessionID(session); 1548 if (!SPCache.isFedlet) { 1549 List fedSessions = (List) 1550 SPCache.fedSessionListsByNameIDInfoKey.get(infoKeyString); 1551 if (fedSessions == null) { 1552 synchronized (SPCache.fedSessionListsByNameIDInfoKey) { 1553 fedSessions = (List) 1554 SPCache.fedSessionListsByNameIDInfoKey.get(infoKeyString); 1555 if (fedSessions == null) { 1556 fedSessions = new ArrayList(); 1557 } 1558 } 1559 synchronized (fedSessions) { 1560 fedSessions.add(new SPFedSession(sessionIndex, tokenID, 1561 info, metaAlias)); 1562 SPCache.fedSessionListsByNameIDInfoKey.put( 1563 infoKeyString, fedSessions); 1564 } 1565 if ((agent != null) && agent.isRunning() && (saml2Svc != null)){ 1566 saml2Svc.setFedSessionCount( 1567 (long)SPCache.fedSessionListsByNameIDInfoKey.size()); 1568 } 1569 1570 if (isIDPProxy) { 1571 //IDP Proxy 1572 IDPSession idpSess = (IDPSession) 1573 IDPCache.idpSessionsBySessionID.get( 1574 tokenID); 1575 if (idpSess == null) { 1576 idpSess = new IDPSession(session); 1577 IDPCache.idpSessionsBySessionID.put( 1578 tokenID, idpSess); 1579 } 1580 if (SAML2Utils.debug.messageEnabled()) { 1581 SAML2Utils.debug.message("Add Session Partner: " + 1582 info.getRemoteEntityID()); 1583 } 1584 idpSess.addSessionPartner(new SAML2SessionPartner( 1585 info.getRemoteEntityID(), true)); 1586 // end of IDP Proxy 1587 } 1588 } else { 1589 synchronized (fedSessions) { 1590 Iterator iter = fedSessions.iterator(); 1591 boolean found = false; 1592 while (iter.hasNext()) { 1593 SPFedSession temp = (SPFedSession) iter.next(); 1594 String idpSessionIndex = null; 1595 if(temp != null) { 1596 idpSessionIndex = temp.idpSessionIndex; 1597 } 1598 if ((idpSessionIndex != null) && 1599 (idpSessionIndex.equals(sessionIndex))) { 1600 temp.spTokenID = tokenID; 1601 temp.info = info; 1602 found = true; 1603 break; 1604 } 1605 } 1606 if (!found) { 1607 fedSessions.add( 1608 new SPFedSession(sessionIndex, tokenID, info, 1609 metaAlias)); 1610 SPCache.fedSessionListsByNameIDInfoKey.put( 1611 infoKeyString, fedSessions); 1612 if ((agent != null) && 1613 agent.isRunning() && 1614 (saml2Svc != null)) 1615 { 1616 saml2Svc.setFedSessionCount( 1617 (long)SPCache.fedSessionListsByNameIDInfoKey. 1618 size()); 1619 } 1620 } 1621 } 1622 } 1623 SPCache.fedSessionListsByNameIDInfoKey.put(infoKeyString, 1624 fedSessions); 1625 if ((agent != null) && agent.isRunning() && (saml2Svc != null)) { 1626 saml2Svc.setFedSessionCount( 1627 (long)SPCache.fedSessionListsByNameIDInfoKey.size()); 1628 } 1629 } 1630 try { 1631 sessionProvider.addListener( 1632 session, new SPSessionListener(infoKeyString, tokenID)); 1633 } catch (SessionException e) { 1634 SAML2Utils.debug.error( 1635 "SPACSUtils.saveInfoInMemory: "+ 1636 "Unable to add session listener."); 1637 } 1638 } 1639 1640 /** Sets the attribute map in the session 1641 * 1642 * @param sessionProvider Session provider 1643 * @param attrMap the Attribute Map 1644 * @param session the valid session object 1645 * @throws com.sun.identity.plugin.session.SessionException 1646 */ 1647 public static void setAttrMapInSession( 1648 SessionProvider sessionProvider, 1649 Map attrMap, Object session) 1650 throws SessionException { 1651 if (attrMap != null && !attrMap.isEmpty()) { 1652 Set entrySet = attrMap.entrySet(); 1653 for(Iterator iter = entrySet.iterator(); iter.hasNext();) { 1654 Map.Entry entry = (Map.Entry)iter.next(); 1655 String attrName = (String)entry.getKey(); 1656 Set attrValues = (Set)entry.getValue(); 1657 if(attrValues != null && !attrValues.isEmpty()) { 1658 sessionProvider.setProperty( 1659 session, attrName, 1660 (String[]) attrValues.toArray( 1661 new String[attrValues.size()])); 1662 if (SAML2Utils.debug.messageEnabled()) { 1663 SAML2Utils.debug.message( 1664 "SPACSUtils.setAttrMapInSessioin: AttrMap:" + 1665 attrName + " , " + attrValues); 1666 } 1667 } 1668 } 1669 } 1670 } 1671 1672 /** Sets Discovery bootstrap credentials in the SSOToken 1673 * 1674 * @param sessionProvider session provider. 1675 * @param assertion assertion. 1676 * @param session the valid session object. 1677 */ 1678 private static void setDiscoBootstrapCredsInSSOToken( 1679 SessionProvider sessionProvider, Assertion assertion, Object session) 1680 throws SessionException { 1681 1682 if (assertion == null) { 1683 return; 1684 } 1685 1686 Set discoBootstrapCreds = null; 1687 Advice advice = assertion.getAdvice(); 1688 if (advice != null) { 1689 List creds = advice.getAdditionalInfo(); 1690 if ((creds != null) && !creds.isEmpty()) { 1691 if (discoBootstrapCreds == null) { 1692 discoBootstrapCreds = new HashSet(); 1693 } 1694 discoBootstrapCreds.addAll(creds); 1695 } 1696 } 1697 1698 if (discoBootstrapCreds != null) { 1699 sessionProvider.setProperty(session, 1700 SAML2Constants.DISCOVERY_BOOTSTRAP_CREDENTIALS, 1701 (String[])discoBootstrapCreds.toArray( 1702 new String[discoBootstrapCreds.size()])); 1703 } 1704 } 1705 1706 /** 1707 * Obtains relay state. Retrieves the relay state from relay state cache. 1708 * If input relay state is null, retrieve it from <code>SPSSOConfig</code>. 1709 * 1710 * @param relayStateID relay state value received from http request. 1711 * @param orgName realm or organization name the service provider resides in 1712 * @param hostEntityId Entity ID of the hosted service provider 1713 * @param sm <code>SAML2MetaManager</code> instance. 1714 * @return final relay state. Or <code>null</code> if the input 1715 * relayStateID is null and no default relay state is configured. 1716 */ 1717 public static String getRelayState( 1718 String relayStateID, 1719 String orgName, 1720 String hostEntityId, 1721 SAML2MetaManager sm 1722 ) { 1723 String relayStateUrl = null; 1724 1725 if ((relayStateID != null) && (relayStateID.trim().length() != 0)) { 1726 CacheObject cache = (CacheObject)SPCache.relayStateHash.remove( 1727 relayStateID); 1728 1729 if (cache != null) { 1730 relayStateUrl = (String)cache.getObject(); 1731 } else if (SAML2FailoverUtils.isSAML2FailoverEnabled()) { 1732 // The key is this way to make it unique compared to when 1733 // the same key is used to store a copy of the AuthnRequestInfo 1734 String key = relayStateID + relayStateID; 1735 try { 1736 // Try and retrieve the value from the SAML2 repository 1737 String relayState = (String) SAML2FailoverUtils.retrieveSAML2Token(key); 1738 if (relayState != null) { 1739 // Get back the relayState 1740 relayStateUrl = relayState; 1741 if (SAML2Utils.debug.messageEnabled()) { 1742 SAML2Utils.debug.message("SPACUtils.getRelayState: relayState" 1743 + " retrieved from SAML2 repository for key: " + key); 1744 } 1745 } 1746 } catch (SAML2TokenRepositoryException se) { 1747 SAML2Utils.debug.error("SPACUtils.getRelayState: Unable to retrieve relayState for key " 1748 + key, se); 1749 } 1750 } else { 1751 if (SAML2Utils.debug.messageEnabled()) { 1752 SAML2Utils.debug.message("SPACUtils.getRelayState: relayState" 1753 + " is null for relayStateID: " + relayStateID + ", SAML2 failover is disabled"); 1754 } 1755 } 1756 1757 if (relayStateUrl == null || relayStateUrl.trim().length() == 0) { 1758 relayStateUrl = relayStateID; 1759 } 1760 } 1761 1762 if (relayStateUrl == null || relayStateUrl.trim().length() == 0) { 1763 relayStateUrl = getAttributeValueFromSPSSOConfig( 1764 orgName, hostEntityId, sm, SAML2Constants.DEFAULT_RELAY_STATE); 1765 } 1766 1767 return relayStateUrl; 1768 } 1769 1770 /** 1771 * Retrieves intermediate redirect url from SP sso config. This url is used 1772 * if you want to goto some place before the final relay state. 1773 * 1774 * @param orgName realm or organization name the service provider resides in 1775 * @param hostEntityId Entity ID of the hosted service provider 1776 * @param sm <code>SAML2MetaManager</code> instance. 1777 * @return intermediate redirect url; or <code>null</code> if the url is 1778 * is not configured or an error occured during the retrieval 1779 * process. 1780 */ 1781 public static String getIntermediateURL(String orgName, 1782 String hostEntityId, 1783 SAML2MetaManager sm) 1784 { 1785 return getAttributeValueFromSPSSOConfig(orgName, hostEntityId, sm, 1786 SAML2Constants.INTERMEDIATE_URL); 1787 } 1788 1789 /** 1790 * Saves response for later retrieval and retrieves local auth url from 1791 * <code>SPSSOConfig</code>. 1792 * If the url does not exist, generate one from request URI. 1793 * If still cannot get it, (shouldn't happen), get it from 1794 * <code>AMConfig.properties</code>. 1795 * 1796 * @param orgName realm or organization name the service provider resides in 1797 * @param hostEntityId Entity ID of the hosted service provider 1798 * @param sm <code>SAML2MetaManager</code> instance to perform meta 1799 * operation. 1800 * @param respInfo to be cached <code>ResponseInfo</code>. 1801 * @param requestURI http request URI. 1802 * @return local login url. 1803 */ 1804 public static String prepareForLocalLogin( 1805 String orgName, 1806 String hostEntityId, 1807 SAML2MetaManager sm, 1808 ResponseInfo respInfo, 1809 String requestURI) 1810 { 1811 String localLoginUrl = getAttributeValueFromSPSSOConfig( 1812 orgName, hostEntityId, sm, SAML2Constants.LOCAL_AUTH_URL); 1813 if ((localLoginUrl == null) || (localLoginUrl.length() == 0)) { 1814 // get it from request 1815 try { 1816 int index = requestURI.indexOf("Consumer/metaAlias"); 1817 if (index != -1) { 1818 localLoginUrl = requestURI.substring(0, index) 1819 + "UI/Login?org=" 1820 + orgName; 1821 } 1822 } catch (IndexOutOfBoundsException e) { 1823 localLoginUrl = null; 1824 } 1825 if ((localLoginUrl == null) || (localLoginUrl.length() == 0)) { 1826 // shouldn't be here, but in case 1827 localLoginUrl = 1828 SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_PROTOCOL) 1829 + "://" 1830 + SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_HOST) 1831 + SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_PORT) 1832 + "/UI/Login?org=" 1833 + orgName; 1834 } 1835 } 1836 synchronized (SPCache.responseHash) { 1837 SPCache.responseHash.put(respInfo.getResponse().getID(), 1838 respInfo); 1839 } 1840 if (SAML2Utils.debug.messageEnabled()) { 1841 SAML2Utils.debug.message("SPACSUtils:prepareForLocalLogin: " + 1842 "localLoginUrl = " + localLoginUrl); 1843 } 1844 return localLoginUrl; 1845 } 1846 1847 /** 1848 * Retrieves attribute value for a given attribute name from 1849 * <code>SPSSOConfig</code>. 1850 * @param orgName realm or organization name the service provider resides in 1851 * @param hostEntityId hosted service provider's Entity ID. 1852 * @param sm <code>SAML2MetaManager</code> instance to perform meta 1853 * operations. 1854 * @param attrName name of the attribute whose value ot be retrived. 1855 * @return value of the attribute; or <code>null</code> if the attribute 1856 * if not configured, or an error occured in the process. 1857 */ 1858 private static String getAttributeValueFromSPSSOConfig(String orgName, 1859 String hostEntityId, 1860 SAML2MetaManager sm, 1861 String attrName) 1862 { 1863 String result = null; 1864 try { 1865 SPSSOConfigElement config = sm.getSPSSOConfig(orgName, 1866 hostEntityId); 1867 if (config == null) { 1868 return null; 1869 } 1870 Map attrs = SAML2MetaUtils.getAttributes(config); 1871 List value = (List) attrs.get(attrName); 1872 if (value != null && value.size() != 0) { 1873 result = ((String) value.iterator().next()).trim(); 1874 } 1875 } catch (SAML2MetaException sme) { 1876 if (SAML2Utils.debug.messageEnabled()) { 1877 SAML2Utils.debug.message("SPACSUtils.getAttributeValueFromSPSSO" 1878 + "Config:", sme); 1879 } 1880 result = null; 1881 } 1882 return result; 1883 } 1884 1885 // gets the attributes from AttibuteStates in the assertions. 1886 private static List getSAMLAttributes(Assertion assertion, 1887 boolean needAttributeEncrypted, 1888 PrivateKey decryptionKey) 1889 { 1890 List attrList = null; 1891 if (assertion != null) { 1892 List statements = assertion.getAttributeStatements(); 1893 if (statements != null && statements.size() > 0 ) { 1894 for (Iterator it = statements.iterator(); it.hasNext(); ) { 1895 AttributeStatement statement = 1896 (AttributeStatement)it.next(); 1897 List attributes = statement.getAttribute(); 1898 if (needAttributeEncrypted && 1899 attributes != null && !attributes.isEmpty()) 1900 { 1901 SAML2Utils.debug.error("Attribute not encrypted."); 1902 return null; 1903 } 1904 if (attributes != null) { 1905 if (attrList == null) { 1906 attrList = new ArrayList(); 1907 } 1908 attrList.addAll(attributes); 1909 } 1910 List encAttrs = statement.getEncryptedAttribute(); 1911 if (encAttrs != null) { 1912 for (Iterator encIter = encAttrs.iterator(); 1913 encIter.hasNext(); ) 1914 { 1915 if (attrList == null) { 1916 attrList = new ArrayList(); 1917 } 1918 try { 1919 attrList.add( 1920 ((EncryptedAttribute) encIter.next()). 1921 decrypt(decryptionKey)); 1922 } catch (SAML2Exception se) { 1923 SAML2Utils.debug.error("Decryption error:", se); 1924 return null; 1925 } 1926 } 1927 } 1928 } 1929 } 1930 } 1931 return attrList; 1932 } 1933 1934 /** 1935 * Processes response from Identity Provider to Fedlet (SP). 1936 * This will do all required protocol processing, include signature, 1937 * issuer and audience validation etc. A map containing processing 1938 * result will be returned. <br> 1939 * Here is a list of keys and values for the returned map: <br> 1940 * SAML2Constants.ATTRIBUTE_MAP -- Attribute map containing all attributes 1941 * passed down from IDP inside the 1942 * Assertion. The value is a 1943 * <code>java.util.Map</code> whose keys 1944 * are attribute names and values are 1945 * <code>java.util.Set</code> of string 1946 * values for the attributes. <br> 1947 * SAML2Constants.RELAY_STATE -- Relay state, value is a string <br> 1948 * SAML2Constants.IDPENTITYID -- IDP entity ID, value is a string<br> 1949 * SAML2Constants.RESPONSE -- Response object, value is an instance of 1950 * com.sun.identity.saml2.protocol.Response 1951 * SAML2Constants.ASSERTION -- Assertion object, value is an instance of 1952 * com.sun.identity.saml2.assertion.Assertion 1953 * SAML2Constants.SUBJECT -- Subject object, value is an instance of 1954 * com.sun.identity.saml2.assertion.Subject 1955 * SAML2Constants.NAMEID -- NameID object, value is an instance of 1956 * com.sun.identity.saml2.assertion.NameID 1957 * 1958 * @param request HTTP Servlet request 1959 * @param response HTTP Servlet response. 1960 * @param out the print writer for writing out presentation 1961 * 1962 * @return <code>Map</code> which holds result of the processing. 1963 * @throws SAML2Exception if the processing failed due to server error. 1964 * @throws IOException if the processing failed due to IO error. 1965 * @throws SessionException if the processing failed due to session error. 1966 * @throws ServletException if the processing failed due to request error. 1967 * 1968 * @supported.api 1969 */ 1970 public static Map processResponseForFedlet (HttpServletRequest request, 1971 HttpServletResponse response, PrintWriter out) throws SAML2Exception, IOException, 1972 SessionException, ServletException { 1973 if ((request == null) || (response == null)) { 1974 throw new ServletException( 1975 SAML2SDKUtils.bundle.getString("nullInput")); 1976 } 1977 1978 String requestURL = request.getRequestURL().toString(); 1979 SAML2MetaManager metaManager = new SAML2MetaManager(); 1980 if (metaManager == null) { 1981 throw new SAML2Exception( 1982 SAML2SDKUtils.bundle.getString("errorMetaManager")); 1983 } 1984 String metaAlias = SAML2MetaUtils.getMetaAliasByUri(requestURL); 1985 if ((metaAlias == null) || (metaAlias.length() == 0)) { 1986 // Check in case metaAlias has been supplied as a parameter 1987 metaAlias = request.getParameter(SAML2MetaManager.NAME_META_ALIAS_IN_URI); 1988 if (metaAlias == null || metaAlias.length() == 0) { 1989 // pick the first available one 1990 List spMetaAliases = 1991 metaManager.getAllHostedServiceProviderMetaAliases("/"); 1992 if ((spMetaAliases != null) && !spMetaAliases.isEmpty()) { 1993 // get first one 1994 metaAlias = (String) spMetaAliases.get(0); 1995 } 1996 if ((metaAlias == null) || (metaAlias.length() == 0)) { 1997 throw new ServletException( 1998 SAML2SDKUtils.bundle.getString("nullSPEntityID")); 1999 } 2000 } 2001 } 2002 String hostEntityId = null; 2003 try { 2004 hostEntityId = metaManager.getEntityByMetaAlias(metaAlias); 2005 } catch (SAML2MetaException sme) { 2006 SAML2SDKUtils.debug.error("SPACSUtils.processResponseForFedlet", 2007 sme); 2008 throw new SAML2Exception( 2009 SAML2SDKUtils.bundle.getString("metaDataError")); 2010 } 2011 if (hostEntityId == null) { 2012 // logging? 2013 throw new SAML2Exception( 2014 SAML2SDKUtils.bundle.getString("metaDataError")); 2015 } 2016 // organization is always root org 2017 String orgName = "/"; 2018 String relayState = request.getParameter(SAML2Constants.RELAY_STATE); 2019 SessionProvider sessionProvider = null; 2020 ResponseInfo respInfo = null; 2021 try { 2022 sessionProvider = SessionManager.getProvider(); 2023 } catch (SessionException se) { 2024 SAML2SDKUtils.debug.error("SPACSUtils.processResponseForFedlet", 2025 se); 2026 throw new SAML2Exception(se); 2027 } 2028 respInfo = SPACSUtils.getResponse( 2029 request, response, orgName, hostEntityId, metaManager); 2030 2031 Object newSession = null; 2032 2033 // Throws a SAML2Exception if the response cannot be validated 2034 // or contains a non-Success StatusCode, invoking the SPAdapter SPI 2035 // for taking action on the failed validation. 2036 // The resulting exception has its redirectionDone flag set if 2037 // the SPAdapter issued a HTTP redirect. 2038 newSession = SPACSUtils.processResponse( 2039 request, response, out, metaAlias, null, respInfo, 2040 orgName, hostEntityId, metaManager); 2041 2042 SAML2SDKUtils.debug.message("SSO SUCCESS"); 2043 String[] redirected = sessionProvider.getProperty(newSession, 2044 SAML2Constants.RESPONSE_REDIRECTED); 2045 if ((redirected != null) && (redirected.length != 0) && 2046 redirected[0].equals("true")) { 2047 SAML2SDKUtils.debug.message("Already redirected in SPAdapter."); 2048 // response redirected already in SPAdapter 2049 return createMapForFedlet(respInfo, null, hostEntityId); 2050 } 2051 // redirect to relay state 2052 String finalUrl = SPACSUtils.getRelayState( 2053 relayState, orgName, hostEntityId, metaManager); 2054 String realFinalUrl = finalUrl; 2055 if (finalUrl != null && finalUrl.length() != 0) { 2056 try { 2057 realFinalUrl = 2058 sessionProvider.rewriteURL(newSession, finalUrl); 2059 } catch (SessionException se) { 2060 SAML2SDKUtils.debug.message("SPACSUtils.processRespForFedlet", 2061 se); 2062 realFinalUrl = finalUrl; 2063 } 2064 } 2065 String redirectUrl = SPACSUtils.getIntermediateURL( 2066 orgName, hostEntityId, metaManager); 2067 String realRedirectUrl = null; 2068 if (redirectUrl != null && redirectUrl.length() != 0) { 2069 if (realFinalUrl != null && realFinalUrl.length() != 0) { 2070 if (redirectUrl.indexOf("?") != -1) { 2071 redirectUrl += "&goto="; 2072 } else { 2073 redirectUrl += "?goto="; 2074 } 2075 redirectUrl += URLEncDec.encode(realFinalUrl); 2076 try { 2077 realRedirectUrl = sessionProvider.rewriteURL( 2078 newSession, redirectUrl); 2079 } catch (SessionException se) { 2080 SAML2SDKUtils.debug.message( 2081 "SPACSUtils.processRespForFedlet: rewriting failed.", se); 2082 realRedirectUrl = redirectUrl; 2083 } 2084 } else { 2085 realRedirectUrl = redirectUrl; 2086 } 2087 } else { 2088 realRedirectUrl = finalUrl; 2089 } 2090 return createMapForFedlet(respInfo, realRedirectUrl, hostEntityId); 2091 } 2092 2093 /** 2094 * Returns <code>true</code> or <code>false</code> 2095 * depending if the flag spDoNotWriteFederationInfo is set in the 2096 * SP Extended metadata 2097 * 2098 * @param realm the realm name 2099 * @param spEntityID the entity id of the Service Provider 2100 * @param metaManager the SAML2MetaMAnager used to read the extendede metadata 2101 * @return the <code>true/false</code> 2102 * @exception SAML2Exception if the operation is not successful 2103 */ 2104 private static Boolean isSPDoNotWriteFedInfo( 2105 String realm, String spEntityID, SAML2MetaManager metaManager) 2106 throws SAML2Exception { 2107 String methodName = "isSPDoNotWriteFedInfo"; 2108 2109 Boolean isSPDoNotWriteFedInfoEnabled = false; 2110 SAML2SDKUtils.debug.message("SPACSUtils." + methodName + "Entering"); 2111 2112 try { 2113 String SPDoNotWriteFedInfo = getAttributeValueFromSPSSOConfig(realm, 2114 spEntityID, metaManager, 2115 SAML2Constants.SP_DO_NOT_WRITE_FEDERATION_INFO); 2116 2117 if (SPDoNotWriteFedInfo != null && !SPDoNotWriteFedInfo.isEmpty()) { 2118 SAML2SDKUtils.debug.message("SPACSUtils." + methodName + 2119 ": SPDoNotWriteFedInfo is: " + SPDoNotWriteFedInfo); 2120 isSPDoNotWriteFedInfoEnabled = SPDoNotWriteFedInfo.equalsIgnoreCase("true"); 2121 } else { 2122 SAML2SDKUtils.debug.message("SPACSUtils." + methodName + 2123 ": SPDoNotWriteFedInfo is: not configured"); 2124 isSPDoNotWriteFedInfoEnabled = false; 2125 } 2126 } catch (Exception ex) { 2127 SAML2Utils.debug.error(methodName + 2128 "Unable to get the SPDoNotWriteFedInfo flag.", ex); 2129 throw new SAML2Exception(ex); 2130 } 2131 2132 return isSPDoNotWriteFedInfoEnabled ; 2133 } 2134 2135 2136 private static Map createMapForFedlet( 2137 ResponseInfo respInfo, String relayUrl, String hostedEntityId) { 2138 Map map = new HashMap(); 2139 if (relayUrl != null) { 2140 map.put(SAML2Constants.RELAY_STATE, relayUrl); 2141 } 2142 Response samlResp = respInfo.getResponse(); 2143 map.put(SAML2Constants.RESPONSE, samlResp); 2144 Assertion assertion = respInfo.getAssertion(); 2145 map.put(SAML2Constants.ASSERTION, assertion); 2146 map.put(SAML2Constants.SUBJECT, assertion.getSubject()); 2147 map.put(SAML2Constants.IDPENTITYID, assertion.getIssuer().getValue()); 2148 map.put(SAML2Constants.SPENTITYID, hostedEntityId); 2149 map.put(SAML2Constants.NAMEID, respInfo.getNameId()); 2150 map.put(SAML2Constants.ATTRIBUTE_MAP, respInfo.getAttributeMap()); 2151 map.put(SAML2Constants.SESSION_INDEX, respInfo.getSessionIndex()); 2152 return map; 2153 } 2154}
Copyright © 2010-2017, ForgeRock All Rights Reserved.