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: FSAuthnResponseEnvelope.java,v 1.2 2008/06/25 05:46:43 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.federation.message; 030 031import com.sun.identity.federation.common.FSUtils; 032import com.sun.identity.federation.common.IFSConstants; 033import com.sun.identity.federation.message.common.FSMsgException; 034import com.sun.identity.saml.common.SAMLUtils; 035import com.sun.identity.saml.common.SAMLException; 036import com.sun.identity.shared.encode.Base64; 037import com.sun.identity.shared.xml.XMLUtils; 038import java.io.ByteArrayInputStream; 039import java.io.IOException; 040import java.util.List; 041import org.w3c.dom.Element; 042import org.w3c.dom.Node; 043import org.w3c.dom.NodeList; 044import org.w3c.dom.Document; 045 046/** 047 * This class defines methods for setting and retrieving attributes and 048 * elements associated with a Liberty Response . 049 * 050 * @supported.all.api 051 */ 052 053public class FSAuthnResponseEnvelope { 054 private List otherElements; 055 private FSAuthnResponse authnResponse; 056 private String assertionConsumerServiceURL = null; 057 private int minorVersion = IFSConstants.FF_11_PROTOCOL_MINOR_VERSION; 058 059 /** 060 * Default Constructor. 061 */ 062 public FSAuthnResponseEnvelope() { 063 } 064 065 /** 066 * Constructor create <code>FSAuthnResponseEnvelope</code> object. 067 * 068 * @param authnResponse the <code>FSAuthnResponse</code> object. 069 */ 070 public FSAuthnResponseEnvelope(FSAuthnResponse authnResponse) { 071 this.authnResponse = authnResponse; 072 this.otherElements = null; 073 } 074 075 /** 076 * Constructor create <code>FSAuthnResponseEnvelope</code> object. 077 * 078 * @param root the Document element . 079 * @throws FSMsgException if there is an error creating the object. 080 * @throws SAMLException if there is an error creating the object. 081 */ 082 public FSAuthnResponseEnvelope(Element root) 083 throws FSMsgException, SAMLException { 084 if (root == null) { 085 FSUtils.debug.message("FSAuthnResponseEnvelope.parseXML: " 086 + "null input."); 087 throw new FSMsgException("nullInput",null); 088 } 089 String tag = null; 090 if (((tag = root.getLocalName()) == null) || 091 (!tag.equals(IFSConstants.AUTHN_RESPONSE_ENVELOPE))) { 092 FSUtils.debug.message("FSAuthnResponseEnvelope.parseXML: " 093 + "wrong input."); 094 throw new FSMsgException("wrongInput",null); 095 } 096 String ns = root.getNamespaceURI(); 097 if (ns == null) { 098 FSUtils.debug.error("FSAuthnResponseEnvelope(Element):" 099 + "No namespace"); 100 throw new FSMsgException("wrongInput",null); 101 } 102 103 if (ns.equals(IFSConstants.FF_12_XML_NS)) { 104 minorVersion = IFSConstants.FF_12_PROTOCOL_MINOR_VERSION; 105 } 106 NodeList nl = root.getChildNodes(); 107 Node child; 108 String childName; 109 int length = nl.getLength(); 110 for (int i = 0; i < length; i++) { 111 child = nl.item(i); 112 if ((childName = child.getLocalName()) != null) { 113 if (childName.equals(IFSConstants.AUTHN_RESPONSE)) { 114 if (authnResponse != null) { 115 if (FSUtils.debug.messageEnabled()) { 116 FSUtils.debug.message("FSAuthnResponseEnvelope: " 117 + "included more than one <AuthnResponse>"); 118 } 119 throw new FSMsgException("moreElement",null); 120 } 121 authnResponse = new FSAuthnResponse((Element) child); 122 } else if (childName.equals( 123 IFSConstants.ASSERTION_CONSUMER_SERVICE_URL)) { 124 assertionConsumerServiceURL = 125 XMLUtils.getElementValue((Element) child); 126 } 127 } 128 } 129 } 130 131 /** 132 * Returns the value of <code>MinorVersion</code> attribute. 133 * 134 * @return the value of <code>MinorVersion</code> attribute. 135 * @see #setMinorVersion(int) 136 */ 137 public int getMinorVersion() { 138 return minorVersion; 139 } 140 141 /** 142 * Sets the value of <code>MinorVersion<code> attribute. 143 * 144 * @param minorVersion the <code>MinorVersion</code> attribute. 145 */ 146 public void setMinorVersion(int minorVersion) { 147 this.minorVersion = minorVersion; 148 } 149 150 /** 151 * Returns a list of elements. 152 * 153 * @return list of elements. 154 * @see #setOtherElements(List) 155 */ 156 public List getOtherElements() { 157 return otherElements; 158 } 159 /** 160 * Sets a list of elements. 161 * 162 * @param otherElement a list of elements. 163 * @see #getOtherElements 164 */ 165 public void setOtherElements(List otherElement) { 166 this.otherElements = otherElement; 167 } 168 169 /** 170 * Returns the <code>FSAuthnResponse</code> object. 171 * 172 * @return the <code>FSAuthnResponse</code> object. 173 * @see #setAuthnResponse(FSAuthnResponse) 174 */ 175 176 public FSAuthnResponse getAuthnResponse() { 177 return authnResponse; 178 } 179 180 /** 181 * Sets the <code>FSAuthnResponse</code> object. 182 * 183 * @param authnResponse the <code>FSAuthnResponse</code> object. 184 * @see #getAuthnResponse 185 */ 186 187 public void setAuthnResponse(FSAuthnResponse authnResponse) { 188 this.authnResponse = authnResponse; 189 } 190 191 /** 192 * Returns the Assertion Consumer Service URL. 193 * 194 * @return the Assertion Consumer Service URL. 195 * @see #setAssertionConsumerServiceURL(String) 196 */ 197 public String getAssertionConsumerServiceURL() { 198 return assertionConsumerServiceURL; 199 } 200 /** 201 * Sets the Assertion Consumer Service URL. 202 * 203 * @param assertionConsumerUrl the Assertion Consumer Service Identifier. 204 * @see #getAssertionConsumerServiceURL 205 */ 206 public void setAssertionConsumerServiceURL(String assertionConsumerUrl) { 207 this.assertionConsumerServiceURL = assertionConsumerUrl; 208 } 209 210 /** 211 * Returns the <code>FSAuthnResponseEnvelope</code> object. 212 * 213 * @param xml the XML string to create this object from 214 * @return <code>FSAuthnResponseEnvelope</code> object. 215 * @throws FSMsgException if there is error creating the object. 216 */ 217 public static FSAuthnResponseEnvelope parseXML(String xml) 218 throws FSMsgException { 219 try { 220 Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug); 221 Element root = doc.getDocumentElement(); 222 return new FSAuthnResponseEnvelope(root); 223 } catch(SAMLException ex){ 224 if (FSUtils.debug.messageEnabled()) { 225 FSUtils.debug.message("FSAuthnResponseEnvelope.parseXML: " 226 + "Error while parsing input xml string"); 227 } 228 throw new FSMsgException("parseError",null); 229 } 230 } 231 /** 232 * Returns XML document String for this object based on the Response Schema. 233 * 234 * @return XML String representing the <code>Response</code> 235 * @throws FSMsgException if there is an error. 236 */ 237 public String toXMLString() throws FSMsgException { 238 return toXMLString(true, true); 239 } 240 241 /** 242 * Creates a String representation of the <code>Response<code> object. 243 * @param includeNS : Determines whether or not the namespace qualifier 244 * is prepended to the Element when converted 245 * @param declareNS : Determines whether or not the namespace is declared 246 * within the Element. 247 * @return A string containing the valid XML for this element. 248 * @throws FSMsgException if there is an error. 249 */ 250 public String toXMLString(boolean includeNS, boolean declareNS) 251 throws FSMsgException { 252 return toXMLString(includeNS, declareNS, false); 253 } 254 255 /** 256 * Creates a String representation of the <code>Response</code> object. 257 * 258 * @param includeNS Determines whether or not the namespace qualifier 259 * is prepended to the Element when converted 260 * @param declareNS Determines whether or not the namespace is declared 261 * within the Element. 262 * @param includeHeader Determines whether the output include the xml 263 * declaration header. 264 * @return a string containing the valid XML for this object. 265 * @throws FSMsgException if there is an error. 266 */ 267 public String toXMLString(boolean includeNS, 268 boolean declareNS, 269 boolean includeHeader) throws FSMsgException { 270 271 StringBuffer xml = new StringBuffer(300); 272 if (includeHeader) { 273 xml.append(IFSConstants.XML_PREFIX) 274 .append(IFSConstants.DEFAULT_ENCODING) 275 .append(IFSConstants.QUOTE) 276 .append(IFSConstants.SPACE) 277 .append(IFSConstants.QUESTION_MARK) 278 .append(IFSConstants.RIGHT_ANGLE); 279 } 280 String prefix = ""; 281 String uri = ""; 282 if (includeNS) { 283 prefix = IFSConstants.LIB_PREFIX; 284 } 285 if (declareNS) { 286 if (minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 287 uri = IFSConstants.LIB_12_NAMESPACE_STRING; 288 } else { 289 uri = IFSConstants.LIB_NAMESPACE_STRING; 290 } 291 } 292 xml.append(IFSConstants.LEFT_ANGLE) 293 .append(prefix) 294 .append(IFSConstants.AUTHN_RESPONSE_ENVELOPE) 295 .append(uri) 296 .append(IFSConstants.RIGHT_ANGLE); 297 298 if (authnResponse != null) { 299 xml.append(authnResponse.toXMLString()); 300 } 301 302 if(assertionConsumerServiceURL != null && 303 assertionConsumerServiceURL.length() != 0) { 304 xml.append(IFSConstants.LEFT_ANGLE) 305 .append(prefix) 306 .append(IFSConstants.ASSERTION_CONSUMER_SERVICE_URL) 307 .append(uri) 308 .append(IFSConstants.RIGHT_ANGLE) 309 .append(assertionConsumerServiceURL) 310 .append(IFSConstants.START_END_ELEMENT) 311 .append(prefix) 312 .append(IFSConstants.ASSERTION_CONSUMER_SERVICE_URL) 313 .append(IFSConstants.RIGHT_ANGLE); 314 } else { 315 throw new FSMsgException("nullInput",null); 316 } 317 xml.append(IFSConstants.START_END_ELEMENT) 318 .append(prefix) 319 .append(IFSConstants.AUTHN_RESPONSE_ENVELOPE); 320 321 return xml.toString(); 322 } 323 324 /** 325 * Returns a <code>Base64</code> Encoded String. 326 * 327 * @return a <code>Base64</code> Encoded String. 328 * @throws FSMsgException if there is an error encoding 329 * the string. 330 */ 331 public String toBASE64EncodedString() throws FSMsgException { 332 return Base64.encode(this.toXMLString().getBytes()); 333 } 334 335 /** 336 * Returns <code>FSAuthnResponseEnvelope</code> object. The 337 * object is creating by parsing the <code>Base64</code> 338 * encoded <code>XML</code> string. 339 * 340 * @param encodedReq the <code>Based64</code> encoded <code>XML</code> 341 * string. 342 * @throws FSMsgException if there is an error 343 * creating <code>FSAuthnResponseEnvelope</code> object. 344 */ 345 public static FSAuthnResponseEnvelope parseBASE64EncodedString( 346 String encodedReq) throws FSMsgException { 347 if (encodedReq != null) { 348 String decodedAuthnReq = new String(Base64.decode(encodedReq)); 349 if (FSUtils.debug.messageEnabled()) { 350 FSUtils.debug.message("FSAuthnResponseEnvelope." 351 + "parseBASE64EncodedString: decoded input string: \n" 352 + decodedAuthnReq); 353 } 354 return parseXML(decodedAuthnReq); 355 } else { 356 if (FSUtils.debug.messageEnabled()) { 357 FSUtils.debug.message("FSAuthnResponseEnvelope." 358 + "parseBASE64EncodedString: null String passed" 359 + "in as argument."); 360 } 361 throw new FSMsgException("nullInput",null); 362 } 363 } 364}