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: FSNameIdentifierMappingRequest.java,v 1.2 2008/06/25 05:46:44 qcheng Exp $ 026 * 027 * Portions Copyrighted 2014-2016 ForgeRock AS. 028 */ 029 030package com.sun.identity.federation.message; 031 032import static org.forgerock.openam.utils.Time.*; 033 034import com.sun.identity.shared.xml.XMLUtils; 035 036import com.sun.identity.shared.Constants; 037import com.sun.identity.shared.DateUtils; 038import com.sun.identity.common.SystemConfigurationUtil; 039 040import com.sun.identity.federation.common.FSUtils; 041import com.sun.identity.federation.common.IFSConstants; 042import com.sun.identity.federation.message.common.FSMsgException; 043 044import com.sun.identity.saml.assertion.NameIdentifier; 045import com.sun.identity.saml.common.SAMLConstants; 046import com.sun.identity.saml.common.SAMLUtils; 047import com.sun.identity.saml.common.SAMLException; 048import com.sun.identity.saml.common.SAMLResponderException; 049 050import com.sun.identity.saml.protocol.AbstractRequest; 051 052import com.sun.identity.saml.xmlsig.XMLSignatureManager; 053 054import java.util.Date; 055import java.util.List; 056 057import org.w3c.dom.Document; 058import org.w3c.dom.Element; 059import org.w3c.dom.Node; 060import org.w3c.dom.NodeList; 061 062/** 063 * The class <code>FSNameIdentifierMappingRequest</code> is used to 064 * create or parse <code>NameIdentifierMappingRequest<code>. 065 * 066 * @supported.all.api 067 * @deprecated since 12.0.0 068 */ 069@Deprecated 070public class FSNameIdentifierMappingRequest extends AbstractRequest { 071 072 private String providerID; 073 private NameIdentifier nameIdentifier; 074 private String targetNamespace; 075 private int minorVersion = IFSConstants.FF_12_PROTOCOL_MINOR_VERSION; 076 private String signatureString; 077 078 /** 079 * Constructor to create <code> FSNameIdentifierMappingRequest<code>. 080 * 081 * @param providerID the requesting provider's ID 082 * @param nameIdentifier the <code>NameIdentifier</code> qualified by the 083 * requesting service provider 084 * @param targetNamespace the provider ID of the other service provider 085 * which the requesting service provider would 086 * subsequently communicate with 087 * @throws FSMsgException if there is an error creating the object. 088 */ 089 public FSNameIdentifierMappingRequest(String providerID, 090 NameIdentifier nameIdentifier, String targetNamespace) 091 throws FSMsgException { 092 this.providerID = providerID; 093 this.nameIdentifier = nameIdentifier; 094 this.targetNamespace = targetNamespace; 095 this.requestID = SAMLUtils.generateID(); 096 setIssueInstant(newDate()); 097 } 098 099 /** 100 * Constructor to create <code> FSNameIdentifierMappingRequest<code> from 101 * the Document Element. 102 * 103 * @param root the <code>NameIdentifierMappingRequest</code> Document 104 * element. 105 * @throws FSMsgException if there is an error. 106 */ 107 public FSNameIdentifierMappingRequest(Element root) throws FSMsgException { 108 if (root == null) { 109 FSUtils.debug.message( 110 "FSNameIdentifierMappingRequest: null element input."); 111 throw new FSMsgException("nullInputParameter",null); 112 } 113 String tag = null; 114 if (((tag = root.getLocalName()) == null) || 115 (!tag.equals(IFSConstants.NAMEID_MAPPING_REQUEST))) { 116 FSUtils.debug.message( 117 "FSNameIdentifierMappingRequest: wrong input"); 118 throw new FSMsgException("wrongInput",null); 119 } 120 121 // get IssueInstant 122 String instantString = root.getAttribute(IFSConstants.ISSUE_INSTANT); 123 if (instantString==null || instantString.length()==0) { 124 FSUtils.debug.error("FSNameIdentifierMappingRequest: " + 125 "missing IssueInstant"); 126 String[] args = { IFSConstants.ISSUE_INSTANT }; 127 throw new FSMsgException("missingAttribute",args); 128 } else { 129 try { 130 issueInstant = DateUtils.stringToDate(instantString); 131 } catch (Exception e) { 132 FSUtils.debug.error("FSNameIdentifierMappingRequest: " + 133 "could not parse IssueInstant.", e); 134 throw new FSMsgException("wrongInput",null); 135 } 136 } 137 138 // get RequestID 139 requestID = root.getAttribute(IFSConstants.REQUEST_ID); 140 141 // get and check versions 142 parseMajorVersion(root.getAttribute(IFSConstants.MAJOR_VERSION)); 143 parseMinorVersion(root.getAttribute(IFSConstants.MINOR_VERSION)); 144 145 // get ProviderID, NameIdentifier & TargetNamespace 146 NodeList contentnl = root.getChildNodes(); 147 Node child; 148 String nodeName; 149 int length = contentnl.getLength(); 150 for (int i = 0; i < length; i++) { 151 child = contentnl.item(i); 152 if ((nodeName = child.getLocalName()) != null) { 153 if (nodeName.equals(IFSConstants.PROVIDER_ID)) { 154 providerID = XMLUtils.getElementValue((Element) child); 155 } else if (nodeName.equals(IFSConstants.NAME_IDENTIFIER)) { 156 try { 157 nameIdentifier = 158 new NameIdentifier((Element) child); 159 } catch (SAMLException samle) { 160 FSUtils.debug.error("FSNameIdentifierMappingRequest: " + 161 "unable to initialize NameIdentifier", samle); 162 throw new FSMsgException( 163 "nameIdentifierCreateError",null,samle); 164 } 165 } else if (nodeName.equals(IFSConstants.TARGET_NAME_SPACE)) { 166 targetNamespace = XMLUtils.getElementValue((Element) child); 167 } 168 } 169 } 170 171 // get signature 172 List signs = XMLUtils.getElementsByTagNameNS1( 173 root, 174 SAMLConstants.XMLSIG_NAMESPACE_URI, 175 SAMLConstants.XMLSIG_ELEMENT_NAME); 176 int signsSize = signs.size(); 177 if (signsSize == 1) { 178 Element elem = (Element)signs.get(0); 179 setSignature(elem); 180 signed = true; 181 } else if (signsSize != 0) { 182 FSUtils.debug.error("FSNameIdentifierMappingRequest: " + 183 "included more than one Signature element."); 184 throw new FSMsgException("moreElement",null); 185 } 186 } 187 188 /** 189 * Returns <code>FSNameIdentifierMappingRequest</code> object. This 190 * object is created by parsing the <code>XML</code> string. 191 * 192 * @param xml <code>XML</code> String 193 * @return the <code>FSNameIdentifierMappingRequest</code> object. 194 * @throws FSMsgException if there is an error creating this object. 195 */ 196 public static FSNameIdentifierMappingRequest parseXML(String xml) 197 throws FSMsgException { 198 Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug); 199 if (doc == null) { 200 FSUtils.debug.error("FSNameIdentifierMappingRequest.parseXML: " + 201 "error while parsing input xml string"); 202 throw new FSMsgException("parseError",null); 203 } 204 Element root = doc.getDocumentElement(); 205 return new FSNameIdentifierMappingRequest(root); 206 } 207 208 /** 209 * Returns the <code>ProviderID</code> attribute. This 210 * is the requesting Service Providers's identifier. 211 * 212 * @return the <code>ProviderID</code> attribute. 213 */ 214 public String getProviderID() { 215 return providerID; 216 } 217 218 /** 219 * Returns the <code>NameIdentifier</code> object qualified by the 220 * requesting service provider . 221 * 222 * @return the <code>NameIdentifier</code> object qualified by the 223 * requesting service provider . 224 */ 225 public NameIdentifier getNameIdentifier() { 226 return nameIdentifier; 227 } 228 229 /** 230 * Returns the value of <code>TargetNamespace</code> attribute. 231 * 232 * @return the value of <code>TargetNamespace</code> attribute. 233 */ 234 public String getTargetNamespace() { 235 return targetNamespace; 236 } 237 238 /** 239 * Sets the <code>MajorVersion</code> by parsing the version string. 240 * 241 * @param majorVer a String representing the <code>MajorVersion</code> to 242 * be set. 243 * @throws FSMsgException when the version mismatches. 244 */ 245 private void parseMajorVersion(String version) throws FSMsgException { 246 try { 247 majorVersion = Integer.parseInt(version); 248 } catch (NumberFormatException e) { 249 if (FSUtils.debug.messageEnabled()) { 250 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 251 "parseMajorVersion: invalid MajorVersion: " + version, e); 252 } 253 throw new FSMsgException("wrongInput",null); 254 } 255 256 if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) { 257 if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) { 258 if (FSUtils.debug.messageEnabled()) { 259 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 260 "parseMajorVersion: MajorVersion is too high"); 261 } 262 throw new FSMsgException("requestVersionTooHigh",null); 263 } else { 264 if (FSUtils.debug.messageEnabled()) { 265 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 266 "parseMajorVersion: MajorVersion is too low"); 267 } 268 throw new FSMsgException("requestVersionTooLow",null); 269 } 270 } 271 } 272 273 /** 274 * Sets the <code>MinorVersion</code> by parsing the version string. 275 * 276 * @param minorVer a String representing the <code>MinorVersion</code> to 277 * be set. 278 * @throws FSMsgException when the version mismatches. 279 */ 280 private void parseMinorVersion(String version) throws FSMsgException { 281 try { 282 minorVersion = Integer.parseInt(version); 283 } catch (NumberFormatException e) { 284 if (FSUtils.debug.messageEnabled()) { 285 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 286 "parseMinorVersion: invalid MinorVersion: " + version, e); 287 } 288 throw new FSMsgException("wrongInput",null); 289 } 290 291 if (minorVersion > IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 292 if (FSUtils.debug.messageEnabled()) { 293 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 294 "parseMinorVersion: MinorVersion is too high"); 295 } 296 throw new FSMsgException("requestVersionTooHigh",null); 297 } else if (minorVersion < IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) { 298 if (FSUtils.debug.messageEnabled()) { 299 FSUtils.debug.message("FSNameIdentifierMappingRequest." + 300 "parseMinorVersion: MinorVersion is too low"); 301 } 302 throw new FSMsgException("requestVersionTooLow",null); 303 } 304 } 305 306 /** 307 * Signs the XML document representing 308 * <code>NameIdentifierMappingRequest</code> using the certificate 309 * indicated by the property "com.sun.identity.saml.xmlsig.certalias" 310 * in AMConfig.properties file. 311 * 312 * @throws SAMLException if there is an error signing the XML document. 313 */ 314 public void signXML() throws SAMLException { 315 String certAlias = SystemConfigurationUtil.getProperty( 316 Constants.SAML_XMLSIG_CERT_ALIAS); 317 signXML(certAlias); 318 } 319 320 /** 321 * Signs the XML document representing 322 * <code>NameIdentifierMappingRequest</code> using the specified 323 * certificate. 324 * 325 * @param certAlias the alias (name) of the certificate used for signing 326 * the XML document 327 * @throws SAMLException it there is an error. 328 */ 329 public void signXML(String certAlias) throws SAMLException { 330 FSUtils.debug.message("FSNameIdentifierMappingRequest.signXML"); 331 if (signed) { 332 if (FSUtils.debug.messageEnabled()) { 333 FSUtils.debug.message("FSNameIdentifierMappingRequest.signXML: " 334 + "the request is already signed."); 335 } 336 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 337 "alreadySigned",null); 338 } 339 if (certAlias==null || certAlias.length()==0) { 340 if (FSUtils.debug.messageEnabled()) { 341 FSUtils.debug.message("FSNameIdentifierMappingRequest.signXML: " 342 + "null certAlias"); 343 } 344 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 345 "cannotFindCertAlias",null); 346 } 347 try { 348 XMLSignatureManager manager = XMLSignatureManager.getInstance(); 349 signatureString = manager.signXML(this.toXMLString(true, true), 350 certAlias, (String) null, IFSConstants.REQUEST_ID, 351 this.getRequestID(), false); 352 signature = XMLUtils.toDOMDocument(signatureString, FSUtils.debug) 353 .getDocumentElement(); 354 signed = true; 355 } catch (Exception e){ 356 FSUtils.debug.error("FSNameIdentifierMappingRequest.signXML: " + 357 "unable to sign", e); 358 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 359 "signFailed",null); 360 361 } 362 } 363 364 /** 365 * Returns the string representation of this object. 366 * This method translates the response to an XML document string. 367 * 368 * @return An XML String representing the response. NOTE: this is a 369 * complete SAML response xml string with ResponseID, 370 * MajorVersion, etc. 371 */ 372 373 public String toXMLString() throws FSMsgException { 374 return toXMLString(true, true); 375 } 376 377 /** 378 * Returns the string representation of this object. 379 * 380 * @return An XML String representing the response. 381 * @throws FSMsgException if there is an error converting 382 * this object ot a string. 383 */ 384 public String toXMLString(boolean includeNS, boolean declareNS) 385 throws FSMsgException { 386 return toXMLString(includeNS, declareNS, false); 387 } 388 389 /** 390 * Returns a String representation of the <samlp:Response> element. 391 * 392 * @param includeNS Determines whether or not the namespace qualifier 393 * is prepended to the Element when converted 394 * @param declareNS Determines whether or not the namespace is declared 395 * within the Element. 396 * @param includeHeader Determines whether the output include the xml 397 * declaration header. 398 * @return a string containing the valid XML for this element 399 * @throws FSMsgException if there is an error converting 400 * this object ot a string. 401 */ 402 public String toXMLString(boolean includeNS, boolean declareNS, 403 boolean includeHeader) throws FSMsgException { 404 405 String prefix = ""; 406 String uriLIB = ""; 407 String uriSAML = ""; 408 if (includeNS) { 409 prefix = IFSConstants.LIB_PREFIX; 410 } 411 if (declareNS) { 412 uriLIB = IFSConstants.LIB_12_NAMESPACE_STRING; 413 uriSAML = IFSConstants.assertionDeclareStr; 414 } 415 String instantString = null; 416 try { 417 instantString = DateUtils.toUTCDateFormat(issueInstant); 418 } catch (Exception e) { 419 FSUtils.debug.error("FSNameIdentifierMappingRequest.toXMLString: " + 420 "could not convert issueInstant to String.", e); 421 } 422 423 // construct xml request 424 StringBuffer xml = new StringBuffer(1000); 425 if (includeHeader) { 426 xml.append(IFSConstants.XML_PREFIX) 427 .append(IFSConstants.DEFAULT_ENCODING) 428 .append(IFSConstants.QUOTE) 429 .append(IFSConstants.SPACE) 430 .append(IFSConstants.QUESTION_MARK) 431 .append(IFSConstants.RIGHT_ANGLE) 432 .append(IFSConstants.NL); 433 } 434 xml.append(IFSConstants.LEFT_ANGLE) 435 .append(prefix) 436 .append(IFSConstants.NAMEID_MAPPING_REQUEST) 437 .append(uriLIB).append(uriSAML) 438 .append(IFSConstants.SPACE) 439 .append(IFSConstants.REQUEST_ID) 440 .append(IFSConstants.EQUAL_TO) 441 .append(IFSConstants.QUOTE) 442 .append(requestID) 443 .append(IFSConstants.QUOTE) 444 .append(IFSConstants.SPACE) 445 .append(IFSConstants.SPACE) 446 .append(IFSConstants.MAJOR_VERSION) 447 .append(IFSConstants.EQUAL_TO) 448 .append(IFSConstants.QUOTE) 449 .append(majorVersion) 450 .append(IFSConstants.QUOTE) 451 .append(IFSConstants.SPACE) 452 .append(IFSConstants.SPACE) 453 .append(IFSConstants.MINOR_VERSION) 454 .append(IFSConstants.EQUAL_TO) 455 .append(IFSConstants.QUOTE) 456 .append(minorVersion) 457 .append(IFSConstants.QUOTE) 458 .append(IFSConstants.SPACE) 459 .append(IFSConstants.SPACE) 460 .append(IFSConstants.ISSUE_INSTANT) 461 .append(IFSConstants.EQUAL_TO) 462 .append(IFSConstants.QUOTE) 463 .append(instantString) 464 .append(IFSConstants.QUOTE) 465 .append(IFSConstants.SPACE) 466 .append(IFSConstants.RIGHT_ANGLE); 467 468 if (signed) { 469 if (signatureString != null) { 470 xml.append(signatureString); 471 } else if (signature != null) { 472 signatureString = XMLUtils.print(signature); 473 xml.append(signatureString); 474 } 475 } 476 xml.append(IFSConstants.LEFT_ANGLE) 477 .append(prefix) 478 .append(IFSConstants.PROVIDER_ID) 479 .append(IFSConstants.RIGHT_ANGLE) 480 .append(providerID) 481 .append(IFSConstants.START_END_ELEMENT) 482 .append(prefix) 483 .append(IFSConstants.PROVIDER_ID) 484 .append(IFSConstants.RIGHT_ANGLE); 485 486 if (nameIdentifier != null) { 487 xml.append(nameIdentifier.toString()); 488 } 489 490 xml.append(IFSConstants.LEFT_ANGLE) 491 .append(prefix) 492 .append(IFSConstants.TARGET_NAME_SPACE) 493 .append(IFSConstants.RIGHT_ANGLE) 494 .append(targetNamespace) 495 .append(IFSConstants.START_END_ELEMENT) 496 .append(prefix) 497 .append(IFSConstants.TARGET_NAME_SPACE) 498 .append(IFSConstants.RIGHT_ANGLE) 499 .append(IFSConstants.START_END_ELEMENT) 500 .append(prefix) 501 .append(IFSConstants.NAMEID_MAPPING_REQUEST) 502 .append(IFSConstants.RIGHT_ANGLE); 503 504 return xml.toString(); 505 } 506}