001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2007 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: AttributeQueryUtil.java,v 1.11 2009/07/24 22:51:48 madan_ranganath Exp $ 026 * 027 */ 028 029/* 030 * Portions copyright 2010-2013 ForgeRock, Inc. 031 */ 032 033package com.sun.identity.saml2.profile; 034 035import java.util.ArrayList; 036import java.util.Date; 037import java.util.HashMap; 038import java.util.HashSet; 039import java.util.Hashtable; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Map; 043import java.util.Set; 044import java.security.PrivateKey; 045import java.security.PublicKey; 046import java.security.cert.X509Certificate; 047import javax.crypto.SecretKey; 048import javax.servlet.http.HttpServletRequest; 049import javax.servlet.http.HttpServletResponse; 050import javax.xml.soap.SOAPException; 051import javax.xml.soap.SOAPMessage; 052import org.w3c.dom.Element; 053 054import com.sun.identity.plugin.datastore.DataStoreProviderException; 055import com.sun.identity.plugin.datastore.DataStoreProvider; 056import com.sun.identity.plugin.session.SessionException; 057import com.sun.identity.plugin.session.SessionManager; 058import com.sun.identity.saml.xmlsig.KeyProvider; 059import com.sun.identity.saml2.assertion.Assertion; 060import com.sun.identity.saml2.assertion.AssertionFactory; 061import com.sun.identity.saml2.assertion.Attribute; 062import com.sun.identity.saml2.assertion.AttributeStatement; 063import com.sun.identity.saml2.assertion.Conditions; 064import com.sun.identity.saml2.assertion.EncryptedAssertion; 065import com.sun.identity.saml2.assertion.Issuer; 066import com.sun.identity.saml2.assertion.NameID; 067import com.sun.identity.saml2.assertion.EncryptedID; 068import com.sun.identity.saml2.assertion.Subject; 069import com.sun.identity.saml2.common.AccountUtils; 070import com.sun.identity.saml2.common.SAML2Constants; 071import com.sun.identity.saml2.common.SAML2Exception; 072import com.sun.identity.saml2.common.SAML2Utils; 073import com.sun.identity.saml2.jaxb.assertion.AttributeElement; 074import com.sun.identity.saml2.jaxb.assertion.AttributeValueElement; 075import com.sun.identity.saml2.jaxb.entityconfig.AttributeAuthorityConfigElement; 076import com.sun.identity.saml2.jaxb.entityconfig.AttributeQueryConfigElement; 077import com.sun.identity.saml2.jaxb.entityconfig.IDPSSOConfigElement; 078import com.sun.identity.saml2.jaxb.metadata.AttributeAuthorityDescriptorElement; 079import com.sun.identity.saml2.jaxb.metadata.AttributeServiceElement; 080import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement; 081import com.sun.identity.saml2.jaxb.metadata.NameIDMappingServiceElement; 082import com.sun.identity.saml2.jaxb.metadataextquery.AttributeQueryDescriptorElement; 083import com.sun.identity.saml2.key.EncInfo; 084import com.sun.identity.saml2.key.KeyUtil; 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.plugins.AttributeAuthorityMapper; 089import com.sun.identity.saml2.protocol.AttributeQuery; 090import com.sun.identity.saml2.protocol.ProtocolFactory; 091import com.sun.identity.saml2.protocol.Response; 092import com.sun.identity.saml2.protocol.Status; 093import com.sun.identity.saml2.protocol.StatusCode; 094import com.sun.identity.saml2.xmlenc.EncManager; 095import java.io.IOException; 096 097 098/** 099 * This class provides methods to send or process <code>AttributeQuery</code>. 100 * 101 * @supported.api 102 */ 103 104public class AttributeQueryUtil { 105 106 static KeyProvider keyProvider = KeyUtil.getKeyProviderInstance(); 107 static Hashtable attrAuthorityMapperCache = new Hashtable(); 108 static DataStoreProvider dsProvider = null; 109 static SAML2MetaManager metaManager = SAML2Utils.getSAML2MetaManager(); 110 111 static { 112 try { 113 dsProvider = SAML2Utils.getDataStoreProvider(); 114 } catch (SAML2Exception se) { 115 SAML2Utils.debug.error("AttributeQueryUtil.static:", se); 116 } 117 } 118 119 private AttributeQueryUtil() { 120 } 121 122 /** 123 * Sends the <code>AttributeQuery</code> to specified 124 * attribute authority and returns <code>Response</code> coming 125 * from the attribute authority. 126 * 127 * @param attrQuery the <code>AttributeQuery</code> object 128 * @param attrAuthorityEntityID entity ID of attribute authority 129 * @param realm the realm of hosted entity 130 * @param attrQueryProfile the attribute query profile or null to ignore 131 * @param attrProfile the attribute profile 132 * @param binding the binding 133 * 134 * @return the <code>Response</code> object 135 * @exception SAML2Exception if the operation is not successful 136 * 137 * @supported.api 138 */ 139 public static Response sendAttributeQuery(AttributeQuery attrQuery, 140 String attrAuthorityEntityID, String realm, String attrQueryProfile, 141 String attrProfile, String binding) throws SAML2Exception { 142 143 AttributeAuthorityDescriptorElement aad = null; 144 try { 145 aad = metaManager.getAttributeAuthorityDescriptor( 146 realm, attrAuthorityEntityID); 147 } catch (SAML2MetaException sme) { 148 SAML2Utils.debug.error("AttributeQueryUtil.sendAttributeQuery:", 149 sme); 150 throw new SAML2Exception( 151 SAML2Utils.bundle.getString("metaDataError")); 152 } 153 154 if (aad == null) { 155 throw new SAML2Exception( 156 SAML2Utils.bundle.getString("attrAuthorityNotFound")); 157 } 158 159 if (binding == null) { 160 throw new SAML2Exception( 161 SAML2Utils.bundle.getString("unsupportedBinding")); 162 } 163 164 String location = findLocation(aad, binding, attrQueryProfile, 165 attrProfile); 166 167 if (location == null) { 168 throw new SAML2Exception( 169 SAML2Utils.bundle.getString("attrAuthorityNotFound")); 170 } 171 172 if (binding.equalsIgnoreCase(SAML2Constants.SOAP)) { 173 signAttributeQuery(attrQuery, realm, false); 174 return sendAttributeQuerySOAP(attrQuery, location, 175 attrAuthorityEntityID, aad); 176 } else { 177 throw new SAML2Exception( 178 SAML2Utils.bundle.getString("unsupportedBinding")); 179 } 180 } 181 182 /** 183 * Sends the <code>AttributeQuery</code> to specified 184 * attribute authority and returns <code>Response</code> coming 185 * from the attribute authority. 186 * 187 * @param attrQuery the <code>AttributeQuery</code> object 188 * @param request the HTTP Request 189 * @param response the HTTP Response 190 * @param attrAuthorityEntityID entity ID of attribute authority 191 * @param realm the realm of hosted entity 192 * @param attrQueryProfile the attribute query profile or null to ignore 193 * @param attrProfile the attribute profile 194 * @param binding the binding 195 * 196 * @exception SAML2Exception if the operation is not successful 197 * 198 * @supported.api 199 */ 200 public static void sendAttributeQuery(AttributeQuery attrQuery, 201 HttpServletRequest request, HttpServletResponse response, 202 String attrAuthorityEntityID, String realm, String attrQueryProfile, 203 String attrProfile, String binding) throws SAML2Exception { 204 205 AttributeAuthorityDescriptorElement aad = null; 206 try { 207 aad = metaManager.getAttributeAuthorityDescriptor( 208 realm, attrAuthorityEntityID); 209 } catch (SAML2MetaException sme) { 210 SAML2Utils.debug.error("AttributeQueryUtil.sendAttributeQuery:", 211 sme); 212 throw new SAML2Exception( 213 SAML2Utils.bundle.getString("metaDataError")); 214 } 215 216 if (aad == null) { 217 throw new SAML2Exception( 218 SAML2Utils.bundle.getString("attrAuthorityNotFound")); 219 } 220 221 if (binding == null) { 222 throw new SAML2Exception( 223 SAML2Utils.bundle.getString("unsupportedBinding")); 224 } 225 226 String location = findLocation(aad, binding, attrQueryProfile, 227 attrProfile); 228 229 if (location == null) { 230 throw new SAML2Exception( 231 SAML2Utils.bundle.getString("attrAuthorityNotFound")); 232 } 233 234 if (binding.equalsIgnoreCase(SAML2Constants.HTTP_POST)) { 235 signAttributeQuery(attrQuery, realm, false); 236 String encodedReqMsg = SAML2Utils.encodeForPOST(attrQuery.toXMLString(true, true)); 237 try { 238 SAML2Utils.postToTarget(response, "SAMLRequest", 239 encodedReqMsg, null, null, location); 240 } catch (IOException ptte) { 241 SAML2Utils.bundle.getBundle("errorSendingAttributeQuery"); 242 } 243 } else { 244 throw new SAML2Exception( 245 SAML2Utils.bundle.getString("unsupportedBinding")); 246 } 247 } 248 249 250 /** 251 * Processes the <code>AttributeQuery</code> coming 252 * from a requester. 253 * 254 * @param attrQuery the <code>AttributeQuery</code> object 255 * @param request the <code>HttpServletRequest</code> object 256 * @param response the <code>HttpServletResponse</code> object 257 * @param attrAuthorityEntityID entity ID of attribute authority 258 * @param realm the realm of hosted entity 259 * @param attrQueryProfileAlias the attribute query profile alias 260 * 261 * @return the <code>Response</code> object 262 * @exception SAML2Exception if the operation is not successful 263 */ 264 public static Response processAttributeQuery(AttributeQuery attrQuery, 265 HttpServletRequest request, HttpServletResponse response, 266 String attrAuthorityEntityID, String realm, 267 String attrQueryProfileAlias) throws SAML2Exception { 268 269 AttributeAuthorityMapper attrAuthorityMapper = 270 getAttributeAuthorityMapper(realm, attrAuthorityEntityID, 271 attrQueryProfileAlias); 272 273 String attrQueryProfile = AttributeQueryUtil.getAttributeQueryProfile( 274 attrQueryProfileAlias); 275 276 try { 277 attrAuthorityMapper.authenticateRequester(request, response, 278 attrQuery, attrAuthorityEntityID, realm); 279 } catch(SAML2Exception se) { 280 if (SAML2Utils.debug.messageEnabled()) { 281 SAML2Utils.debug.message("AttributeQueryUtil." + 282 "processAttributeQuery: ", se); 283 } 284 return SAML2Utils.getErrorResponse(attrQuery, 285 SAML2Constants.REQUESTER, null, se.getMessage(), null); 286 } 287 288 try { 289 attrAuthorityMapper.validateAttributeQuery(request, response, 290 attrQuery, attrAuthorityEntityID, realm); 291 } catch(SAML2Exception se) { 292 SAML2Utils.debug.error("AttributeQueryUtil.processAttributeQuery:", 293 se); 294 return SAML2Utils.getErrorResponse(attrQuery, 295 SAML2Constants.REQUESTER, null, se.getMessage(), null); 296 } 297 298 Issuer issuer = attrQuery.getIssuer(); 299 String requesterEntityID = issuer.getValue(); 300 AttributeAuthorityDescriptorElement aad = null; 301 try { 302 aad = metaManager.getAttributeAuthorityDescriptor( 303 realm, attrAuthorityEntityID); 304 } catch (SAML2MetaException sme) { 305 SAML2Utils.debug.error("AttributeQueryUtil.processAttributeQuery:", 306 sme); 307 return SAML2Utils.getErrorResponse(attrQuery, 308 SAML2Constants.RESPONDER, null, 309 SAML2Utils.bundle.getString("metaDataError"), null); 310 } 311 312 if (aad == null) { 313 return SAML2Utils.getErrorResponse(attrQuery, 314 SAML2Constants.REQUESTER, null, 315 SAML2Utils.bundle.getString("attrAuthorityNotFound"), null); 316 } 317 318 Object identity = null; 319 try { 320 identity = attrAuthorityMapper.getIdentity(request, response, 321 attrQuery, attrAuthorityEntityID, realm); 322 } catch (SAML2Exception se) { 323 if (SAML2Utils.debug.messageEnabled()) { 324 SAML2Utils.debug.message("AttributeQueryUtil." + 325 "processAttributeQuery: ", se); 326 } 327 return SAML2Utils.getErrorResponse(attrQuery, 328 SAML2Constants.REQUESTER, SAML2Constants.UNKNOWN_PRINCIPAL, 329 se.getMessage(), null); 330 } 331 332 if (identity == null) { 333 if (SAML2Utils.debug.messageEnabled()) { 334 SAML2Utils.debug.message("AttributeQueryUtil." + 335 "processAttributeQuery: unable to find identity."); 336 } 337 return SAML2Utils.getErrorResponse(attrQuery, 338 SAML2Constants.REQUESTER, SAML2Constants.UNKNOWN_PRINCIPAL, 339 null, null); 340 } 341 342 // Addition to support changing of desired attributes list 343 List desiredAttrs = (List)request.getAttribute("AttributeQueryUtil-desiredAttrs"); 344 if (desiredAttrs == null) { 345 desiredAttrs = attrQuery.getAttributes(); 346 } 347 try { 348 desiredAttrs = verifyDesiredAttributes(aad.getAttribute(), 349 desiredAttrs); 350 } catch (SAML2Exception se) { 351 return SAML2Utils.getErrorResponse(attrQuery, 352 SAML2Constants.REQUESTER, 353 SAML2Constants.INVALID_ATTR_NAME_OR_VALUE, null, null); 354 } 355 356 List attributes = attrAuthorityMapper.getAttributes(identity, 357 attrQuery, attrAuthorityEntityID, realm); 358 359 if (request.getAttribute("AttributeQueryUtil-storeAllAttributes") != null) { 360 request.setAttribute("AttributeQueryUtil-allAttributes", attributes); 361 } 362 363 attributes = filterAttributes(attributes, desiredAttrs); 364 365 ProtocolFactory protocolFactory = ProtocolFactory.getInstance(); 366 Response samlResp = protocolFactory.createResponse(); 367 List assertionList = new ArrayList(); 368 369 Assertion assertion = null; 370 try { 371 assertion = getAssertion(attrQuery, attrAuthorityEntityID, 372 requesterEntityID, realm, attrQueryProfileAlias, attributes); 373 } catch (SAML2Exception se) { 374 if (SAML2Utils.debug.messageEnabled()) { 375 SAML2Utils.debug.message( 376 "AttributeQueryUtil.processAttributeQuery:", se); 377 } 378 return SAML2Utils.getErrorResponse(attrQuery, 379 SAML2Constants.RESPONDER, null, se.getMessage(), null); 380 } 381 382 EncryptedID encryptedID = attrQuery.getSubject().getEncryptedID(); 383 if (encryptedID != null) { 384 EncryptedAssertion encryptedAssertion = null; 385 try { 386 signAssertion(assertion, realm, attrAuthorityEntityID, false); 387 encryptedAssertion = encryptAssertion(assertion, 388 encryptedID, attrAuthorityEntityID, requesterEntityID, 389 realm, attrQueryProfileAlias); 390 } catch (SAML2Exception se) { 391 if (SAML2Utils.debug.messageEnabled()) { 392 SAML2Utils.debug.message( 393 "AttributeQueryUtil.processAttributeQuery:", se); 394 } 395 return SAML2Utils.getErrorResponse(attrQuery, 396 SAML2Constants.RESPONDER, null, se.getMessage(), null); 397 } 398 assertionList.add(encryptedAssertion); 399 samlResp.setEncryptedAssertion(assertionList); 400 } else { 401 assertionList.add(assertion); 402 samlResp.setAssertion(assertionList); 403 } 404 405 samlResp.setID(SAML2Utils.generateID()); 406 samlResp.setInResponseTo(attrQuery.getID()); 407 408 samlResp.setVersion(SAML2Constants.VERSION_2_0); 409 samlResp.setIssueInstant(new Date()); 410 411 Status status = protocolFactory.createStatus(); 412 StatusCode statusCode = protocolFactory.createStatusCode(); 413 statusCode.setValue(SAML2Constants.SUCCESS); 414 status.setStatusCode(statusCode); 415 samlResp.setStatus(status); 416 417 Issuer respIssuer = AssertionFactory.getInstance().createIssuer(); 418 respIssuer.setValue(attrAuthorityEntityID); 419 samlResp.setIssuer(respIssuer); 420 421 signResponse(samlResp, attrAuthorityEntityID, realm, false); 422 423 return samlResp; 424 } 425 426 /** 427 * Converts attribute query profile alias to attribute query profile. 428 * 429 * @param attrQueryProfileAlias attribute query profile alias 430 * 431 * @return attribute query profile 432 */ 433 public static String getAttributeQueryProfile( 434 String attrQueryProfileAlias) { 435 436 if (attrQueryProfileAlias == null) { 437 return null; 438 } else if (attrQueryProfileAlias.equals( 439 SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE_ALIAS)) { 440 return SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE; 441 } else if (attrQueryProfileAlias.equals( 442 SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE_ALIAS)) { 443 return SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE; 444 } 445 446 return null; 447 } 448 449 private static void signAttributeQuery(AttributeQuery attrQuery, 450 String realm, boolean includeCert) throws SAML2Exception { 451 String requesterEntityID = attrQuery.getIssuer().getValue(); 452 453 String alias = SAML2Utils.getSigningCertAlias(realm, requesterEntityID, 454 SAML2Constants.ATTR_QUERY_ROLE); 455 456 PrivateKey signingKey = keyProvider.getPrivateKey(alias); 457 if (signingKey == null) { 458 throw new SAML2Exception( 459 SAML2Utils.bundle.getString("missingSigningCertAlias")); 460 } 461 462 X509Certificate signingCert = null; 463 if (includeCert) { 464 signingCert = keyProvider.getX509Certificate(alias); 465 } 466 467 if (signingKey != null) { 468 attrQuery.sign(signingKey, signingCert); 469 } 470 } 471 472 public static void validateEntityRequester(AttributeQuery attrQuery, 473 String attrAuthorityEntityID, String realm) throws SAML2Exception { 474 475 Issuer issuer = attrQuery.getIssuer(); 476 String format = issuer.getFormat(); 477 if ((format == null) || (format.length() == 0) || 478 (format.equals(SAML2Constants.UNSPECIFIED)) || 479 (format.equals(SAML2Constants.ENTITY))) { 480 481 String requestedEntityID = issuer.getValue(); 482 483 if (!SAML2Utils.isSourceSiteValid(issuer, realm, 484 attrAuthorityEntityID)) { 485 throw new SAML2Exception(SAML2Utils.bundle.getString( 486 "attrQueryIssuerInvalid")); 487 } 488 } else { 489 throw new SAML2Exception(SAML2Utils.bundle.getString( 490 "attrQueryIssuerInvalid")); 491 } 492 } 493 494 /** 495 * Checks if the attribute query signature is valid. 496 * 497 * @param attrQuery attribute query 498 * @param attrAuthorityEntityID entity ID of attribute authority 499 * @param realm the realm of hosted entity 500 * 501 * @exception SAML2Exception if the attribute query signature is not valid. 502 */ 503 public static void verifyAttrQuerySignature(AttributeQuery attrQuery, 504 String attrAuthorityEntityID, String realm) 505 throws SAML2Exception { 506 507 if (!attrQuery.isSigned()) { 508 throw new SAML2Exception(SAML2Utils.bundle.getString( 509 "attrQueryNotSigned")); 510 } 511 512 String requestedEntityID = attrQuery.getIssuer().getValue(); 513 514 AttributeQueryDescriptorElement attrqDesc = 515 metaManager.getAttributeQueryDescriptor(realm, requestedEntityID); 516 if (attrqDesc == null) { 517 throw new SAML2Exception(SAML2Utils.bundle.getString( 518 "attrQueryIssuerNotFound")); 519 } 520 X509Certificate signingCert = 521 KeyUtil.getVerificationCert(attrqDesc, requestedEntityID, 522 SAML2Constants.ATTR_QUERY_ROLE); 523 524 if (signingCert != null) { 525 boolean valid = attrQuery.isSignatureValid(signingCert); 526 if (SAML2Utils.debug.messageEnabled()) { 527 SAML2Utils.debug.message( 528 "AttributeQueryUtil.verifyAttributeQuery: " + 529 "Signature validity is : " + valid); 530 } 531 if (!valid) { 532 throw new SAML2Exception(SAML2Utils.bundle.getString( 533 "invalidSignatureAttrQuery")); 534 } 535 } else { 536 throw new SAML2Exception( 537 SAML2Utils.bundle.getString("missingSigningCertAlias")); 538 } 539 } 540 541 public static String getIdentityFromDataStoreX509Subject( 542 AttributeQuery attrQuery, String attrAuthorityEntityID, String realm) 543 throws SAML2Exception { 544 545 Subject subject = attrQuery.getSubject(); 546 NameID nameID = null; 547 EncryptedID encryptedID = subject.getEncryptedID(); 548 549 if (encryptedID != null) { 550 String alias = SAML2Utils.getEncryptionCertAlias(realm, 551 attrAuthorityEntityID, SAML2Constants.ATTR_AUTH_ROLE); 552 PrivateKey privateKey = keyProvider.getPrivateKey(alias); 553 554 nameID = encryptedID.decrypt(privateKey); 555 } else { 556 nameID = subject.getNameID(); 557 } 558 559 if (!SAML2Constants.X509_SUBJECT_NAME.equals(nameID.getFormat())) { 560 throw new SAML2Exception(SAML2Utils.bundle.getString( 561 "unsupportedAttrQuerySubjectNameID")); 562 } 563 564 String mappingAttrName = getAttributeValueFromAttrAuthorityConfig( 565 realm, attrAuthorityEntityID, 566 SAML2Constants.X509_SUBJECT_DATA_STORE_ATTR_NAME); 567 568 if ((mappingAttrName == null) || (mappingAttrName.length() == 0)) { 569 throw new SAML2Exception(SAML2Utils.bundle.getString( 570 "x509SubjectMappingNotConfigured")); 571 } 572 573 String x509SubjectDN = nameID.getValue(); 574 Map attrMap = new HashMap(); 575 Set values = new HashSet(); 576 values.add(x509SubjectDN); 577 attrMap.put(mappingAttrName, values); 578 579 if (SAML2Utils.debug.messageEnabled()) { 580 SAML2Utils.debug.message( 581 "AttributeQueryUtil.getIdentityFromDataStoreX509Subject: " + 582 "mappingAttrName = " + mappingAttrName + 583 ", X509 subject DN = " + x509SubjectDN); 584 } 585 586 try { 587 return dsProvider.getUserID(realm, attrMap); 588 } catch (DataStoreProviderException dse) { 589 SAML2Utils.debug.error( 590 "AttributeQueryUtil.getIdentityFromDataStoreX509Subject:",dse); 591 throw new SAML2Exception(dse.getMessage()); 592 } 593 } 594 595 public static String getIdentity(AttributeQuery attrQuery, 596 String attrAuthorityEntityID, String realm) throws SAML2Exception { 597 598 Subject subject = attrQuery.getSubject(); 599 NameID nameID = null; 600 EncryptedID encryptedID = subject.getEncryptedID(); 601 602 if (encryptedID != null) { 603 String alias = SAML2Utils.getEncryptionCertAlias(realm, 604 attrAuthorityEntityID, SAML2Constants.ATTR_AUTH_ROLE); 605 PrivateKey privateKey = keyProvider.getPrivateKey(alias); 606 607 nameID = encryptedID.decrypt(privateKey); 608 } else { 609 nameID = subject.getNameID(); 610 } 611 612 String nameIDFormat = nameID.getFormat(); 613 // NameIDFormat is "transient" 614 if (SAML2Constants.NAMEID_TRANSIENT_FORMAT.equals(nameIDFormat)) { 615 return (String)IDPCache.userIDByTransientNameIDValue.get( 616 nameID.getValue()); 617 } else 618 // NameIDFormat is "unspecified" 619 if (SAML2Constants.UNSPECIFIED.equals(nameIDFormat)) { 620 Map userIDsSearchMap = new HashMap(); 621 Set userIDValuesSet = new HashSet(); 622 userIDValuesSet.add(nameID.getValue()); 623 String userId = "uid"; 624 625 IDPSSOConfigElement config = SAML2Utils.getSAML2MetaManager().getIDPSSOConfig( 626 realm, attrAuthorityEntityID); 627 Map attrs = SAML2MetaUtils.getAttributes(config); 628 629 List nimAttrs = (List)attrs.get(SAML2Constants.NAME_ID_FORMAT_MAP); 630 631 632 for (Iterator i = nimAttrs.iterator(); i.hasNext(); ) { 633 String attrName = (String)i.next(); 634 if (attrName != null && attrName.length()>2 && attrName.startsWith(nameIDFormat)) { 635 int eqPos = attrName.indexOf('='); 636 if (eqPos != -1 && eqPos<attrName.length()-2) { 637 userId = attrName.substring(eqPos+1); 638 SAML2Utils.debug.message("AttributeQueryUtil.getIdentity: NameID attribute from map: " + userId); 639 break; 640 } 641 } 642 } 643 userIDsSearchMap.put(userId, userIDValuesSet); 644 try { 645 return dsProvider.getUserID(realm, userIDsSearchMap); 646 } catch (DataStoreProviderException dse) { 647 SAML2Utils.debug.error( 648 "AttributeQueryUtil.getIdentityFromDataStore1:", dse); 649 throw new SAML2Exception(dse.getMessage()); 650 } 651 } else { 652 String requestedEntityID = attrQuery.getIssuer().getValue(); 653 654 try { 655 return dsProvider.getUserID(realm, SAML2Utils.getNameIDKeyMap( 656 nameID, attrAuthorityEntityID, requestedEntityID, realm, 657 SAML2Constants.IDP_ROLE)); 658 } catch (DataStoreProviderException dse) { 659 SAML2Utils.debug.error( 660 "AttributeQueryUtil.getIdentityFromDataStore:", dse); 661 throw new SAML2Exception(dse.getMessage()); 662 } 663 } 664 } 665 666 public static List getUserAttributes(String userId, 667 AttributeQuery attrQuery, String attrAuthorityEntityID, String realm) 668 throws SAML2Exception { 669 670 String requestedEntityID = attrQuery.getIssuer().getValue(); 671 672 Map configMap = SAML2Utils.getConfigAttributeMap(realm, 673 requestedEntityID, SAML2Constants.SP_ROLE); 674 if (SAML2Utils.debug.messageEnabled()) { 675 SAML2Utils.debug.message( 676 "AttributeQueryUtil.getUserAttributes: " + 677 "remote SP attribute map = " + configMap); 678 } 679 if (configMap == null || configMap.isEmpty()) { 680 configMap = SAML2Utils.getConfigAttributeMap(realm, 681 attrAuthorityEntityID, SAML2Constants.IDP_ROLE); 682 if (configMap == null || configMap.isEmpty()) { 683 if (SAML2Utils.debug.messageEnabled()) { 684 SAML2Utils.debug.message( 685 "AttributeQueryUtil.getUserAttributes:" + 686 "Configuration map is not defined."); 687 } 688 return null; 689 } 690 if (SAML2Utils.debug.messageEnabled()) { 691 SAML2Utils.debug.message( 692 "AttributeQueryUtil.getUserAttributes: " + 693 "hosted IDP attribute map=" + configMap); 694 } 695 } 696 697 List attributes = new ArrayList(); 698 699 Set localAttributes = new HashSet(); 700 localAttributes.addAll(configMap.values()); 701 Map valueMap = null; 702 703 try { 704 valueMap = dsProvider.getAttributes(userId, localAttributes); 705 } catch (DataStoreProviderException dse) { 706 if (SAML2Utils.debug.warningEnabled()) { 707 SAML2Utils.debug.warning( 708 "AttributeQueryUtil.getUserAttributes:", dse); 709 } 710 } 711 712 Iterator iter = configMap.keySet().iterator(); 713 while(iter.hasNext()) { 714 String samlAttribute = (String)iter.next(); 715 String localAttribute = (String)configMap.get(samlAttribute); 716 String[] localAttributeValues = null; 717 if ((valueMap != null) && (!valueMap.isEmpty())) { 718 Set values = (Set)valueMap.get(localAttribute); 719 if ((values == null) || values.isEmpty()) { 720 if (SAML2Utils.debug.messageEnabled()) { 721 SAML2Utils.debug.message( 722 "AttributeQueryUtil.getUserAttributes:" + 723 " user profile does not have value for " + 724 localAttribute); 725 } 726 } else { 727 localAttributeValues = (String[]) 728 values.toArray(new String[values.size()]); 729 } 730 } 731 732 if ((localAttributeValues == null) || 733 (localAttributeValues.length == 0)) { 734 if (SAML2Utils.debug.messageEnabled()) { 735 SAML2Utils.debug.message( 736 "AttributeQueryUtil.getUserAttributes:" + 737 " user does not have " + localAttribute); 738 } 739 continue; 740 } 741 742 Attribute attr = SAML2Utils.getSAMLAttribute(samlAttribute, 743 localAttributeValues); 744 attributes.add(attr); 745 } 746 return attributes; 747 } 748 749 public static void signResponse(Response response, 750 String attrAuthorityEntityID, String realm, boolean includeCert) 751 throws SAML2Exception { 752 753 String alias = SAML2Utils.getSigningCertAlias(realm, 754 attrAuthorityEntityID, SAML2Constants.ATTR_AUTH_ROLE); 755 756 PrivateKey signingKey = keyProvider.getPrivateKey(alias); 757 if (signingKey == null) { 758 throw new SAML2Exception( 759 SAML2Utils.bundle.getString("missingSigningCertAlias")); 760 } 761 762 X509Certificate signingCert = null; 763 if (includeCert) { 764 signingCert = keyProvider.getX509Certificate(alias); 765 } 766 767 if (signingKey != null) { 768 response.sign(signingKey, signingCert); 769 } 770 } 771 772 private static Assertion getAssertion(AttributeQuery attrQuery, 773 String attrAuthorityEntityID, String requesterEntityID, String realm, 774 String attrQueryProfileAlias, List attributes) throws SAML2Exception { 775 776 AssertionFactory assertionFactory = AssertionFactory.getInstance(); 777 Assertion assertion = assertionFactory.createAssertion(); 778 assertion.setID(SAML2Utils.generateID()); 779 assertion.setVersion(SAML2Constants.VERSION_2_0); 780 assertion.setIssueInstant(new Date()); 781 Issuer issuer = assertionFactory.createIssuer(); 782 issuer.setValue(attrAuthorityEntityID); 783 assertion.setIssuer(issuer); 784 785 Subject subjectQ = attrQuery.getSubject(); 786 Subject subject = assertionFactory.createSubject(); 787 subject.setEncryptedID(subjectQ.getEncryptedID()); 788 subject.setNameID(subjectQ.getNameID()); 789 subject.setBaseID(subjectQ.getBaseID()); 790 subject.setSubjectConfirmation(subjectQ.getSubjectConfirmation()); 791 assertion.setSubject(subject); 792 793 if ((attributes != null) && (!attributes.isEmpty())) { 794 AttributeStatement attrStatement = 795 assertionFactory.createAttributeStatement(); 796 797 attrStatement.setAttribute(attributes); 798 List attrStatementList = new ArrayList(); 799 attrStatementList.add(attrStatement); 800 assertion.setAttributeStatements(attrStatementList); 801 } 802 803 int effectiveTime = IDPSSOUtil.getEffectiveTime(realm, 804 attrAuthorityEntityID); 805 int notBeforeSkewTime = IDPSSOUtil.getNotBeforeSkewTime(realm, 806 attrAuthorityEntityID); 807 Conditions conditions = IDPSSOUtil.getConditions(requesterEntityID, 808 notBeforeSkewTime, effectiveTime); 809 assertion.setConditions(conditions); 810 811 return assertion; 812 } 813 814 private static void signAssertion(Assertion assertion, String realm, 815 String attrAuthorityEntityID, boolean includeCert) 816 throws SAML2Exception { 817 818 String alias = SAML2Utils.getSigningCertAlias(realm, 819 attrAuthorityEntityID, SAML2Constants.ATTR_AUTH_ROLE); 820 821 PrivateKey signingKey = keyProvider.getPrivateKey(alias); 822 X509Certificate signingCert = null; 823 if (includeCert) { 824 signingCert = keyProvider.getX509Certificate(alias); 825 } 826 827 if (signingKey != null) { 828 assertion.sign(signingKey, signingCert); 829 } 830 } 831 832 private static EncryptedAssertion encryptAssertion(Assertion assertion, 833 EncryptedID encryptedID, String attrAuthorityEntityID, 834 String requesterEntityID, String realm, String attrQueryProfileAlias) 835 throws SAML2Exception { 836 837 String alias = SAML2Utils.getEncryptionCertAlias(realm, 838 attrAuthorityEntityID, SAML2Constants.ATTR_AUTH_ROLE); 839 PrivateKey privateKey = keyProvider.getPrivateKey(alias); 840 841 SecretKey secretKey = EncManager.getEncInstance().getSecretKey( 842 encryptedID.toXMLString(true, true), privateKey); 843 844 AttributeQueryDescriptorElement aqd = 845 metaManager.getAttributeQueryDescriptor(realm, requesterEntityID); 846 EncInfo encInfo = KeyUtil.getEncInfo(aqd, requesterEntityID, 847 SAML2Constants.ATTR_QUERY_ROLE); 848 849 Element el = EncManager.getEncInstance().encrypt( 850 assertion.toXMLString(true, true), encInfo.getWrappingKey(), 851 secretKey, encInfo.getDataEncAlgorithm(), 852 encInfo.getDataEncStrength(), requesterEntityID, 853 "EncryptedAssertion"); 854 855 return AssertionFactory.getInstance().createEncryptedAssertion(el); 856 } 857 858 private static List verifyDesiredAttributes(List supportedAttrs, 859 List desiredAttrs) throws SAML2Exception { 860 861 if ((supportedAttrs == null) || (supportedAttrs.isEmpty())) { 862 return desiredAttrs; 863 } 864 865 if ((desiredAttrs == null) || (desiredAttrs.isEmpty())) { 866 return convertAttributes(supportedAttrs); 867 } 868 869 for(Iterator iterD = desiredAttrs.iterator(); iterD.hasNext(); ) { 870 Attribute attrD = (Attribute)iterD.next(); 871 boolean isAttrValid = false; 872 Iterator iterS = supportedAttrs.iterator(); 873 while(iterS.hasNext()) { 874 AttributeElement attrS = (AttributeElement)iterS.next(); 875 if (isSameAttribute(attrD, attrS)) { 876 if (isValueValid(attrD, attrS)) { 877 isAttrValid = true; 878 break; 879 } else { 880 throw new SAML2Exception( 881 "Attribute value not suppoted"); 882 } 883 } 884 } 885 if (isAttrValid) { 886 iterS.remove(); 887 } else { 888 throw new SAML2Exception("Attribute name not suppoted"); 889 } 890 } 891 return desiredAttrs; 892 } 893 894 private static List convertAttributes(List jaxbAttrs) 895 throws SAML2Exception { 896 897 List resultAttrs = new ArrayList(); 898 for(Iterator iter = jaxbAttrs.iterator(); iter.hasNext(); ) { 899 AttributeElement jaxbAttr = (AttributeElement)iter.next(); 900 Attribute attr = AssertionFactory.getInstance().createAttribute(); 901 attr.setName(jaxbAttr.getName()); 902 attr.setNameFormat(jaxbAttr.getNameFormat()); 903 attr.setFriendlyName(jaxbAttr.getFriendlyName()); 904 905 List jaxbValues = jaxbAttr.getAttributeValue(); 906 if ((jaxbValues != null) && (!jaxbValues.isEmpty())) { 907 List newValues = new ArrayList(); 908 for(Iterator iterV = jaxbValues.iterator(); iterV.hasNext();) { 909 AttributeValueElement jaxbValeu = 910 (AttributeValueElement)iter.next(); 911 List content = jaxbValeu.getContent(); 912 if ((content != null) && (!content.isEmpty())) { 913 newValues.add(content.get(0)); 914 } 915 } 916 if (!newValues.isEmpty()) { 917 attr.setAttributeValueString(newValues); 918 } 919 } 920 resultAttrs.add(attr); 921 } 922 return resultAttrs; 923 } 924 925 private static List filterAttributes(List attributes, List desiredAttrs) { 926 927 if ((attributes == null) || (attributes.isEmpty())) { 928 SAML2Utils.debug.message("AttributeQueryUtil.filterAttributes: attributes are null"); 929 return attributes; 930 } 931 if ((desiredAttrs == null) || (desiredAttrs.isEmpty())) { 932 SAML2Utils.debug.message("AttributeQueryUtil.filterAttributes: desired attributes are null"); 933 return attributes; 934 } 935 936 List returnAttributes = new ArrayList(); 937 if ((desiredAttrs != null) && (!desiredAttrs.isEmpty())) { 938 for(Iterator iterD = desiredAttrs.iterator(); iterD.hasNext();){ 939 940 Attribute attrD = (Attribute)iterD.next(); 941 for(Iterator iter = attributes.iterator(); iter.hasNext();) { 942 943 Attribute attr = (Attribute)iter.next(); 944 if (isSameAttribute(attr, attrD) ) { 945 attr = filterAttributeValues(attr, attrD); 946 if (attr != null) { 947 //let's copy FriendlyName if exists 948 String fName = attrD.getFriendlyName(); 949 if (fName != null && fName.length() > 0){ 950 try { 951 attr.setFriendlyName(fName); 952 } catch (SAML2Exception e) { 953 //do nothing, attribute will be sent without 954 //friendlyName set 955 } 956 } 957 returnAttributes.add(attr); 958 } 959 break; 960 } 961 } 962 } 963 964 } 965 return returnAttributes; 966 967 } 968 969 private static boolean isSameAttribute(Attribute attr1, Attribute attr2) { 970 if (!attr1.getName().equals(attr2.getName())) { 971 return false; 972 } 973 974 String nameFormat1 = attr1.getNameFormat(); 975 976 if (nameFormat1 == null) { 977 return (attr2.getNameFormat() == null); 978 } else { 979 return (nameFormat1.equals(attr2.getNameFormat())); 980 } 981 982 } 983 984 private static Attribute filterAttributeValues(Attribute attr, 985 Attribute desiredAttr) { 986 987 List valuesD = desiredAttr.getAttributeValueString(); 988 if ((valuesD == null) || (valuesD.isEmpty())) { 989 return attr; 990 } 991 992 List values = attr.getAttributeValueString(); 993 if ((values == null) || (values.isEmpty())) { 994 return null; 995 } 996 997 List newValuesD = new ArrayList(); 998 for(Iterator iter = valuesD.iterator(); iter.hasNext(); ) { 999 String valueD = (String)iter.next(); 1000 if (values.contains(valueD)) { 1001 newValuesD.add(valueD); 1002 } 1003 } 1004 1005 if (newValuesD.isEmpty()) { 1006 return null; 1007 } 1008 1009 if (newValuesD.size() == valuesD.size()) { 1010 return desiredAttr; 1011 } 1012 1013 try { 1014 Attribute newAttr = 1015 AssertionFactory.getInstance().createAttribute(); 1016 newAttr.setName(desiredAttr.getName()); 1017 newAttr.setNameFormat(desiredAttr.getNameFormat()); 1018 newAttr.setFriendlyName(desiredAttr.getFriendlyName()); 1019 newAttr.setAnyAttribute(desiredAttr.getAnyAttribute()); 1020 newAttr.setAttributeValueString(newValuesD); 1021 1022 return newAttr; 1023 } catch(SAML2Exception se) { 1024 if (SAML2Utils.debug.messageEnabled()) { 1025 SAML2Utils.debug.message( 1026 "AttributeQueryUtil.filterAttributeValues:", se); 1027 } 1028 return null; 1029 } 1030 } 1031 1032 private static boolean isSameAttribute(Attribute attr1, 1033 AttributeElement attr2) { 1034 1035 if (!attr1.getName().equals(attr2.getName())) { 1036 return false; 1037 } 1038 1039 String nameFormat1 = attr1.getNameFormat(); 1040 1041 if (nameFormat1 == null) { 1042 return (attr2.getNameFormat() == null); 1043 } else { 1044 return (nameFormat1.equals(attr2.getNameFormat())); 1045 } 1046 1047 } 1048 1049 private static boolean isValueValid(Attribute desiredAttr, 1050 AttributeElement supportedAttr) { 1051 1052 List valuesD = desiredAttr.getAttributeValueString(); 1053 if ((valuesD == null) || (valuesD.isEmpty())) { 1054 return true; 1055 } 1056 List attrValuesS = supportedAttr.getAttributeValue(); 1057 if ((attrValuesS == null) || (attrValuesS.isEmpty())) { 1058 return true; 1059 } 1060 1061 List valuesS = new ArrayList(); 1062 for(Iterator iter = attrValuesS.iterator(); iter.hasNext(); ) { 1063 AttributeValueElement attrValueElem = 1064 (AttributeValueElement)iter.next(); 1065 valuesS.addAll(attrValueElem.getContent()); 1066 } 1067 1068 try { 1069 return valuesS.containsAll(valuesD); 1070 } catch (Exception ex) { 1071 if (SAML2Utils.debug.messageEnabled()) { 1072 SAML2Utils.debug.message( 1073 "AttributeQueryUtil.isValueValid:", ex); 1074 } 1075 return false; 1076 } 1077 } 1078 1079 private static Response sendAttributeQuerySOAP(AttributeQuery attrQuery, 1080 String attributeServiceURL, String attrAuthorityEntityID, 1081 AttributeAuthorityDescriptorElement aad) throws SAML2Exception { 1082 1083 String attrQueryXMLString = attrQuery.toXMLString(true, true); 1084 if (SAML2Utils.debug.messageEnabled()) { 1085 SAML2Utils.debug.message( 1086 "AttributeQueryUtil.sendAttributeQuerySOAP: " + 1087 "attrQueryXMLString = " + attrQueryXMLString); 1088 SAML2Utils.debug.message( 1089 "AttributeQueryUtil.sendAttributeQuerySOAP: " + 1090 "attributeServiceURL = " + attributeServiceURL); 1091 } 1092 1093 SOAPMessage resMsg = null; 1094 try { 1095 resMsg = SAML2Utils.sendSOAPMessage(attrQueryXMLString, 1096 attributeServiceURL, true); 1097 } catch (SOAPException se) { 1098 SAML2Utils.debug.error( 1099 "AttributeQueryUtil.sendAttributeQuerySOAP: ", se); 1100 throw new SAML2Exception( 1101 SAML2Utils.bundle.getString("errorSendingAttributeQuery")); 1102 } 1103 1104 Element respElem = SAML2Utils.getSamlpElement(resMsg, "Response"); 1105 Response response = 1106 ProtocolFactory.getInstance().createResponse(respElem); 1107 1108 if (SAML2Utils.debug.messageEnabled()) { 1109 SAML2Utils.debug.message( 1110 "AttributeQueryUtil.sendAttributeQuerySOAP: " + 1111 "response = " + response.toXMLString(true, true)); 1112 } 1113 1114 verifyResponse(response, attrQuery, attrAuthorityEntityID, aad); 1115 1116 return response; 1117 } 1118 1119 private static void verifyResponse(Response response, 1120 AttributeQuery attrQuery, String attrAuthorityEntityID, 1121 AttributeAuthorityDescriptorElement aad) 1122 throws SAML2Exception { 1123 1124 String attrQueryID = attrQuery.getID(); 1125 if ((attrQueryID != null) && 1126 (!attrQueryID.equals(response.getInResponseTo()))) { 1127 1128 throw new SAML2Exception( 1129 SAML2Utils.bundle.getString("invalidInResponseToAttrQuery")); 1130 } 1131 1132 Issuer respIssuer = response.getIssuer(); 1133 if (respIssuer == null) { 1134 return; 1135 } 1136 1137 if (!attrAuthorityEntityID.equals(respIssuer.getValue())) { 1138 throw new SAML2Exception(SAML2Utils.bundle.getString( 1139 "responseIssuerMismatch")); 1140 } 1141 1142 if (!response.isSigned()) { 1143 throw new SAML2Exception(SAML2Utils.bundle.getString( 1144 "responseNotSigned")); 1145 } 1146 1147 X509Certificate signingCert = 1148 KeyUtil.getVerificationCert(aad, attrAuthorityEntityID, 1149 SAML2Constants.ATTR_AUTH_ROLE); 1150 1151 if (signingCert != null) { 1152 boolean valid = response.isSignatureValid(signingCert); 1153 if (SAML2Utils.debug.messageEnabled()) { 1154 SAML2Utils.debug.message( 1155 "AttributeQueryUtil.verifyResponse: " + 1156 "Signature validity is : " + valid); 1157 } 1158 if (!valid) { 1159 throw new SAML2Exception(SAML2Utils.bundle.getString( 1160 "invalidSignatureOnResponse")); 1161 } 1162 } else { 1163 throw new SAML2Exception( 1164 SAML2Utils.bundle.getString("missingSigningCertAlias")); 1165 } 1166 1167 } 1168 1169 private static String findLocation( 1170 AttributeAuthorityDescriptorElement aad, String binding, 1171 String attrQueryProfile, String attrProfile) { 1172 SAML2Utils.debug.message("AttributeQueryUtil.findLocation entering..."); 1173 List attrProfiles = aad.getAttributeProfile(); 1174 if ((attrProfiles == null) || (attrProfiles.isEmpty())) { 1175 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: attrProfiles is null or empty"); 1176 if (attrProfile != null) { 1177 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: attrProfiles is null or empty and attrProfile is null"); 1178 return null; 1179 } 1180 } else if (!attrProfiles.contains(attrProfile)) { 1181 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: attrProfile not found in the attrProfiles"); 1182 return null; 1183 } 1184 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: entering..."); 1185 1186 List attrServices = aad.getAttributeService(); 1187 for(Iterator iter = attrServices.iterator(); iter.hasNext(); ) { 1188 AttributeServiceElement attrService = 1189 (AttributeServiceElement)iter.next(); 1190 if (isValidAttributeService(binding, attrService, 1191 attrQueryProfile)) { 1192 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: found valid service"); 1193 return attrService.getLocation(); 1194 } 1195 } 1196 SAML2Utils.debug.message("AttributeQueryUtil.findLocation: nothing found, leaving last line with null"); 1197 1198 return null; 1199 } 1200 1201 private static boolean isValidAttributeService(String binding, 1202 AttributeServiceElement attrService, String attrQueryProfile) { 1203 1204 if (!binding.equalsIgnoreCase(attrService.getBinding())) { 1205 return false; 1206 } 1207 1208 if (attrQueryProfile == null) { 1209 return false; 1210 } 1211 1212 return ((attrQueryProfile.equals( 1213 SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE)) || 1214 (SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE.equals( 1215 attrQueryProfile) && attrService.isSupportsX509Query())); 1216 } 1217 1218 /** 1219 * Returns an <code>AttributeAuthorityMapper</code> 1220 * 1221 * @param realm the realm name 1222 * @param attrAuthorityEntityID the entity id of the attribute authority 1223 * @param attrQueryProfileAlias attribute profile alias 1224 * 1225 * @return the <code>AttributeAuthorityMapper</code> 1226 * @exception SAML2Exception if the operation is not successful 1227 */ 1228 static AttributeAuthorityMapper getAttributeAuthorityMapper(String realm, 1229 String attrAuthorityEntityID, String attrQueryProfileAlias) 1230 throws SAML2Exception { 1231 1232 String attrAuthorityMapperName = null; 1233 AttributeAuthorityMapper attrAuthorityMapper = null; 1234 try { 1235 attrAuthorityMapperName = getAttributeValueFromAttrAuthorityConfig( 1236 realm, attrAuthorityEntityID, attrQueryProfileAlias + "_" + 1237 SAML2Constants.ATTRIBUTE_AUTHORITY_MAPPER); 1238 1239 if (attrAuthorityMapperName == null) { 1240 attrAuthorityMapperName = 1241 SAML2Constants.DEFAULT_ATTRIBUTE_AUTHORITY_MAPPER_CLASS; 1242 if (SAML2Utils.debug.messageEnabled()) { 1243 SAML2Utils.debug.message( 1244 "AttributeQueryUtil.getAttributeAuthorityMapper: use "+ 1245 attrAuthorityMapperName); 1246 } 1247 } 1248 attrAuthorityMapper = (AttributeAuthorityMapper) 1249 attrAuthorityMapperCache.get(attrAuthorityMapperName); 1250 if (attrAuthorityMapper == null) { 1251 attrAuthorityMapper = (AttributeAuthorityMapper) 1252 Class.forName(attrAuthorityMapperName).newInstance(); 1253 attrAuthorityMapperCache.put(attrAuthorityMapperName, 1254 attrAuthorityMapper); 1255 } else { 1256 if (SAML2Utils.debug.messageEnabled()) { 1257 SAML2Utils.debug.message( 1258 "AttributeQueryUtil.getAttributeAuthorityMapper: " + 1259 "got the AttributeAuthorityMapper from cache"); 1260 } 1261 } 1262 } catch (Exception ex) { 1263 SAML2Utils.debug.error( 1264 "AttributeQueryUtil.getAttributeAuthorityMapper: " + 1265 "Unable to get IDP Attribute Mapper.", ex); 1266 throw new SAML2Exception(ex); 1267 } 1268 1269 return attrAuthorityMapper; 1270 } 1271 1272 private static String getAttributeValueFromAttrAuthorityConfig( 1273 String realm, String attrAuthorityEntityID, String attrName) 1274 { 1275 try { 1276 AttributeAuthorityConfigElement config = 1277 metaManager.getAttributeAuthorityConfig(realm, 1278 attrAuthorityEntityID); 1279 Map attrs = SAML2MetaUtils.getAttributes(config); 1280 String value = null; 1281 List values = (List) attrs.get(attrName); 1282 if ((values != null) && (!values.isEmpty())) { 1283 value = ((String)values.iterator().next()).trim(); 1284 } 1285 return value; 1286 } catch (SAML2MetaException sme) { 1287 if (SAML2Utils.debug.messageEnabled()) { 1288 SAML2Utils.debug.message("AttributeQueryUtil." + 1289 "getAttributeValueFromAttrAuthorityConfig: " + 1290 "get AttributeAuthorityConfig failed", sme); 1291 } 1292 } 1293 return null; 1294 } 1295 1296 /** 1297 * Sends the AttributeQuery to specified attribute authority, 1298 * validates the response and returns the attribute map 1299 * <code>Map<String, String></code> to the Fedlet 1300 * 1301 * @param spEntityID SP entity ID 1302 * @param idpEntityID IDP entity ID 1303 * @param nameIDValue NameID value 1304 * @param attrsList The list of attributes whose values need to be 1305 * fetched from IDP 1306 * @param attrQueryProfileAlias Attribute Query Profile Alias 1307 * @param subjectDN Attribute name which contains X.509 subject DN 1308 * 1309 * @return the <code>Map</code> object 1310 * @exception SAML2Exception if the operation is not successful 1311 * 1312 * @deprecated Use #getAttributesForFedlet(String, String, String, List, String, String) 1313 */ 1314 public static Map<String, String> getAttributeMapForFedlet(String spEntityID, 1315 String idpEntityID, 1316 String nameIDValue, 1317 List attrsList, 1318 String attrQueryProfileAlias, 1319 String subjectDN) 1320 throws SAML2Exception { 1321 Map<String, Set<String>> attrMap = getAttributesForFedlet(spEntityID, 1322 idpEntityID, 1323 nameIDValue, 1324 attrsList, 1325 attrQueryProfileAlias, 1326 subjectDN); 1327 1328 Map<String, String> newAttrMap = new HashMap<String, String>(); 1329 for (Map.Entry<String, Set<String>> entry : attrMap.entrySet()) { 1330 String attrName = entry.getKey(); 1331 Set<String> attrValue = entry.getValue(); 1332 StringBuilder pipedValue = new StringBuilder(); 1333 for(String value : attrValue) { 1334 // Multiple attribute values 1335 // are seperated with "|" 1336 if (pipedValue.length() > 0 ) { 1337 pipedValue.append('|'); 1338 } 1339 pipedValue.append(value); 1340 } 1341 newAttrMap.put(attrName, pipedValue.toString()); 1342 1343 } 1344 1345 return newAttrMap; 1346 } 1347 1348 /** 1349 * Sends the AttributeQuery to specified attribute authority, 1350 * validates the response and returns the attribute map 1351 * <code>Map<String, Set<String>></code> to the Fedlet 1352 * 1353 * @param spEntityID SP entity ID 1354 * @param idpEntityID IDP entity ID 1355 * @param nameIDValue NameID value 1356 * @param attrsList The list of attributes whose values need to be 1357 * fetched from IDP 1358 * @param attrQueryProfileAlias Attribute Query Profile Alias 1359 * @param subjectDN Attribute name which contains X.509 subject DN 1360 * 1361 * @return the <code>Map</code> object 1362 * @exception SAML2Exception if the operation is not successful 1363 * 1364 * @supported.api 1365 */ 1366 public static Map<String, Set<String>> getAttributesForFedlet(String spEntityID, 1367 String idpEntityID, 1368 String nameIDValue, 1369 List attrsList, 1370 String attrQueryProfileAlias, 1371 String subjectDN) 1372 throws SAML2Exception { 1373 1374 AttributeQueryConfigElement attrQueryConfig = 1375 metaManager.getAttributeQueryConfig("/", spEntityID); 1376 if (attrQueryConfig == null) { 1377 if (SAML2Utils.debug.messageEnabled()) { 1378 SAML2Utils.debug.message("AttributeQueryUtil." + 1379 "getAttributeMapForFedlet: " + 1380 "Attribute Query Config is null"); 1381 } 1382 return null; 1383 } 1384 1385 String attrqMetaAlias = attrQueryConfig.getMetaAlias(); 1386 if (attrqMetaAlias == null) { 1387 if (SAML2Utils.debug.messageEnabled()) { 1388 SAML2Utils.debug.message("AttributeQueryUtil." + 1389 "getAttributeMapForFedlet: " + 1390 "Attribute Query MetaAlias is null"); 1391 } 1392 return null; 1393 } 1394 1395 boolean wantNameIDEncrypted = SAML2Utils.getWantNameIDEncrypted("/", 1396 spEntityID, 1397 SAML2Constants.ATTR_QUERY_ROLE); 1398 1399 AttributeQuery attrQuery = constructAttrQueryForFedlet(spEntityID, 1400 idpEntityID, 1401 nameIDValue, 1402 attrsList, 1403 attrqMetaAlias, 1404 attrQueryProfileAlias, 1405 subjectDN, 1406 wantNameIDEncrypted); 1407 1408 String attrQueryProfile = null; 1409 if (attrQueryProfileAlias.equals( 1410 SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE_ALIAS)) { 1411 attrQueryProfile = SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE; 1412 } else if (attrQueryProfileAlias.equals( 1413 SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE_ALIAS)) { 1414 attrQueryProfile = SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE; 1415 } 1416 1417 Response samlResp = sendAttributeQuery(attrQuery, idpEntityID, 1418 "/", 1419 attrQueryProfile, 1420 SAML2Constants.BASIC_ATTRIBUTE_PROFILE, 1421 SAML2Constants.SOAP); 1422 1423 // Validate the response 1424 boolean validResp = validateSAMLResponseForFedlet(samlResp, 1425 spEntityID, 1426 wantNameIDEncrypted); 1427 Map<String, Set<String>> attrMap = new HashMap(); 1428 if (validResp) { 1429 // Return back the AttributeMap 1430 if (samlResp != null) { 1431 List assertions = null; 1432 if (wantNameIDEncrypted) { 1433 assertions = samlResp.getEncryptedAssertion(); 1434 } else { 1435 assertions = samlResp.getAssertion(); 1436 } 1437 for (Iterator asserIter = assertions.iterator(); 1438 asserIter.hasNext();) { 1439 Assertion assertion = null; 1440 if (wantNameIDEncrypted) { 1441 assertion = getDecryptedAssertion( 1442 (EncryptedAssertion)asserIter.next(), 1443 spEntityID); 1444 } else { 1445 assertion = (Assertion)asserIter.next(); 1446 } 1447 if (assertion != null) { 1448 List statements = assertion.getAttributeStatements(); 1449 if (statements != null && statements.size() > 0 ) { 1450 for (Iterator stmtIter = statements.iterator(); 1451 stmtIter.hasNext();) { 1452 AttributeStatement statement = 1453 (AttributeStatement)stmtIter.next(); 1454 List attributes = statement.getAttribute(); 1455 if (attributes != null) { 1456 for (Iterator attribIter = 1457 attributes.iterator(); 1458 attribIter.hasNext(); ) { 1459 Attribute attr = 1460 (Attribute)attribIter.next(); 1461 String attrName = attr.getName(); 1462 List attrValueList = 1463 attr.getAttributeValueString(); 1464 Set<String> attrValue = new HashSet(); 1465 for (Iterator attrValueIter = 1466 attrValueList.iterator(); 1467 attrValueIter.hasNext(); ) { 1468 String value = 1469 (String)attrValueIter.next(); 1470 attrValue.add(value); 1471 } 1472 attrMap.put(attrName,attrValue); 1473 } 1474 } else { 1475 if (SAML2Utils.debug.messageEnabled()) { 1476 SAML2Utils.debug.message( 1477 "AttributeQueryUtil." + 1478 "getAttributeMapForFedlet: " + 1479 "No Attributes present in " + 1480 "SAML response"); 1481 } 1482 } 1483 } 1484 } else { 1485 if (SAML2Utils.debug.messageEnabled()) { 1486 SAML2Utils.debug.message("AttributeQueryUtil." + 1487 "getAttributeMapForFedlet: " + 1488 "Empty Statement present in SAML response"); 1489 } 1490 } 1491 } else { 1492 if (SAML2Utils.debug.messageEnabled()) { 1493 SAML2Utils.debug.message("AttributeQueryUtil." + 1494 "getAttributeMapForFedlet: " + 1495 "Empty Assertion present in SAML response"); 1496 } 1497 } 1498 } 1499 } 1500 } else { 1501 if (SAML2Utils.debug.messageEnabled()) { 1502 SAML2Utils.debug.message("AttributeQueryUtil." + 1503 "getAttributeMapForFedlet: " + 1504 "Invalid response obtained from Attribute Authority"); 1505 } 1506 } 1507 // Return the attribute map and to the fedlet 1508 return attrMap; 1509 } 1510 1511 /** 1512 * Constructs the Attribute Query used by the Fedlet to retrieve the 1513 * values from IDP 1514 * 1515 * @param samlResp saml response 1516 * 1517 * @exception SAML2Exception if the operation is not successful 1518 * 1519 * @supported.api 1520 */ 1521 private static AttributeQuery constructAttrQueryForFedlet( 1522 String spEntityID, 1523 String idpEntityID, 1524 String nameIDValue, 1525 List attrsList, 1526 String attrqMetaAlias, 1527 String attrProfileNameAlias, 1528 String subjectDN, 1529 boolean wantNameIDEncrypted) throws SAML2Exception 1530 { 1531 String attrqEntityID = 1532 SAML2Utils.getSAML2MetaManager().getEntityByMetaAlias(attrqMetaAlias); 1533 1534 ProtocolFactory protocolFactory = ProtocolFactory.getInstance(); 1535 AssertionFactory assertionFactory = AssertionFactory.getInstance(); 1536 1537 AttributeQuery attrQuery = protocolFactory.createAttributeQuery(); 1538 1539 Issuer issuer = assertionFactory.createIssuer(); 1540 issuer.setValue(attrqEntityID); 1541 1542 attrQuery.setIssuer(issuer); 1543 attrQuery.setID(SAML2Utils.generateID()); 1544 attrQuery.setVersion(SAML2Constants.VERSION_2_0); 1545 attrQuery.setIssueInstant(new Date()); 1546 1547 List attrs = new ArrayList(); 1548 for (Iterator attrIter = attrsList.iterator(); 1549 attrIter.hasNext();) { 1550 Attribute attr = assertionFactory.createAttribute(); 1551 String attributeName = (String)attrIter.next(); 1552 attr.setName(attributeName); 1553 attr.setNameFormat(SAML2Constants.BASIC_NAME_FORMAT); 1554 attrs.add(attr); 1555 } 1556 attrQuery.setAttributes(attrs); 1557 1558 Subject subject = assertionFactory.createSubject(); 1559 NameID nameID = assertionFactory.createNameID(); 1560 nameID.setNameQualifier(idpEntityID); 1561 nameID.setSPNameQualifier(spEntityID); 1562 1563 if (attrProfileNameAlias.equals( 1564 SAML2Constants.DEFAULT_ATTR_QUERY_PROFILE_ALIAS)) { 1565 nameID.setFormat(SAML2Constants.NAMEID_TRANSIENT_FORMAT); 1566 nameID.setValue(nameIDValue); 1567 } 1568 1569 if (attrProfileNameAlias.equals( 1570 SAML2Constants.X509_SUBJECT_ATTR_QUERY_PROFILE_ALIAS)) { 1571 nameID.setFormat(SAML2Constants.X509_SUBJECT_NAME); 1572 nameID.setValue(subjectDN); 1573 } 1574 1575 if (!wantNameIDEncrypted) { 1576 subject.setNameID(nameID); 1577 } else { 1578 AttributeAuthorityDescriptorElement aad = 1579 metaManager.getAttributeAuthorityDescriptor("/", idpEntityID); 1580 1581 EncInfo encInfo = KeyUtil.getEncInfo(aad, idpEntityID, 1582 SAML2Constants.ATTR_AUTH_ROLE); 1583 1584 EncryptedID encryptedID = nameID.encrypt(encInfo.getWrappingKey(), 1585 encInfo.getDataEncAlgorithm(), 1586 encInfo.getDataEncStrength(), 1587 idpEntityID); 1588 subject.setEncryptedID(encryptedID); 1589 } 1590 1591 attrQuery.setSubject(subject); 1592 1593 return attrQuery; 1594 } 1595 1596 /** 1597 * Validates the SAML response obtained from Attribute Authortity 1598 * 1599 * @param samlResp saml response 1600 * 1601 * @exception SAML2Exception if the operation is not successful 1602 * 1603 * @supported.api 1604 */ 1605 private static boolean validateSAMLResponseForFedlet( 1606 Response samlResp, 1607 String spEntityID, 1608 boolean wantNameIDEncrypted) throws SAML2Exception 1609 { 1610 boolean resp = true; 1611 if (samlResp != null && samlResp.isSigned()) { 1612 List assertions = null; 1613 if (wantNameIDEncrypted) { 1614 assertions = samlResp.getEncryptedAssertion(); 1615 } else { 1616 assertions = samlResp.getAssertion(); 1617 } 1618 if (assertions == null) { 1619 return false; 1620 } 1621 for (Iterator asserIter = assertions.iterator(); 1622 asserIter.hasNext();) { 1623 Assertion assertion = null; 1624 if (wantNameIDEncrypted) { 1625 assertion = getDecryptedAssertion( 1626 (EncryptedAssertion)asserIter.next(), 1627 spEntityID); 1628 } else { 1629 assertion = (Assertion)asserIter.next(); 1630 } 1631 if (assertion != null) { 1632 Conditions conditions = assertion.getConditions(); 1633 if (conditions != null) { 1634 List audienceRes = conditions. 1635 getAudienceRestrictions(); 1636 if (audienceRes.size() > 1) { 1637 resp = false; 1638 break; 1639 } 1640 } 1641 List statements = assertion.getAttributeStatements(); 1642 if (statements.size() > 1) { 1643 resp = false; 1644 break; 1645 } 1646 } 1647 } 1648 } else { 1649 resp = false; 1650 } 1651 return resp; 1652 } 1653 1654 /** 1655 * Returns the decrypted assertion 1656 * 1657 * @param samlResp saml response 1658 * 1659 * @exception SAML2Exception if the operation is not successful 1660 * 1661 * @supported.api 1662 */ 1663 private static Assertion getDecryptedAssertion( 1664 EncryptedAssertion eAssertion, 1665 String spEntityID) throws SAML2Exception 1666 { 1667 if (eAssertion != null) { 1668 String alias = SAML2Utils.getEncryptionCertAlias("/", spEntityID, 1669 SAML2Constants.ATTR_QUERY_ROLE); 1670 PrivateKey privateKey = 1671 KeyUtil.getKeyProviderInstance().getPrivateKey(alias); 1672 if (privateKey != null) { 1673 Assertion assertion = eAssertion.decrypt(privateKey); 1674 return assertion; 1675 } 1676 } 1677 return null; 1678 } 1679}