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: SAML2SDKUtils.java,v 1.12 2008/08/31 05:49:48 bina Exp $ 026 * 027 * Portions copyright 2014 ForgeRock AS. 028 * 029 */ 030 031 032package com.sun.identity.saml2.common; 033 034import com.sun.identity.liberty.ws.disco.ResourceOffering; 035import com.sun.identity.liberty.ws.security.SecurityAssertion; 036import com.sun.identity.plugin.session.SessionManager; 037import com.sun.identity.plugin.session.SessionProvider; 038import com.sun.identity.saml.common.SAMLConstants; 039import com.sun.identity.saml.common.SAMLUtilsCommon; 040import com.sun.identity.saml2.jaxb.entityconfig.BaseConfigType; 041import com.sun.identity.saml2.meta.SAML2MetaUtils; 042import com.sun.identity.shared.configuration.SystemPropertiesManager; 043import com.sun.identity.shared.debug.Debug; 044import com.sun.identity.shared.locale.Locale; 045import com.sun.identity.shared.xml.XMLUtils; 046 047import java.security.SecureRandom; 048import java.lang.reflect.Constructor; 049import java.lang.reflect.InvocationTargetException; 050import java.util.ArrayList; 051import java.util.HashMap; 052import java.util.List; 053import java.util.Map; 054import java.util.ResourceBundle; 055import javax.servlet.http.HttpServletRequest; 056import javax.xml.soap.SOAPException; 057import org.w3c.dom.Attr; 058import org.w3c.dom.Element; 059import org.w3c.dom.NamedNodeMap; 060 061/** 062 * The <code>SAML2SDKUtils</code> contains utility methods for SAML 2.0 063 * implementation. 064 * 065 * @supported.all.api 066 */ 067public class SAML2SDKUtils { 068 // 069 // This utility class will be run on client side as well, 070 // so DO NOT add any static block which will not run on client side. 071 // 072 // The debugging instances 073 public static Debug debug = Debug.getInstance("libSAML2"); 074 private static Debug decryptDebug = Debug.getInstance("SAML2Decrypt"); 075 // SAML2 Resource bundle 076 public static final String BUNDLE_NAME = "libSAML2"; 077 // The resource bundle for SAML 2.0 implementation. 078 public static ResourceBundle bundle = Locale. 079 getInstallResourceBundle(BUNDLE_NAME); 080 protected static final String SAML2ID_PREFIX = "s2"; 081 public static SecureRandom random = new SecureRandom(); 082 083 /** 084 * Defines mapping between interface and implementation class, 085 * the properties are read from AMConfig.properties in following format: 086 * com.sun.identity.saml2.sdk.mapping.<interface>=<implementation_class> 087 * e.g. 088 * com.sun.identity.saml2.sdk.mapping.Assertion=com.xxx.saml2.AssertionImpl 089 */ 090 private static Map classMapping = new HashMap(); 091 092 // define constants for the interface names 093 public static final String ACTION = "Action"; 094 public static final String ADVICE = "Advice"; 095 public static final String ASSERTION = "Assertion"; 096 public static final String ASSERTION_ID_REF = "AssertionIDRef"; 097 public static final String ASSERTION_ID_REQUEST = "AssertionIDRequest"; 098 public static final String ATTRIBUTE = "Attribute"; 099 public static final String ATTRIBUTE_STATEMENT = "AttributeStatement"; 100 public static final String AUDIENCE_RESTRICTION = "AudienceRestriction"; 101 public static final String AUTHN_CONTEXT = "AuthnContext"; 102 public static final String AUTHN_STATEMENT = "AuthnStatement"; 103 public static final String AUTHZ_DECISION_STATEMENT = 104 "AuthzDecisionStatement"; 105 public static final String BASEID = "BaseID"; 106 public static final String CONDITION = "Condition"; 107 public static final String CONDITIONS = "Conditions"; 108 public static final String ENCRYPTED_ASSERTION = "EncryptedAssertion"; 109 public static final String ENCRYPTED_ATTRIBUTE = "EncryptedAttribute"; 110 public static final String ENCRYPTED_ELEMENT = "EncryptedElement"; 111 public static final String ENCRYPTEDID = "EncryptedID"; 112 public static final String EVIDENCE = "Evidence"; 113 public static final String ISSUER = "Issuer"; 114 public static final String KEYINFO_CONFIRMATION_DATA = 115 "KeyInfoConfirmationData"; 116 public static final String NAMEID = "NameID"; 117 public static final String ONE_TIME_USE = "OneTimeUse"; 118 public static final String PROXY_RESTRICTION = "ProxyRestriction"; 119 public static final String STATEMENT = "Statement"; 120 public static final String SUBJECT_CONFIRMATION_DATA = 121 "SubjectConfirmationData"; 122 public static final String SUBJECT_CONFIRMATION = "SubjectConfirmation"; 123 public static final String SUBJECT = "Subject"; 124 public static final String SUBJECT_LOCALITY = "SubjectLocality"; 125 public static final String ARTIFACT = "Artifact"; 126 public static final String ARTIFACT_RESOLVE = "ArtifactResolve"; 127 public static final String ARTIFACT_RESPONSE = "ArtifactResponse"; 128 public static final String ATTRIBUTE_QUERY = "AttributeQuery"; 129 public static final String AUTHN_QUERY = "AuthnQuery"; 130 public static final String AUTHN_REQUEST = "AuthnRequest"; 131 public static final String ECP_RELAY_STATE = "ECPRelayState"; 132 public static final String ECP_REQUEST = "ECPRequest"; 133 public static final String ECP_RESPONSE = "ECPResponse"; 134 public static final String EXTENSIONS = "Extensions"; 135 public static final String GET_COMPLETE = "GetComplete"; 136 public static final String IDPENTRY = "IDPEntry"; 137 public static final String IDPLIST = "IDPList"; 138 public static final String LOGOUT_REQUEST = "LogoutRequest"; 139 public static final String LOGOUT_RESPONSE = "LogoutResponse"; 140 public static final String MANAGE_NAMEID_REQUEST = "ManageNameIDRequest"; 141 public static final String MANAGE_NAMEID_RESPONSE = "ManageNameIDResponse"; 142 public static final String NAMEID_POLICY = "NameIDPolicy"; 143 public static final String NEW_ENCRYPTEDID = "NewEncryptedID"; 144 public static final String NEWID = "NewID"; 145 public static final String REQUESTED_AUTHN_CONTEXT = 146 "RequestedAuthnContext"; 147 public static final String REQUESTERID = "RequesterID"; 148 public static final String RESPONSE = "Response"; 149 public static final String SCOPING = "Scoping"; 150 public static final String SESSION_INDEX = "SessionIndex"; 151 public static final String STATUS_CODE = "StatusCode"; 152 public static final String STATUS_DETAIL = "StatusDetail"; 153 public static final String STATUS = "Status"; 154 public static final String STATUS_MESSAGE = "StatusMessage"; 155 public static final String STATUS_RESPONSE = "StatusResponse"; 156 public static final String NAMEIDMAPPING_REQ = "NameIDMappingRequest"; 157 public static final String NAMEIDMAPPING_RES = "NameIDMappingResponse"; 158 159 /** 160 * List of Interfaces in assertion and protocol packages which could have 161 * customized implementation 162 */ 163 private static String[] interfactNames = { 164 ACTION, ADVICE, ASSERTION, ASSERTION_ID_REF, ASSERTION_ID_REQUEST, 165 ATTRIBUTE, ATTRIBUTE_STATEMENT, AUDIENCE_RESTRICTION, AUTHN_CONTEXT, 166 AUTHN_STATEMENT, AUTHZ_DECISION_STATEMENT, BASEID, 167 CONDITION, CONDITIONS, ENCRYPTED_ASSERTION, 168 ENCRYPTED_ATTRIBUTE, ENCRYPTED_ELEMENT, ENCRYPTEDID, EVIDENCE, 169 ISSUER, KEYINFO_CONFIRMATION_DATA, NAMEID, 170 ONE_TIME_USE, PROXY_RESTRICTION, STATEMENT, 171 SUBJECT_CONFIRMATION_DATA, SUBJECT_CONFIRMATION, SUBJECT, 172 SUBJECT_LOCALITY, ARTIFACT, ARTIFACT_RESOLVE, ARTIFACT_RESPONSE, 173 ATTRIBUTE_QUERY, AUTHN_QUERY, AUTHN_REQUEST, EXTENSIONS, GET_COMPLETE, 174 IDPENTRY, IDPLIST, LOGOUT_REQUEST, LOGOUT_RESPONSE, 175 MANAGE_NAMEID_REQUEST, MANAGE_NAMEID_RESPONSE, NAMEID_POLICY, 176 NEW_ENCRYPTEDID, NEWID, REQUESTED_AUTHN_CONTEXT, REQUESTERID, RESPONSE, 177 SCOPING, SESSION_INDEX, STATUS_CODE, STATUS_DETAIL, STATUS, 178 STATUS_MESSAGE, STATUS_RESPONSE, NAMEIDMAPPING_REQ, NAMEIDMAPPING_RES}; 179 180 /** 181 * Class array for Artifact constructor 182 */ 183 private static Class[] artParam = new Class[] { (new byte[2]).getClass(), 184 int.class, String.class, String.class }; 185 186 /** 187 * Class array for String as parameter 188 */ 189 private static Class[] stringParam = new Class[] {String.class}; 190 191 /** 192 * Class array for Element as parameter 193 */ 194 private static Class[] elementParam = new Class[] {Element.class}; 195 196 static { 197 // initialize class mapper 198 int len = interfactNames.length; 199 for (int i = 0; i < len; i++) { 200 String iName = interfactNames[i]; 201 try { 202 String implClass = SystemPropertiesManager.get( 203 SAML2Constants.SDK_CLASS_MAPPING + iName); 204 if (implClass != null && implClass.trim().length() != 0) { 205 // try it out 206 if (debug.messageEnabled()) { 207 debug.message("SAML2SDKUtils.init: mapper for " + iName 208 + "=" + implClass); 209 } 210 classMapping.put(iName, Class.forName(implClass.trim())); 211 } 212 } catch (ClassNotFoundException cnfe) { 213 debug.error("SAML2SDKUtils.init: " + iName, cnfe); 214 } 215 } 216 } 217 218 /** 219 * Protected contstructor. 220 */ 221 protected SAML2SDKUtils() {} 222 223 /** 224 * Returns default object instance for a given interface. 225 * @param iName name of the interface. 226 * @return object instance corresponding to the interface implementation. 227 * return null if the object instance could not be obtained. 228 */ 229 public static Object getObjectInstance(String iName) { 230 Class implClass = (Class) classMapping.get(iName); 231 if (implClass == null) { 232 return null; 233 } else { 234 try { 235 return implClass.newInstance(); 236 } catch (InstantiationException ie) { 237 debug.error("SAML2SDKUtils.getDefaultInstance: " + iName, ie); 238 } catch (IllegalAccessException iae) { 239 debug.error("SAML2SDKUtils.getDefaultInstance: " + iName, iae); 240 } 241 return null; 242 } 243 } 244 245 /** 246 * Returns new object instance taking String parameter in constructor. 247 * @param iName name of the interface. 248 * @param value String value to be used as parameter in constructor. 249 * @return object instance corresponding to the interface implementation. 250 * return null if the object instance could not be obtained. 251 */ 252 public static Object getObjectInstance(String iName, String value){ 253 Class implClass = (Class) classMapping.get(iName); 254 if (implClass == null) { 255 return null; 256 } else { 257 if (debug.messageEnabled()) { 258 debug.message("SAML2SDKUtils.getObjectInstance: new customized " 259 + "impl (String) instance for " + iName); 260 } 261 Object[] params = new Object[] { value }; 262 return getObjectInstance(implClass, stringParam, params); 263 } 264 } 265 266 /** 267 * Returns new object instance taking Element parameter in constructor. 268 * @param iName name of the interface. 269 * @param value Element value to be used as parameter in constructor. 270 * @return object instance corresponding to the interface implementation. 271 * return null if the object instance could not be obtained. 272 */ 273 public static Object getObjectInstance(String iName, Element value) { 274 Class implClass = (Class) classMapping.get(iName); 275 if (implClass == null) { 276 return null; 277 } else { 278 if (debug.messageEnabled()) { 279 debug.message("SAML2SDKUtils.getObjectInstance: new customized " 280 + "impl instance (Element) for " + iName); 281 } 282 Object[] params = new Object[] { value }; 283 return getObjectInstance(implClass, elementParam, params); 284 } 285 } 286 287 /** 288 * Returns new object instance with given parameters. 289 * @param iName name of the interface. 290 * @param typecode type code. 291 * @param endpointIndex end point index. 292 * @param sourceID source ID. 293 * @param messageHandle message handler. 294 * @return object instance corresponding to the interface implementation. 295 * return null if the object instance could not be obtained. 296 */ 297 298 public static Object getObjectInstance(String iName, byte[] typecode, 299 int endpointIndex, String sourceID, String messageHandle) { 300 Class implClass = (Class) classMapping.get(iName); 301 if (implClass == null) { 302 return null; 303 } else { 304 if (debug.messageEnabled()) { 305 debug.message("SAML2SDKUtils.getObjectInstance: new customized " 306 + "impl (4) instance for " + iName); 307 } 308 Object[] params = new Object[] 309 { typecode, new Integer(endpointIndex), 310 sourceID, messageHandle }; 311 return getObjectInstance(implClass, artParam, params); 312 } 313 } 314 315 316 /** 317 * Returns new object instance with given parameter in constructor. 318 * @param impl Class instance. 319 * @param paramObj Class array for constructor parameters. 320 * @param valueObj Object array for values of constructor parameters. 321 * @return object instance corresponding to the interface implementation. 322 * return null if the object instance could not be obtained. 323 */ 324 private static Object getObjectInstance(Class impl, 325 Class[] paramObj, Object[] valueObj) { 326 try { 327 Constructor constr = impl.getConstructor(paramObj); 328 return constr.newInstance(valueObj); 329 } catch (NoSuchMethodException nsme) { 330 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 331 nsme); 332 } catch (SecurityException se) { 333 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 334 se); 335 } catch (InstantiationException ie) { 336 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 337 ie); 338 } catch (IllegalAccessException iae) { 339 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 340 iae); 341 } catch (IllegalArgumentException iae) { 342 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 343 iae); 344 } catch (InvocationTargetException ite) { 345 debug.error("SAML2SDKUtils.getObjectInstance: " + impl.getName(), 346 ite); 347 } 348 return null; 349 } 350 351 /** 352 * Verifies if an element is a type of a specific statement. 353 * Currently, this method is used by class AuthnStatementImpl, 354 * AuthzDecisionStatement and AttributeStatementImpl. 355 * @param element a DOM Element which needs to be verified. 356 * @param statementname A specific name of a statement, for example, 357 * AuthnStatement, AuthzStatement or AttributeStatement 358 * @return <code>true</code> if the element is of the specific type; 359 * <code>false</code> otherwise. 360 */ 361 public static boolean checkStatement(Element element, String statementname){ 362 if (element == null || statementname == null) { 363 return false; 364 } 365 366 String tag = element.getLocalName(); 367 if (tag == null) { 368 return false; 369 } else if (tag.equals("Statement")) { 370 NamedNodeMap nm = element.getAttributes(); 371 int len = nm.getLength(); 372 String attrName = null; 373 Attr attr = null; 374 for (int j = 0; j < len; j++) { 375 attr = (Attr) nm.item(j); 376 attrName = attr.getLocalName(); 377 if ((attrName != null) && (attrName.equals("type")) && 378 (attr.getNodeValue().equals(statementname + "Type"))) { 379 return true; 380 } 381 } 382 } else if (tag.equals(statementname)) { 383 return true; 384 } 385 return false; 386 } 387 388 /** 389 * Converts byte array to String. 390 * 391 * @param bytes Byte Array to be converted. 392 * @return result of the conversion. 393 */ 394 public static String byteArrayToString(byte[] bytes) { 395 char chars[] = new char[bytes.length]; 396 for (int i = 0; i < bytes.length; i++) { 397 chars[i] = (char) bytes[i]; 398 } 399 return new String(chars); 400 } 401 402 /** 403 * Converts integer to byte array. 404 * 405 * @param i an integer value between 0 and 65535. 406 * @return a byte array whose length is 2. 407 * @throws SAML2Exception if the input is not between 0 and 65535. 408 */ 409 public static byte[] intToTwoBytes(int i) 410 throws SAML2Exception { 411 if (i < 0 || i > 65535) { 412 debug.error("SAML2Utils.intToTwoBytes: wrong index value range."); 413 throw new SAML2Exception( 414 bundle.getString("wrongInput")); 415 } 416 417 String hexStr = Integer.toHexString(i); 418 419 //System.out.println("Original="+hexStr); 420 421 int len = hexStr.length(); 422 String norm = null; 423 if (len > 4) { 424 norm = hexStr.substring(0,4); 425 } else { 426 switch (len) { 427 case 1: 428 norm = "000"+hexStr; 429 break; 430 case 2: 431 norm = "00"+hexStr; 432 break; 433 case 3: 434 norm = "0"+hexStr; 435 break; 436 default: 437 norm = hexStr; 438 } 439 } 440 441 byte[] bytes = hexStringToByteArray(norm); 442 443 return bytes; 444 } 445 446 /** 447 * Converts two bytes to an integer. 448 * 449 * @param bytes byte array whose length is 2. 450 * @return an integer value between 0 and 65535. 451 * @throws SAML2Exception if the input is null or the length is not 2. 452 */ 453 public static int twoBytesToInt(byte[] bytes) 454 throws SAML2Exception { 455 if (bytes == null || bytes.length != 2) { 456 debug.error("SAML2Utils.twoBytesToInt: input is null or length is " 457 + "not 2."); 458 throw new SAML2Exception(bundle.getString("wrontInput")); 459 } 460 461 String str0 = Integer.toHexString(bytes[0]); 462 int len0 = str0.length(); 463 String norm0 = null; 464 if (len0 > 2) { 465 norm0 = str0.substring(len0-2, len0); 466 } else { 467 norm0 = str0; 468 } 469 String str1 = Integer.toHexString(bytes[1]); 470 int len1 = str1.length(); 471 String norm1 = null; 472 if (len1 > 2) { 473 norm1 = str1.substring(len1-2, len1); 474 } else if (len1 == 1) { 475 norm1 = "0"+str1; 476 } else { 477 norm1 = str1; 478 } 479 480 String wholeHexStr = norm0+norm1; 481 482 int i = Integer.parseInt(wholeHexStr, 16); 483 484 return i; 485 } 486 487 /** 488 * Generates message handle used in an <code>Artifact</code>. 489 * 490 * @return String format of 20-byte sequence identifying 491 * a message. 492 */ 493 public static String generateMessageHandle() { 494 if (random == null) { 495 return null; 496 } 497 byte bytes[] = new byte[SAML2Constants.ID_LENGTH]; 498 random.nextBytes(bytes); 499 return byteArrayToString(bytes); 500 } 501 502 /** 503 * Converts String to Byte Array. 504 * 505 * @param input String to be converted. 506 * @return result of the conversion. 507 */ 508 public static byte[] stringToByteArray(String input) { 509 char chars[] = input.toCharArray(); 510 byte bytes[] = new byte[chars.length]; 511 for (int i = 0; i < chars.length; i++) { 512 bytes[i] = (byte) chars[i]; 513 } 514 return bytes; 515 } 516 517 /** 518 * Converts byte array to <code>Hex</code> String. 519 * 520 * @param byteArray Byte Array to be converted. 521 * @return result of the conversion. 522 */ 523 public static String byteArrayToHexString(byte[] byteArray) { 524 int readBytes = byteArray.length; 525 StringBuffer hexData = new StringBuffer(); 526 int onebyte; 527 for (int i=0; i < readBytes; i++) { 528 onebyte = ((0x000000ff & byteArray[i]) | 0xffffff00); 529 hexData.append(Integer.toHexString(onebyte).substring(6)); 530 } 531 return hexData.toString(); 532 } 533 534 /** 535 * Converts <code>Hex</code> String to Byte Array. 536 * 537 * @param hexString <code>Hex</code> String to be converted. 538 * @return result of the conversion. 539 */ 540 public static byte[] hexStringToByteArray(String hexString) { 541 int read = hexString.length(); 542 byte[] byteArray = new byte[read/2]; 543 for (int i=0, j=0; i < read; i++, j++) { 544 String part = hexString.substring(i,i+2); 545 byteArray[j] = 546 new Short(Integer.toString(Integer.parseInt(part,16))). 547 byteValue(); 548 i++; 549 } 550 return byteArray; 551 } 552 553 /** 554 * Generates ID. 555 * @return ID value. 556 */ 557 public static String generateID() { 558 if (random == null) { 559 return null; 560 } 561 byte bytes[] = new byte[SAML2Constants.ID_LENGTH]; 562 random.nextBytes(bytes); 563 return (SAML2ID_PREFIX + byteArrayToHexString(bytes)); 564 } 565 566 /** 567 * Gets the Discovery bootstrap resource offering in an attribute 568 * statement. After a single sign-on with an Identity Provider, a service 569 * provider may get Discovery service esource Offerings through a SAML2 570 * assertion. This APIs helps in retrieving the resource offerings 571 * if the user has been authenticated through the SAML2 SSO. It will 572 * need to have a valid single sign on token (generated through the 573 * SAML2 SSO). 574 * 575 * @param request <code>HttpServletRequest</code> associated with a user 576 * session. 577 * @return <code>ResourceOffering</code> Discovery Resource Offering, 578 * null if there is any failure or if there is not one 579 */ 580 public static ResourceOffering getDiscoveryBootStrapResourceOffering( 581 HttpServletRequest request) { 582 583 if (request == null) { 584 if (debug.messageEnabled()) { 585 debug.message("SAML2Utils.getDiscoveryBootStrapResource" + 586 "Offerings: null Input params"); 587 } 588 return null; 589 } 590 try { 591 SessionProvider sessionProvider = SessionManager.getProvider(); 592 Object session = sessionProvider.getSession(request); 593 594 String[] roStr = sessionProvider.getProperty(session, 595 SAML2Constants.DISCOVERY_BOOTSTRAP_ATTRIBUTE_NAME); 596 if ((roStr == null) || (roStr.length == 0)) { 597 return null; 598 } 599 600 return new ResourceOffering( 601 XMLUtils.toDOMDocument(roStr[0], debug).getDocumentElement()); 602 603 } catch(Exception ex) { 604 debug.error("SAML2Utils.getDiscoveryBootStrapResourceOfferings: " + 605 " Exception while retrieving discovery boot strap info.", ex); 606 return null; 607 } 608 609 } 610 611 /** 612 * Gets the Discovery bootstrap credentials. 613 * After a single sign-on with an Identity Provider, a service 614 * provider may get Discovery bootstrap resource offerings and credentials 615 * through a SAML assertion. This APIs helps in retrieving the credentials 616 * if the user has been authenticated through the SAML2 SSO. It will 617 * need to have a valid single sign on token (generated through the 618 * SAML2 SSO). 619 * 620 * @param request <code>HttpServletRequest</code> associated with a user 621 * session. 622 * @return <code>List</code> of <code>SecurityAssertions</code>, 623 * null if there is any failure or if there is not one 624 */ 625 public static List getDiscoveryBootStrapCredentials( 626 HttpServletRequest request) { 627 628 if (request == null) { 629 if (debug.messageEnabled()) { 630 debug.message("SAML2Utils.getDiscoveryBootStrapCredentials: " + 631 " null Input params"); 632 } 633 return null; 634 } 635 try { 636 SessionProvider sessionProvider = SessionManager.getProvider(); 637 Object session = sessionProvider.getSession(request); 638 String[] credentials = sessionProvider.getProperty(session, 639 SAML2Constants.DISCOVERY_BOOTSTRAP_CREDENTIALS); 640 if ((credentials == null) || (credentials.length == 0)) { 641 return null; 642 } 643 644 List securityAssertions = new ArrayList(); 645 for(int i=0; i< credentials.length; i++) { 646 SecurityAssertion securityAssertion = new SecurityAssertion( 647 XMLUtils.toDOMDocument(credentials[i], debug) 648 .getDocumentElement()); 649 securityAssertions.add(securityAssertion); 650 } 651 return securityAssertions; 652 } catch(Exception ex) { 653 debug.error("SAML2Utils.getDiscoveryBootStrapCredentials: ", ex); 654 return null; 655 } 656 } 657 658 /** 659 * Creates <code>SOAPMessage</code> with the input XML String 660 * as message body. 661 * @param xmlString XML string to be put into <code>SOAPMessage</code> body. 662 * @return newly created <code>SOAPMessage</code>. 663 * @exception SOAPException if it cannot create the 664 * <code>SOAPMessage</code>. 665 */ 666 public static String createSOAPMessageString(String xmlString) 667 throws SOAPException, SAML2Exception { 668 StringBuffer sb = new StringBuffer(500); 669 if (debug.messageEnabled()) { 670 debug.message("SAML2Utils.createSOAPMessage: xmlstr = " + 671 xmlString); 672 } 673 sb.append("<").append(SAMLConstants.SOAP_ENV_PREFIX). 674 append(":Envelope").append(SAMLConstants.SPACE). 675 append("xmlns:").append(SAMLConstants.SOAP_ENV_PREFIX). 676 append("=\"").append(SAMLConstants.SOAP_URI).append("\">"). 677 append("<"). 678 append(SAMLConstants.SOAP_ENV_PREFIX).append(":Body>"). 679 append(xmlString). 680 append(SAMLConstants.START_END_ELEMENT). 681 append(SAMLConstants.SOAP_ENV_PREFIX). 682 append(":Body>"). 683 append(SAMLConstants.START_END_ELEMENT). 684 append(SAMLConstants.SOAP_ENV_PREFIX). 685 append(":Envelope>").append(SAMLConstants.NL); 686 687 if (debug.messageEnabled()) { 688 debug.message("SAML2Utils.createSOAPMessage: soap message = " + 689 sb.toString()); 690 } 691 return sb.toString(); 692 } 693 694 695 /** 696 * Fills in basic auth user and password inside the location URL 697 * if configuration is done properly 698 * @param config Either an SPSSOConfigElement object , an 699 * IDPSSOConfigElement object or PEPConfigElement. 700 * @param locationURL The original location URL which is to be 701 * inserted with user:password@ before the 702 * hostname part and after // 703 * @return The modified location URL with the basic auth user 704 * and password if configured properly 705 */ 706 public static String fillInBasicAuthInfo( 707 BaseConfigType config, 708 String locationURL) { 709 710 if (config == null) { 711 return locationURL; 712 } 713 Map map = SAML2MetaUtils.getAttributes(config); 714 List baoList = (List)map.get( 715 SAML2Constants.BASIC_AUTH_ON); 716 if (baoList == null || baoList.isEmpty()) { 717 return locationURL; 718 } 719 String on = (String)baoList.get(0); 720 if (on == null) { 721 return locationURL; 722 } 723 on = on.trim(); 724 if (on.length() == 0 || !on.equalsIgnoreCase("true")) { 725 return locationURL; 726 } 727 List ul = (List)map.get( 728 SAML2Constants.BASIC_AUTH_USER); 729 730 if (ul == null || ul.isEmpty()) { 731 return locationURL; 732 } 733 String u = (String) ul.get(0); 734 if (u == null) { 735 return locationURL; 736 } 737 u = u.trim(); 738 if (u.length() == 0) { 739 return locationURL; 740 } 741 List pl = (List)map.get( 742 SAML2Constants.BASIC_AUTH_PASSWD); 743 String p = null; 744 if (pl != null && !pl.isEmpty()) { 745 p = (String) pl.get(0); 746 } 747 if (p == null) { 748 p = ""; 749 } 750 751 String dp = SAMLUtilsCommon.decodePassword(p); 752 753 int index = locationURL.indexOf("//"); 754 return locationURL.substring(0, index+2) + 755 u + ":" + dp + "@" + 756 locationURL.substring(index+2); 757 } 758 759 /** 760 * Converts a value of XML boolean type to Boolean object. 761 * 762 * @param str a value of XML boolean type 763 * @return a Boolean object. 764 * @throws SAML2Exception if there is a syntax error 765 */ 766 public static Boolean StringToBoolean(String str) throws SAML2Exception { 767 if (str == null) { 768 return null; 769 } 770 771 if (str.equals("true") || str.equals("1")) { 772 return Boolean.TRUE; 773 } 774 775 if (str.equals("false") || str.equals("0")) { 776 return Boolean.FALSE; 777 } 778 779 throw new SAML2Exception(SAML2SDKUtils.bundle.getString( 780 "invalidXMLBooleanValue")); 781 } 782 783 /** 784 * Removes deployment URI from the pass down string. i.e. 785 * from "/opensso/ArtifactResolver/metaAlias/idp" to 786 * "/ArtifactResolver/metaAlias/idp". 787 * @param uri the URI string which the deployment uri is to be removed 788 * return string without deployment uri 789 */ 790 public static String removeDeployUri(String uri) { 791 if ((uri == null) || (uri.length() == 0)) { 792 return uri; 793 } 794 int loc = uri.indexOf("/", 1); 795 if (loc == -1) { 796 return null; 797 } else { 798 return uri.substring(loc); 799 } 800 } 801 802 /** 803 * Returns the boolean value as a <code>Boolean</code> object. 804 * 805 * @param value boolean value true or false. 806 * 807 */ 808 public static Boolean booleanValueOf(String value) { 809 return new Boolean("true".equalsIgnoreCase(value) || "1".equals(value)); 810 } 811 812 /** 813 * If enabled, decodes the provided XML element and prints it out to the decryption debug log. 814 * @param callerName String representing the name of the calling method. 815 * @param xmlElement String representing an XML document with decrypted 816 * data. 817 */ 818 public static void decodeXMLToDebugLog(String callerName, Element xmlElement) { 819 if (decryptDebug.messageEnabled() && isSAMLDecryptionDebugEnabled()) { 820 String xmlOutput = XMLUtils.print(xmlElement); 821 decryptDebug.message(callerName + "Decrypted xml element node:\n" + 822 ((xmlOutput != null) ? xmlOutput : "NULL")); 823 } 824 } 825 826 /** 827 * Tells whether SAML SP decryption debug mode is enabled. 828 * 829 * @return <code>true</code> if SAML decryption debug mode is enabled, or <code>false</code> otherwise or if the 830 * property is not found. 831 */ 832 public static boolean isSAMLDecryptionDebugEnabled() { 833 return SystemPropertiesManager.getAsBoolean(SAML2Constants.SAML_DECRYPTION_DEBUG_MODE); 834 } 835}