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