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: XACMLAuthzDecisionQueryImpl.java,v 1.4 2008/06/25 05:48:15 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.xacml.saml2.impl; 030 031import com.sun.identity.saml2.assertion.AssertionFactory; 032import com.sun.identity.saml2.common.SAML2Exception; 033import com.sun.identity.saml2.protocol.impl.RequestAbstractImpl; 034import com.sun.identity.saml2.protocol.ProtocolFactory; 035import com.sun.identity.shared.xml.XMLUtils; 036import com.sun.identity.shared.DateUtils; 037import com.sun.identity.xacml.common.XACMLException; 038import com.sun.identity.xacml.common.XACMLConstants; 039import com.sun.identity.xacml.common.XACMLSDKUtils; 040import com.sun.identity.xacml.context.Request; 041import com.sun.identity.xacml.saml2.XACMLAuthzDecisionQuery; 042import com.sun.identity.xacml.context.ContextFactory; 043import org.w3c.dom.Attr; 044import org.w3c.dom.Document; 045import org.w3c.dom.Element; 046import org.w3c.dom.NamedNodeMap; 047import org.w3c.dom.Node; 048import org.w3c.dom.NodeList; 049import java.text.ParseException; 050 051/** 052 * The <code>XACMLAuthzDecisionQueryImpl</code> is an impelmentation 053 * of <code>XACMLAuthzDecisionQuery</code> interface. 054 * 055 * The <code>XACMLAuthzDecisionQuery</code> element is a SAML Query that 056 * extends SAML Protocol schema type <code>RequestAbstractType</code>. 057 * It allows an XACML PEP to submit an XACML Request Context in a SAML 058 * Query along with other information. This element is an alternative to 059 * SAML defined <code><samlp:AuthzDecisionQuery></code> that allows an 060 * XACML PEP to communicate with an XACML PDP using SAML2 protocol. 061 * <p> 062 * <pre> 063 *<xs:element name="XACMLAuthzDecisionQuery" 064 * type="XACMLAuthzDecisionQueryType"/> 065 *<xs:complexType name="XACMLAuthzDecisionQueryType"> 066 * <xs:complexContent> 067 * <xs:extension base="samlp:RequestAbstractType"> 068 * <xs:sequence> 069 * <xs:element ref="xacml-context:Request"/> 070 * <xs:sequence> 071 * <xs:attribute name="InputContextOnly" 072 * type="boolean" 073 * use="optional" 074 * default="false"/> 075 * <xs:attribute name="ReturnContext" 076 * type="boolean" 077 * use="optional" 078 * default="false"/> 079 * <xs:extension> 080 * <xs:complexContent> 081 *<xs:complexType> 082 * </pre> 083 * 084 * Schema for Base: 085 * <pre> 086 * <complexType name="RequestAbstractType" abstract="true"> 087 * <sequence> 088 * <element ref="saml:Issuer" minOccurs="0"/> 089 * <element ref="ds:Signature" minOccurs="0"/> 090 * <element ref="samlp:Extensions" minOccurs="0"/> 091 * <sequence> 092 * <attribute name="ID" type="ID" use="required"/> 093 * <attribute name="Version" type="string" use="required"/> 094 * <attribute name="IssueInstant" type="dateTime" use="required"/> 095 * <attribute name="Destination" type="anyURI" use="optional"/> 096 * <attribute name="Consent" type="anyURI" use="optional"/> 097 * <complexType> 098 * </pre> 099 *@supported.all.api 100 */ 101public class XACMLAuthzDecisionQueryImpl extends RequestAbstractImpl 102 implements XACMLAuthzDecisionQuery { 103 104 //TODO: need to reimplement toXML, toXML, process, 105 //makeImmutable, isMutable methods 106 private boolean inputContextOnly = false; 107 private boolean returnContext = false; 108 private Request request; 109 110 private String xmlString; 111 112 /** 113 * Default constructor 114 */ 115 public XACMLAuthzDecisionQueryImpl() { 116 isMutable = true; 117 } 118 119 /** 120 * This constructor is used to build <code>XACMLAuthzDecisionQuery</code> 121 * object from a block of existing XML that has already been built into a 122 * DOM. 123 * 124 * @param element A <code>org.w3c.dom.Element</code> representing 125 * DOM tree for <code>XACMLAuthzDecisionQuery</code> object 126 * @exception SAML2Exception if it could not process the Element 127 */ 128 public XACMLAuthzDecisionQueryImpl(Element element) throws SAML2Exception { 129 parseDOMElement(element); 130 if (isSigned) { 131 signedXMLString = XMLUtils.print(element); 132 } 133 } 134 135 /** 136 * This constructor is used to build <code>XACMLAuthzDecisionQuery</code> 137 * object from a XML string. 138 * 139 * @param xml A <code>java.lang.String</code> representing 140 * an <code>XACMLAuthzDecisionQuery</code> object 141 * @exception XACMLException if it could not process the XML string 142 */ 143 public XACMLAuthzDecisionQueryImpl(String xml) throws SAML2Exception { 144 Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug); 145 if (document != null) { 146 Element rootElement = document.getDocumentElement(); 147 parseDOMElement(rootElement); 148 this.xmlString = xml; 149 if(isSigned) { 150 signedXMLString = xml; 151 } 152 } else { 153 XACMLSDKUtils.debug.error( 154 "XACMLAuthzDecisionQueryImpl.processElement(): invalid XML " 155 +"input"); 156 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 157 "errorObtainingElement")); 158 } 159 } 160 161 162 /** 163 * Returns the XML attribute boolean value which governs the 164 * source of information that the PDP is allowed to use in 165 * making an authorization decision. If this attribute is "true" 166 * then it indiactes that the authorization decision has been made 167 * solely on the basis of information contained in the <code> 168 * XACMLAuthzDecisionQuery</code>; no external attributes have been 169 * used. If this value is "false" then the decision may have been made 170 * on the basis of external attributes not conatined in the <code> 171 * XACMLAuthzDecisionQuery</code>. 172 * @return <code>boolean</code> indicating the value 173 * of this attribute. 174 */ 175 public boolean getInputContextOnly() { 176 return inputContextOnly; 177 } 178 179 180 /** 181 * Sets the XML attribute boolean value which governs the 182 * source of information that the PDP is allowed to use in 183 * making an authorization decision. If this attribute is "true" 184 * then it indicates to the PDP that the authorization decision has to be 185 * made solely on the basis of information contained in the <code> 186 * XACMLAuthzDecisionQuery</code>; no external attributes may be 187 * used. If this value is "false" then the decision can be made 188 * on the basis of external attributes not conatined in the <code> 189 * XACMlAuthzDecisionQuery</code>. 190 * @param inputContextOnly <code>boolean</code> indicating the value 191 * of this attribute. 192 * 193 * @exception XACMLException if the object is immutable 194 * An object is considered <code>immutable</code> if <code> 195 * makeImmutable()</code> has been invoked on it. It can 196 * be determined by calling <code>isMutable</code> on the object. 197 */ 198 public void setInputContextOnly(boolean inputContextOnly) throws 199 XACMLException 200 { 201 this.inputContextOnly = inputContextOnly; 202 } 203 204 205 /** 206 * Returns the XML attribute boolean value which provides means 207 * to PEP to request that an <code>xacml-context>Request</code> 208 * element be included in the <code>XACMlAuthzdecisionStatement</code> 209 * resulting from the request. It also governs the contents of that 210 * <code.Request</code> element. If this attribite is "true" then the 211 * PDP SHALL include the <code>xacml-context:Request</code> element in the 212 * <code>XACMLAuthzDecisionStatement</code> element in the 213 * <code>XACMLResponse</code>. 214 * The <code>xacml-context:Request</code> SHALL include all the attributes 215 * supplied by the PEP in the <code>AuthzDecisionQuery</code> which were 216 * used in making the authz decision. Other addtional attributes which may 217 * have been used by the PDP may be included. 218 * If this attribute is "false" then the PDP SHALL NOT include the 219 * <code>xacml-context:Request</code> element in the 220 * <code>XACMLAuthzDecisionStatement<code>. 221 * 222 * @return <code>boolean</code> indicating the value 223 * of this attribute. 224 */ 225 public boolean getReturnContext() { 226 return returnContext; 227 } 228 229 /** 230 * Sets the boolean value for this XML attribute 231 * 232 * @param returnContext <code>boolean</code> indicating the value 233 * of this attribute. 234 * 235 * @exception XACMLException if the object is immutable 236 * An object is considered <code>immutable</code> if <code> 237 * makeImmutable()</code> has been invoked on it. It can 238 * be determined by calling <code>isMutable</code> on the object. 239 * 240 * @see #getReturnContext() 241 */ 242 public void setReturnContext(boolean returnContext) throws XACMLException { 243 this.returnContext = returnContext; 244 } 245 246 /** 247 * Returns the <code>xacml-context:Request</code> element of this object 248 * 249 * @return the <code>xacml-context:Request</code> elements of this object 250 */ 251 public Request getRequest() { 252 return request; 253 } 254 255 /** 256 * Sets the <code>xacml-context:Request</code> element of this object 257 * 258 * @param request the <code>xacml-context:Request</code> element of this 259 * object. 260 * 261 * @exception XACMLException if the object is immutable 262 * An object is considered <code>immutable</code> if <code> 263 * makeImmutable()</code> has been invoked on it. It can 264 * be determined by calling <code>isMutable</code> on the object. 265 */ 266 public void setRequest(Request request) throws XACMLException { 267 if (request == null) { 268 throw new XACMLException( 269 XACMLSDKUtils.xacmlResourceBundle.getString( 270 "null_not_valid")); 271 } 272 this.request = request; 273 } 274 275 /** 276 * Returns a string representation of this object 277 * 278 * @return a string representation of this object 279 * @exception XACMLException if conversion fails for any reason 280 */ 281 public String toXMLString() throws XACMLException { 282 //top level element 283 return toXMLString(true, true); 284 } 285 286 /** 287 * Returns a <code>String</code> representation of this object 288 * @param includeNSPrefix Determines whether or not the namespace qualifier 289 * is prepended to the Element when converted 290 * @param declareNS Determines whether or not the namespace is declared 291 * within the Element. 292 * @return a string representation of this object 293 * @exception XACMLException if conversion fails for any reason 294 */ 295 public String toXMLString(boolean includeNSPrefix, boolean declareNS) 296 throws XACMLException { 297 if (isSigned && signedXMLString != null) { 298 return signedXMLString; 299 } 300 301 //validateData(); 302 StringBuffer sb = new StringBuffer(1000); 303 String nsPrefix = ""; 304 String nsDeclaration = ""; 305 if (declareNS) { 306 nsDeclaration = XACMLConstants.SAMLP_NS_DECLARATION; 307 } 308 if (includeNSPrefix) { 309 nsPrefix = XACMLConstants.SAMLP_NS_PREFIX; 310 } 311 312 sb.append("\n<") 313 .append(XACMLConstants.SAMLP_NS_PREFIX) 314 .append(XACMLConstants.REQUEST_ABSTRACT) 315 .append(XACMLConstants.SAMLP_NS_DECLARATION) 316 .append(XACMLConstants.XSI_TYPE_XACML_AUTHZ_DECISION_QUERY) 317 .append(XACMLConstants.XSI_NS_DECLARATION) 318 .append(XACMLConstants.XACML_SAMLP_NS_DECLARATION) 319 .append(XACMLConstants.SPACE) 320 .append(XACMLConstants.XACML_SAMLP_NS_PREFIX) 321 .append(XACMLConstants.INPUT_CONTEXT_ONLY).append("=") 322 .append(XACMLSDKUtils.quote(Boolean.toString(inputContextOnly))) 323 .append(XACMLConstants.SPACE) 324 .append(XACMLConstants.XACML_SAMLP_NS_PREFIX) 325 .append(XACMLConstants.RETURN_CONTEXT).append("=") 326 .append(XACMLSDKUtils.quote(Boolean.toString(returnContext))) 327 .append(XACMLConstants.SPACE) 328 .append("ID").append("=") 329 .append(XACMLSDKUtils.quote(requestId)) 330 .append(XACMLConstants.SPACE) 331 .append("Version").append("=") 332 .append(XACMLSDKUtils.quote(version)) 333 .append(XACMLConstants.SPACE) 334 .append("IssueInstant").append("=") 335 .append(XACMLSDKUtils.quote(DateUtils.toUTCDateFormat( 336 issueInstant))); 337 if (destinationURI != null && destinationURI.trim().length() != 0) { 338 sb.append(" Destination=\"").append(destinationURI). 339 append("\""); 340 } 341 if (consent != null && consent.trim().length() != 0) { 342 sb.append(" Consent=\"").append(consent).append("\""); 343 } 344 sb.append(">\n"); 345 try { 346 if (nameID != null) { 347 sb.append(nameID.toXMLString(includeNSPrefix, declareNS)); 348 } 349 if (signatureString != null) { 350 sb.append(signatureString); 351 } 352 if (extensions != null) { 353 sb.append(extensions.toXMLString(includeNSPrefix, declareNS)); 354 } 355 } catch (Exception e) { 356 } 357 358 if (request != null) { 359 sb.append(request.toXMLString(true, true)).append("\n"); 360 } 361 362 sb.append("\n</") 363 .append(XACMLConstants.SAMLP_NS_PREFIX) 364 .append(XACMLConstants.REQUEST_ABSTRACT) 365 .append(">\n"); 366 return sb.toString(); 367 } 368 369 370 protected void parseDOMElement(Element element) throws SAML2Exception { 371 //TODO: fix 372 String value = null; 373 if (element == null) { 374 XACMLSDKUtils.debug.error( 375 "XACMLAuthzDecisionQueryImpl.processElement(): " 376 + "invalid root element"); 377 throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString( 378 "invalid_element")); 379 } 380 381 // First check that we're really parsing an XACMLAuthzDecisionQuery 382 if (! element.getLocalName().equals( 383 XACMLConstants.REQUEST_ABSTRACT)) { 384 XACMLSDKUtils.debug.error( 385 "XACMLAuthzDecisionQueryImpl.processElement(): " 386 + "invalid root element"); 387 throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString( 388 "missing_local_name")); 389 } 390 391 //TODO: check for xsi:type= 392 393 // now we get the request 394 NodeList nodes = element.getChildNodes(); 395 ContextFactory factory = ContextFactory.getInstance(); 396 for (int i = 0; i < nodes.getLength(); i++) { 397 Node node = nodes.item(i); 398 if ((node.getNodeType() == Node.ELEMENT_NODE) || 399 (node.getNodeType() == Node.ATTRIBUTE_NODE)) { 400 if (node.getLocalName().equals(XACMLConstants.REQUEST)) { 401 if (request != null) { 402 //validation error, throw error 403 } else { 404 request = factory.getInstance().createRequest( 405 (Element)node); 406 } 407 } 408 } 409 } 410 411 // make sure we got a request 412 if (request == null) { 413 //throw new XACMLException( 414 // XACMLSDKUtils.xacmlResourceBundle.getString( 415 // "null_not_valid")); 416 } 417 418 System.out.println("ReturnContex:" + element.getAttributeNS( 419 XACMLConstants.XACML_SAMLP_NS_URI, 420 XACMLConstants.RETURN_CONTEXT)); 421 System.out.println("InputContextOnly:" + element.getAttributeNS( 422 XACMLConstants.XACML_SAMLP_NS_URI, 423 XACMLConstants.INPUT_CONTEXT_ONLY)); 424 String returnContextString = element.getAttributeNS( 425 XACMLConstants.XACML_SAMLP_NS_URI, 426 XACMLConstants.RETURN_CONTEXT); 427 if (returnContextString != null) { 428 returnContext = Boolean.valueOf(returnContextString).booleanValue(); 429 } 430 431 String inputContextOnlyString = element.getAttributeNS( 432 XACMLConstants.XACML_SAMLP_NS_URI, 433 XACMLConstants.INPUT_CONTEXT_ONLY); 434 if (inputContextOnlyString != null) { 435 inputContextOnly = Boolean.valueOf(inputContextOnlyString) 436 .booleanValue(); 437 } 438 439 NamedNodeMap attrs = element.getAttributes(); 440 441 //TODO: change the baseclass impl and call super.parse... 442 443 //parse the attributes of base class RequestAbstract 444 NamedNodeMap atts = ((Node)element).getAttributes(); 445 if (atts != null) { 446 int length = atts.getLength(); 447 for (int i = 0; i < length; i++) { 448 Attr attr = (Attr) atts.item(i); 449 String attrName = attr.getName(); 450 String attrValue = attr.getValue().trim(); 451 if (attrName.equals("ID")) { 452 requestId = attrValue; 453 } else if (attrName.equals("Version")) { 454 version = attrValue; 455 } else if (attrName.equals("IssueInstant")) { 456 try { 457 issueInstant = DateUtils.stringToDate(attrValue); 458 } catch (ParseException pe) { 459 throw new XACMLException(pe.getMessage()); 460 } 461 } else if (attrName.equals("Destination")) { 462 destinationURI = attrValue; 463 } 464 } 465 } 466 467 //parse the elements of base class RequestAbstract 468 NodeList nl = element.getChildNodes(); 469 Node child; 470 String childName; 471 int length = nl.getLength(); 472 for (int i = 0; i < length; i++) { 473 child = nl.item(i); 474 if ((childName = child.getLocalName()) != null) { 475 if (childName.equals("Issuer")) { 476 if (nameID != null) { 477 if (XACMLSDKUtils.debug.messageEnabled()) { 478 XACMLSDKUtils.debug.message( 479 "ArtifactResolveImpl.parse" 480 + "Element: included more than one Issuer."); 481 } 482 throw new XACMLException( 483 XACMLSDKUtils.xacmlResourceBundle.getString( 484 "invalid_duplicate_element")); 485 } 486 if (signatureString != null || 487 extensions != null ) 488 { 489 if (XACMLSDKUtils.debug.messageEnabled()) { 490 XACMLSDKUtils.debug.message( 491 "ArtifactResolveImpl.parse" 492 + "Element:wrong sequence."); 493 } 494 throw new XACMLException( 495 XACMLSDKUtils.xacmlResourceBundle.getString( 496 "schemaViolation")); 497 } 498 nameID = AssertionFactory.getInstance().createIssuer( 499 (Element) child); 500 } else if (childName.equals("Signature")) { 501 if (signatureString != null) { 502 if (XACMLSDKUtils.debug.messageEnabled()) { 503 XACMLSDKUtils.debug.message( 504 "ArtifactResolveImpl.parse" 505 + "Element:included more than one Signature."); 506 } 507 throw new XACMLException( 508 XACMLSDKUtils.xacmlResourceBundle.getString( 509 "invalid_duplicate_element")); 510 } 511 if (extensions != null ) { 512 if (XACMLSDKUtils.debug.messageEnabled()) { 513 XACMLSDKUtils.debug.message( 514 "ArtifactResolveImpl.parse" 515 + "Element:wrong sequence."); 516 } 517 throw new XACMLException( 518 XACMLSDKUtils.xacmlResourceBundle.getString( 519 "schemaViolation")); 520 } 521 signatureString = XMLUtils.print((Element) child); 522 isSigned = true; 523 } else if (childName.equals("Extensions")) { 524 if (extensions != null) { 525 if (XACMLSDKUtils.debug.messageEnabled()) { 526 XACMLSDKUtils.debug.message( 527 "ArtifactResolveImpl.parse" 528 + "Element:included more than one Extensions."); 529 } 530 throw new XACMLException( 531 XACMLSDKUtils.xacmlResourceBundle.getString( 532 "invalid_duplicate_element")); 533 } 534 extensions = ProtocolFactory.getInstance().createExtensions( 535 (Element) child); 536 } else if (childName.equals("Request")) { 537 //no action, it has been processd already 538 } else { 539 if (XACMLSDKUtils.debug.messageEnabled()) { 540 XACMLSDKUtils.debug.message( 541 "XACMLAuthzDecisionQueryImpl.parseDOMElement" 542 + "Element: Invalid element:" + childName); 543 } 544 throw new XACMLException( 545 XACMLSDKUtils.xacmlResourceBundle.getString( 546 "invalidElement")); 547 } 548 } 549 } 550 551 validateData(); 552 553 } 554 555 /** 556 * Makes the object immutable 557 */ 558 public void makeImmutable() { 559 //TODO: fix 560 } 561 562 protected void validateData() throws SAML2Exception { 563 //TODO: fix or remove? 564 super.validateData(); 565 } 566 567}