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: FSSAMLRequest.java,v 1.2 2008/06/25 05:46:45 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.federation.message; 030 031import java.text.ParseException; 032import java.util.List; 033import java.util.Collections; 034import java.util.ArrayList; 035 036import org.w3c.dom.Element; 037import org.w3c.dom.Node; 038import org.w3c.dom.NodeList; 039import com.sun.identity.shared.xml.XMLUtils; 040import com.sun.identity.shared.DateUtils; 041import com.sun.identity.saml.protocol.AssertionArtifact; 042import com.sun.identity.saml.protocol.Request; 043import com.sun.identity.saml.common.SAMLConstants; 044import com.sun.identity.saml.common.SAMLException; 045import com.sun.identity.saml.common.SAMLUtils; 046import com.sun.identity.saml.common.SAMLRequestVersionTooHighException; 047import com.sun.identity.saml.common.SAMLRequestVersionTooLowException; 048import com.sun.identity.saml.common.SAMLRequesterException; 049import com.sun.identity.saml.xmlsig.XMLSignatureManager; 050import com.sun.identity.federation.common.*; 051 052/** 053 * This class had methods to create a <code>SAML</code> Request 054 * object from a Document Element and to create Request message 055 * from this object. 056 * 057 * @supported.all.api 058 */ 059 060public class FSSAMLRequest extends Request { 061 062 /* 063 * Default Constructor. 064 */ 065 protected FSSAMLRequest() {} 066 067 /** 068 * Constructor creates <code>FSSAMLRequest</code> from 069 * the Document Element. 070 * 071 * @param root the Document Element. 072 * @throws SAMLException if there is an error creating this object. 073 */ 074 public FSSAMLRequest(Element root) throws SAMLException { 075 // Make sure this is a Request 076 String tag = null; 077 if (root == null) { 078 SAMLUtils.debug.message("FSSAMLRequest(Element): null input."); 079 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 080 "nullInput",null); 081 } 082 if (((tag = root.getLocalName()) == null) || 083 (!tag.equals("Request"))) { 084 SAMLUtils.debug.message("FSSAMLRequest(Element): wrong input"); 085 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 086 "wrongInput",null); 087 } 088 089 // Attribute MajorVersion 090 parseMajorVersion(root.getAttribute("MajorVersion")); 091 092 // Attribute MinorVersion 093 parseMinorVersion(root.getAttribute("MinorVersion")); 094 095 List signs = XMLUtils.getElementsByTagNameNS1(root, 096 SAMLConstants.XMLSIG_NAMESPACE_URI, 097 SAMLConstants.XMLSIG_ELEMENT_NAME); 098 int signsSize = signs.size(); 099 if (signsSize == 1) { 100 XMLSignatureManager manager = XMLSignatureManager.getInstance(); 101 if (minorVersion == 102 IFSConstants.FF_11_SAML_PROTOCOL_MINOR_VERSION) { 103 valid = manager.verifyXMLSignature(root); 104 } else { 105 valid = manager.verifyXMLSignature(root, 106 IFSConstants.REQUEST_ID, null); 107 } 108 if (!valid) { 109 if (SAMLUtils.debug.messageEnabled()) { 110 SAMLUtils.debug.message("FSSAMLRequest(Element): couldn't" 111 + " verify Request's signature."); 112 } 113 } 114 xmlString = XMLUtils.print(root); 115 signed = true; 116 } else if (signsSize != 0) { 117 if (SAMLUtils.debug.messageEnabled()) { 118 SAMLUtils.debug.message("FSSAMLRequest(Element): included more " 119 + "than one Signature element."); 120 } 121 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 122 "moreElement",null); 123 } 124 125 // Attribute RequestID 126 requestID = root.getAttribute("RequestID"); 127 if ((requestID == null) || (requestID.length() == 0)) { 128 if (SAMLUtils.debug.messageEnabled()) { 129 SAMLUtils.debug.message("FSSAMLRequest(Element): Request " 130 + "does not have a RequestID."); 131 } 132 String[] args = { IFSConstants.REQUEST_ID }; 133 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 134 "missingAttribute",args); 135 } 136 137 // Attribute IssueInstant 138 String instantString = root.getAttribute("IssueInstant"); 139 if ((instantString == null) || (instantString.length() == 0)) { 140 SAMLUtils.debug.message("FSSAMLRequest(Element): " 141 + " missing IssueInstant"); 142 String[] args = { IFSConstants.ISSUE_INSTANT }; 143 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 144 "missingAttribute",args); 145 } else { 146 try { 147 issueInstant = DateUtils.stringToDate(instantString); 148 } catch (ParseException e) { 149 SAMLUtils.debug.message( 150 "FSSAMLRequest(Element): could not parse IssueInstant", 151 e); 152 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 153 "wrongInput",null); 154 } 155 } 156 157 // get the contents of the request 158 NodeList contentnl = root.getChildNodes(); 159 Node child; 160 String nodeName; 161 String respondWith; 162 for (int i = 0, length = contentnl.getLength(); i < length; i++) { 163 child = contentnl.item(i); 164 if ((nodeName = child.getLocalName()) != null) { 165 if (nodeName.equals("RespondWith")) { 166 respondWith = XMLUtils.getElementValue((Element) child); 167 if (respondWith.length() == 0) { 168 if (SAMLUtils.debug.messageEnabled()) { 169 SAMLUtils.debug.message("FSSAMLRequest(Element): " 170 + "wrong RespondWith value."); 171 } 172 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 173 "wrongInput",null); 174 } 175 if (respondWiths == Collections.EMPTY_LIST) { 176 respondWiths = new ArrayList(); 177 } 178 respondWiths.add(respondWith); 179 } else if (nodeName.equals("Signature")) { 180 signature = (Element) child; 181 } else if (nodeName.equals("AssertionArtifact")) { 182 // make sure the content has no other elements assigned 183 if ((contentType != NOT_SUPPORTED) && 184 (contentType != ASSERTION_ARTIFACT)) { 185 if (SAMLUtils.debug.messageEnabled()) { 186 SAMLUtils.debug.message("FSSAMLRequest(Element): " 187 + "contained mixed contents."); 188 } 189 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 190 "wrongInput",null); 191 } 192 contentType = ASSERTION_ARTIFACT; 193 if (artifacts == Collections.EMPTY_LIST) { 194 artifacts = new ArrayList(); 195 } 196 try{ 197 AssertionArtifact newArt = new FSAssertionArtifact( 198 XMLUtils.getElementValue((Element) child)); 199 artifacts.add(newArt); 200 }catch (Exception e){ 201 SAMLUtils.debug.error("FSSAMLRequest(Element): ", e); 202 } 203 } else { 204 if (SAMLUtils.debug.messageEnabled()) { 205 SAMLUtils.debug.message("FSSAMLRequest(Element):invalid" 206 + " node" + nodeName); 207 } 208 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 209 "wrongInput",null); 210 } // check nodeName 211 } // if nodeName != null 212 } // done for the nodelist loop 213 214 if (contentType == NOT_SUPPORTED) { 215 SAMLUtils.debug.message("Request: empty content."); 216 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 217 "wrongInput",null); 218 } 219 } 220 221 222 /** 223 * Sets the <code>MajorVersion</code> by parsing the version string. 224 * 225 * @param majorVer a String representing the <code>MajorVersion</code> to 226 * be set. 227 * @throws SAMLException when the version mismatches. 228 */ 229 private void parseMajorVersion(String majorVer) throws SAMLException { 230 try { 231 majorVersion = Integer.parseInt(majorVer); 232 } catch (NumberFormatException e) { 233 if (SAMLUtils.debug.messageEnabled()) { 234 SAMLUtils.debug.message("FSSAMLRequest(Element): invalid " 235 + "MajorVersion", e); 236 } 237 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 238 "wrongInput",null); 239 } 240 241 if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) { 242 if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) { 243 if (SAMLUtils.debug.messageEnabled()) { 244 SAMLUtils.debug.message("FSSAMLRequest(Element): " 245 + "MajorVersion of the Request is too high."); 246 } 247 throw new SAMLRequestVersionTooHighException( 248 FSUtils.BUNDLE_NAME,"requestVersionTooHigh",null); 249 } else { 250 if (SAMLUtils.debug.messageEnabled()) { 251 SAMLUtils.debug.message("FSSAMLRequest(Element): " 252 + "MajorVersion of the Request is too low."); 253 } 254 throw new SAMLRequestVersionTooLowException(FSUtils.BUNDLE_NAME, 255 "requestVersionTooLow",null); 256 } 257 } 258 259 } 260 261 /** 262 * Sets the <code>MinorVersion</code> by parsing the version string. 263 * 264 * @param minorVer a String representing the <code>MinorVersion</code> to 265 * be set. 266 * @throws SAMLException when the version mismatches. 267 */ 268 private void parseMinorVersion(String minorVer) throws SAMLException { 269 try { 270 minorVersion = Integer.parseInt(minorVer); 271 } catch (NumberFormatException e) { 272 if (FSUtils.debug.messageEnabled()) { 273 FSUtils.debug.message("Request(Element): invalid " 274 + "MinorVersion", e); 275 } 276 throw new SAMLRequesterException(FSUtils.BUNDLE_NAME, 277 "wrongInput",null); 278 } 279 280 if(minorVersion > IFSConstants.FF_12_SAML_PROTOCOL_MINOR_VERSION) { 281 FSUtils.debug.error("Request(Element): MinorVersion" 282 + " of the Request is too high."); 283 throw new SAMLRequestVersionTooHighException(FSUtils.BUNDLE_NAME, 284 "requestVersionTooHigh",null); 285 } else if (minorVersion < 286 IFSConstants.FF_11_SAML_PROTOCOL_MINOR_VERSION) { 287 FSUtils.debug.error("Request(Element): MinorVersion" 288 + " of the Request is too low."); 289 throw new SAMLRequestVersionTooLowException(FSUtils.BUNDLE_NAME, 290 "requestVersionTooLow",null); 291 } 292 } 293 294 /** 295 * Returns the <code>MinorVersion</code> attribute. 296 * 297 * @return the Minor Version. 298 * @see #setMinorVersion(int) 299 */ 300 public int getMinorVersion() { 301 return minorVersion; 302 } 303 304 /** 305 * Sets the <code>MinorVersion</code>. 306 * 307 * @param version the minor version in the assertion. 308 * @see #setMinorVersion(int) 309 */ 310 public void setMinorVersion(int version) { 311 minorVersion = version; 312 } 313}