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: Assertion.java,v 1.3 2008/06/25 05:47:31 qcheng Exp $ 026 * 027 */ 028 029 030package com.sun.identity.saml.assertion; 031 032import com.sun.identity.shared.DateUtils; 033import com.sun.identity.saml.common.*; 034import com.sun.identity.saml.xmlsig.*; 035import com.sun.identity.common.SystemConfigurationUtil; 036import com.sun.identity.shared.xml.XMLUtils; 037import java.util.Set; 038import java.util.List; 039import java.util.Date; 040import java.text.ParseException; 041import org.w3c.dom.Node; 042import org.w3c.dom.NodeList; 043import org.w3c.dom.Element; 044import org.w3c.dom.Document; 045 046/** 047 *This object stands for <code>Assertion</code> element. An Assertion is a 048 *package of information that supplies one or more <code>Statement</code> made 049 *by an issuer. There are three kinds of assertionsL Authentication, 050 *AuthorizationDecision and Attribute assertion. 051 *@supported.all.api 052 */ 053public class Assertion extends AssertionBase { 054 055 /** 056 * Returns whether the signature on the object is valid or not. 057 * @return true if the signature on the object is valid; false otherwise. 058 */ 059 public boolean isSignatureValid() { 060 if (signed & ! validationDone) { 061 valid = SAMLUtils.checkSignatureValid( 062 xmlString, ASSERTION_ID_ATTRIBUTE, _issuer); 063 064 validationDone = true; 065 } 066 return valid; 067 } 068 069 /** 070 * Signs the Assertion. 071 * @exception SAMLException If it could not sign the Assertion. 072 */ 073 public void signXML() throws SAMLException { 074 String certAlias = 075 SystemConfigurationUtil.getProperty( 076 "com.sun.identity.saml.xmlsig.certalias"); 077 signXML(certAlias); 078 } 079 080 /** 081 * Signs the Assertion. 082 * 083 * @param certAlias certification Alias used to sign Assertion. 084 * @exception SAMLException if it could not sign the Assertion. 085 */ 086 public void signXML(String certAlias) throws SAMLException { 087 if (signed) { 088 if (SAMLUtils.debug.messageEnabled()) { 089 SAMLUtils.debug.message("Assertion.signXML: the assertion is " 090 + "already signed."); 091 } 092 throw new SAMLException( 093 SAMLUtils.bundle.getString("alreadySigned")); 094 } 095 096 if (certAlias == null) { 097 if (SAMLUtils.debug.messageEnabled()) { 098 SAMLUtils.debug.message("Assetion.signXML: couldn't obtain " 099 + "this site's cert alias."); 100 } 101 throw new SAMLResponderException( 102 SAMLUtils.bundle.getString("cannotFindCertAlias")); 103 } 104 105 XMLSignatureManager manager = XMLSignatureManager.getInstance(); 106 if ((_majorVersion == 1) && (_minorVersion == 0)) { 107 SAMLUtils.debug.message("Assetion.signXML: sign with version 1.0"); 108 signatureString = manager.signXML(this.toString(true, true), 109 certAlias); 110 // this block is used for later return of signature element by 111 // getSignature() method 112 signature = 113 XMLUtils.toDOMDocument(signatureString, SAMLUtils.debug) 114 .getDocumentElement(); 115 116 } else { 117 SAMLUtils.debug.message("Assetion.signXML: sign with version 1.1"); 118 Document doc = XMLUtils.toDOMDocument(this.toString(true, true), 119 SAMLUtils.debug); 120 // sign with SAML 1.1 spec & include cert in KeyInfo 121 signature = manager.signXML(doc, certAlias, null, 122 ASSERTION_ID_ATTRIBUTE, getAssertionID(), true, null); 123 signatureString = XMLUtils.print(signature); 124 } 125 signed = true; 126 xmlString = this.toString(true, true); 127 } 128 129 130 /** 131 *Default constructor 132 *Declaring protected to enable extensibility 133 */ 134 protected Assertion() { 135 super(); 136 } 137 138 /** 139 * Contructs <code>Assertion</code> object from a 140 * block of existing XML that has already been built into a DOM. 141 * 142 * @param assertionElement A <code>org.w3c.dom.Element</code> representing 143 * DOM tree for <code>Assertion</code> object 144 * @exception SAMLException if it could not process the Element properly, 145 * implying that there is an error in the sender or in the 146 * element definition. 147 */ 148 public Assertion(org.w3c.dom.Element assertionElement) 149 throws SAMLException 150 { 151 parseAssertionElement(assertionElement); 152 } 153 154 protected void parseAssertionElement(Element assertionElement) 155 throws SAMLException 156 { 157 if (SAMLUtils.debug.messageEnabled()) { 158 SAMLUtils.debug.message("Assertion.parseAssertionElement:"); 159 } 160 161 Element elt = (Element) assertionElement; 162 String eltName = elt.getLocalName(); 163 if (eltName == null) { 164 if (SAMLUtils.debug.messageEnabled()) { 165 SAMLUtils.debug.message("Assertion: local name missing"); 166 } 167 throw new SAMLRequesterException(SAMLUtils.bundle.getString 168 ("nullInput")) ; 169 } 170 if (!(eltName.equals("Assertion"))) { 171 if (SAMLUtils.debug.messageEnabled()) { 172 SAMLUtils.debug.message("Assertion: invalid root element"); 173 } 174 throw new SAMLRequesterException(SAMLUtils.bundle.getString 175 ("invalidElement")+ ":"+eltName) ; 176 } 177 178 String read = elt.getAttribute("Issuer"); 179 if ((read == null) || (read.length() == 0)) { 180 if (SAMLUtils.debug.messageEnabled()) { 181 SAMLUtils.debug.message("Assertion: Issuer missing"); 182 } 183 throw new SAMLRequesterException( 184 SAMLUtils.bundle.getString("missingAttribute") +":"+"Issuer"); 185 } else { 186 _issuer = read; 187 } 188 189 List signs = XMLUtils.getElementsByTagNameNS1(assertionElement, 190 SAMLConstants.XMLSIG_NAMESPACE_URI, 191 SAMLConstants.XMLSIG_ELEMENT_NAME); 192 int signsSize = signs.size(); 193 if (signsSize == 1) { 194 // delay the signature validation till user call isSignatureValid() 195 xmlString = XMLUtils.print(assertionElement); 196 signed = true; 197 validationDone = false; 198 } else if (signsSize != 0) { 199 if (SAMLUtils.debug.messageEnabled()) { 200 SAMLUtils.debug.message("Assertion(Element): included more than" 201 + " one Signature element."); 202 } 203 throw new SAMLRequesterException( 204 SAMLUtils.bundle.getString("moreElement")); 205 } 206 207 read = elt.getAttribute("MajorVersion"); 208 if ((read == null) || (read.length() == 0)) { 209 if (SAMLUtils.debug.messageEnabled()) { 210 SAMLUtils.debug.message("Assertion: MajorVersion missing"); 211 } 212 throw new SAMLRequesterException( 213 SAMLUtils.bundle.getString("missingAttribute")+":"+ 214 "MajorVersion"); 215 } 216 else { 217 int ver = 0; 218 try { 219 ver = Integer.parseInt(read); 220 } catch ( NumberFormatException ne ) { 221 SAMLUtils.debug.error( 222 "Assertion: invalid integer in MajorVersion", ne); 223 throw new SAMLRequesterException( 224 SAMLUtils.bundle.getString("invalidNumber")+":"+ 225 "MajorVersion"); 226 } 227 if (ver != sc.ASSERTION_MAJOR_VERSION) { 228 if (ver < sc.ASSERTION_MAJOR_VERSION) { 229 if (SAMLUtils.debug.messageEnabled()) { 230 SAMLUtils.debug.message( 231 "Assertion: MajorVersion too low"); 232 } 233 throw new SAMLVersionMismatchException( 234 SAMLUtils.bundle.getString("assertionVersionTooLow") 235 + ":"+"MajorVersion"); 236 } else if (ver > sc.ASSERTION_MAJOR_VERSION) { 237 if (SAMLUtils.debug.messageEnabled()) { 238 SAMLUtils.debug.message( 239 "Assertion: MajorVersion too high"); 240 } 241 throw new SAMLVersionMismatchException( 242 SAMLUtils.bundle.getString("assertionVersionTooHigh") 243 +":"+"MajorVersion"); 244 } 245 } 246 } 247 read = elt.getAttribute("MinorVersion"); 248 if ((read == null) || (read.length() == 0)) { 249 if (SAMLUtils.debug.messageEnabled()) 250 SAMLUtils.debug.message("Assertion: MinorVersion missing"); 251 throw new SAMLRequesterException( 252 SAMLUtils.bundle.getString("missingAttribute") 253 +":"+"MinorVersion"); 254 } 255 else { 256 int ver = 0; 257 try { 258 ver = Integer.parseInt(read); 259 } catch ( NumberFormatException ne ) { 260 SAMLUtils.debug.error( 261 "Assertion: invalid integer in MinorVersion", ne); 262 throw new SAMLRequesterException( 263 SAMLUtils.bundle.getString("invalidNumber") 264 +":"+"MinorVersion"); 265 } 266 267 if (SAMLUtils.debug.messageEnabled()) { 268 SAMLUtils.debug.message("Assertion.parseAssertionElement: " + 269 "minMinorVersion = " + getMinAssertionMinorVersion() + 270 ", maxMinorVersion = " + getMaxAssertionMinorVersion()); 271 } 272 273 if (ver < getMinAssertionMinorVersion()) { 274 if (SAMLUtils.debug.messageEnabled()) { 275 SAMLUtils.debug.message("Assertion: MinorVersion too low"); 276 } 277 throw new SAMLVersionMismatchException( 278 SAMLUtils.bundle.getString("assertionVersionTooLow")); 279 } else if (ver > getMaxAssertionMinorVersion()) { 280 if (SAMLUtils.debug.messageEnabled()) { 281 SAMLUtils.debug.message("Assertion: MinorVersion too high"); 282 } 283 throw new SAMLVersionMismatchException( 284 SAMLUtils.bundle.getString("assertionVersionTooHigh") 285 +":"+"MinorVersion"); 286 } else { 287 _minorVersion=ver; 288 } 289 } 290 read = elt.getAttribute("AssertionID"); 291 if ((read == null) || (read.length() == 0)) { 292 if (SAMLUtils.debug.messageEnabled()) 293 SAMLUtils.debug.message("Assertion: AssertionID missing"); 294 throw new SAMLRequesterException( 295 SAMLUtils.bundle.getString("missingAttribute") 296 +":"+"AssertionID"); 297 } 298 else { 299 _assertionID = new AssertionIDReference(read); 300 } 301 302 read = elt.getAttribute("IssueInstant"); 303 if ((read == null) || (read.length() == 0)) { 304 if (SAMLUtils.debug.messageEnabled()) { 305 SAMLUtils.debug.message("Assertion: IssueInstant missing"); 306 } 307 throw new SAMLRequesterException( 308 SAMLUtils.bundle.getString("missingAttribute") 309 +":"+"IssueInstant"); 310 } else { 311 try { 312 _issueInstant = DateUtils.stringToDate(read); 313 } catch (ParseException pe) { 314 if (SAMLUtils.debug.messageEnabled()) 315 SAMLUtils.debug.message( 316 "Assertion: could not parse IssueInstant", pe); 317 throw new SAMLRequesterException(SAMLUtils.bundle.getString( 318 "wrongInput") + " " + pe.getMessage()); 319 } 320 } 321 322 NodeList nl = assertionElement.getChildNodes(); 323 int length = nl.getLength(); 324 for (int n=0; n<length; n++) { 325 Node child = (Node)nl.item(n); 326 if (child.getNodeType() != Node.ELEMENT_NODE) continue; 327 String childName = child.getLocalName(); 328 if (childName.equals("Conditions")) 329 _conditions = new Conditions((Element)child); 330 else if (childName.equals("Advice")) 331 _advice = new Advice((Element)child); 332 else if (childName.equals("AuthenticationStatement")) { 333 _statements.add(new AuthenticationStatement((Element)child)); 334 } 335 else if (childName.equals("AuthorizationDecisionStatement")) { 336 _statements.add(new AuthorizationDecisionStatement( 337 (Element)child)); 338 } 339 else if (childName.equals("AttributeStatement")) { 340 _statements.add(new AttributeStatement((Element)child)); 341 } 342 else if (childName.equals("Signature")) { 343 signature = (Element) child; 344 } 345 else if (!processUnknownElement((Element)child)) { 346 if (SAMLUtils.debug.messageEnabled()) { 347 SAMLUtils.debug.message( 348 "Assertion: invalid element in Assertion"); 349 } 350 throw new SAMLRequesterException("invalidElement"); 351 } 352 } 353 if (_statements.isEmpty()) { 354 if (SAMLUtils.debug.messageEnabled()) { 355 SAMLUtils.debug.message( 356 "Assertion: mandatory statement missing"); 357 } 358 throw new SAMLRequesterException("missingStatement"); 359 } 360 } 361 362 363 /** 364 * Contructs <code>Assertion</code> object and populate the data members: 365 * <code>assertionID</code>, the issuer, time when assertion issued and a 366 * set of <code>Statement</code>(s) in the assertion. 367 * 368 * @param assertionID <code>assertionID</code> attribute contained within 369 * this <code>Assertion</code> if null, an <code>assertionID</code> 370 * is generated internally. 371 * @param issuer The issuer of this assertion. 372 * @param issueInstant time instant of the issue. It has type 373 * <code>dateTime</code> which is built in to the W3C XML Schema 374 * Types specification.if null, current time is used. 375 * @param statements set of <code>Statement</code> objects within this 376 * <code>Assertion</code>. It could be of type 377 * <code>AuthenticationStatement</code>, 378 * <code>AuthorizationDecisionStatement</code> and 379 * <code>AttributeStatement</code>. Each Assertion can have multiple 380 * type of statements in it. 381 * @exception SAMLException if there is an error in processing input. 382 */ 383 public Assertion(String assertionID,java.lang.String issuer, 384 Date issueInstant, Set statements) throws SAMLException 385 { 386 super(assertionID, issuer, issueInstant, statements); 387 } 388 389 /** 390 * Contructs <code>Assertion</code> object and populate the data members: 391 * the <code>assertionID</code>, the issuer, time when assertion issued, 392 * the conditions when creating a new assertion and a set of 393 * <code>Statement</code>(s) in the assertion. 394 * 395 * @param assertionID <code>AssertionID</code> contained within this 396 * <code>Assertion</code> if null its generated internally. 397 * @param issuer The issuer of this assertion. 398 * @param issueInstant time instant of the issue. It has type 399 * <code>dateTime</code> which is built in to the W3C XML Schema 400 * Types specification. if null, current time is used. 401 * @param conditions <code>Conditions</code> under which the this 402 * <code>Assertion</code> is valid. 403 * @param statements Set of <code>Statement</code> objects within this 404 * <code>Assertion</code>. It could be of type 405 * <code>AuthenticationStatement</code>, 406 * <code>AuthorizationDecisionStatement</code> and 407 * <code>AttributeStatement</code>. Each Assertion can have multiple 408 * type of statements in it. 409 * @exception SAMLException if there is an error in processing input. 410 */ 411 public Assertion(String assertionID,java.lang.String issuer, 412 Date issueInstant, Conditions conditions, Set statements) 413 throws SAMLException 414 { 415 super(assertionID, issuer, issueInstant, conditions, statements); 416 } 417 418 /** 419 * Contructs <code>Assertion</code> object and populate the data members: 420 * the <code>ssertionID</code>, the issuer, time when assertion issued, 421 * the conditions when creating a new assertion , <code>Advice</code> 422 * applicable to this <code>Assertion</code> and a set of 423 * <code>Statement</code>(s) in the assertion. 424 * 425 * @param assertionID <code>AssertionID</code> object contained within this 426 * <code>Assertion</code> if null its generated internally. 427 * @param issuer The issuer of this assertion. 428 * @param issueInstant Time instant of the issue. It has type 429 * <code>dateTime</code> which is built in to the W3C XML Schema 430 * Types specification. if null, current time is used. 431 * @param conditions <code>Conditions</code> under which the this 432 * <code>Assertion</code> is valid. 433 * @param advice <code>Advice</code> applicable for this 434 * <code>Assertion</code>. 435 * @param statements Set of <code>Statement</code> objects within this 436 * <code>Assertion</code>. It could be of type 437 * <code>AuthenticationStatement</code>, 438 * <code>AuthorizationDecisionStatement</code> and 439 * <code>AttributeStatement</code>. Each Assertion can have 440 * multiple type of statements in it. 441 * @exception SAMLException if there is an error in processing input. 442 */ 443 public Assertion(String assertionID,java.lang.String issuer, 444 Date issueInstant, Conditions conditions, Advice advice, 445 Set statements) throws SAMLException 446 { 447 super(assertionID, issuer, issueInstant, conditions, advice,statements); 448 } 449 450 /** 451 * Returns the advice of an assertion. 452 * 453 * @return <code>Advice</code> object containing advice information of the 454 * assertion. 455 */ 456 public Advice getAdvice() { 457 return (Advice)_advice; 458 } 459 460 protected AdviceBase createAdvice(Element adviceElement) 461 throws SAMLException { 462 return new Advice(adviceElement); 463 } 464 465 protected AuthorizationDecisionStatementBase 466 createAuthorizationDecisionStatement(Element authDecisionElement) 467 throws SAMLException { 468 return new AuthorizationDecisionStatement(authDecisionElement); 469 } 470 471 protected AuthenticationStatement 472 createAuthenticationStatement(Element authenticationElement) 473 throws SAMLException { 474 return new AuthenticationStatement(authenticationElement); 475 } 476 477 protected AttributeStatement 478 createAttributeStatement(Element attributeElement) 479 throws SAMLException { 480 return new AttributeStatement(attributeElement); 481 } 482 483 protected AssertionIDReference 484 createAssertionIDReference(Element assertionIDRefElement) 485 throws SAMLException { 486 return new AssertionIDReference(assertionIDRefElement); 487 } 488 489 protected AssertionIDReference 490 createAssertionIDReference(String assertionID) throws SAMLException { 491 return new AssertionIDReference(assertionID); 492 } 493 494 protected Conditions 495 createConditions(Element conditionsElement) throws SAMLException { 496 return new Conditions(conditionsElement); 497 } 498 499 protected boolean processUnknownElement(Element element) 500 throws SAMLException 501 { 502 if (SAMLUtils.debug.messageEnabled()) { 503 SAMLUtils.debug.message("Assertion.processUnknownElement:"); 504 } 505 return false; 506 } 507 508 protected int getMinAssertionMinorVersion() { 509 return sc.ASSERTION_MINOR_VERSION_ZERO; 510 } 511 512 protected int getMaxAssertionMinorVersion() { 513 return sc.ASSERTION_MINOR_VERSION_ONE; 514 } 515}