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: Action.java,v 1.2 2008/06/25 05:47:31 qcheng Exp $ 026 * 027 */ 028 029 030package com.sun.identity.saml.assertion; 031 032import java.util.*; 033import org.w3c.dom.*; 034import com.sun.identity.saml.common.SAMLUtilsCommon; 035import com.sun.identity.saml.common.SAMLConstants; 036import com.sun.identity.saml.common.SAMLException; 037import com.sun.identity.saml.common.SAMLRequesterException; 038import com.sun.identity.shared.xml.XMLUtils; 039 040/** 041 *This class is designed for <code>Action</code> element in SAML core 042 *assertion. This element specifies an action on specified resource for 043 *which permission is sought. 044 *@supported.all.api 045 */ 046public class Action { 047 //An action sought to be performed on the specified resource 048 protected String _action = null; 049 050 //represent the attribute NameSpace of the <code>Action</code> element 051 protected String _namespace = SAMLConstants.ACTION_NAMESPACE_NEGATION; 052 053 /** 054 * Constructs an action element from an existing XML block. 055 * 056 * @param element representing a DOM tree element. 057 * @exception SAMLException f there is an error in the sender or in 058 * the element definition. 059 */ 060 public Action(Element element) throws SAMLException{ 061 // make sure that the input xml block is not null 062 if (element == null) { 063 SAMLUtilsCommon.debug.message("Action: Input is null."); 064 throw new SAMLRequesterException( 065 SAMLUtilsCommon.bundle.getString("nullInput")); 066 } 067 // Make sure this is as Action. 068 String tag = null; 069 tag = element.getLocalName(); 070 if ((tag == null) || (!tag.equals("Action"))) { 071 SAMLUtilsCommon.debug.message("Action: wrong input"); 072 throw new SAMLRequesterException( 073 SAMLUtilsCommon.bundle.getString("wrongInput")); 074 } 075 076 // handle the attribute of <code>Action</code> element 077 // Note: element attributes are not children of ELEMENT_NODEs but 078 // are properties of their associated ELEMENT_NODE. 079 NamedNodeMap atts = ((Node)element).getAttributes(); 080 int attrCount = atts.getLength(); 081 int i = 0; 082 for (i = 0; i < attrCount; i++) { 083 Node att = atts.item(i); 084 if (att.getNodeType() == Node.ATTRIBUTE_NODE) { 085 String attName = att.getLocalName(); 086 if (attName == null || attName.length() == 0) { 087 if (SAMLUtilsCommon.debug.messageEnabled()) { 088 SAMLUtilsCommon.debug.message("Action: Attribute Name" + 089 "is either null or empty."); 090 } 091 throw new SAMLRequesterException( 092 SAMLUtilsCommon.bundle.getString("nullInput")); 093 } 094 if (attName.equals("Namespace")) { 095 _namespace = ((Attr)att).getValue().trim(); 096 } 097 if ((_namespace == null) || (_namespace.length() == 0)) { 098 _namespace = SAMLConstants.ACTION_NAMESPACE_NEGATION; 099 } 100 } 101 } 102 //handle the children elements of <code>Action</code> 103 NodeList nodes = element.getChildNodes(); 104 int nodeCount = nodes.getLength(); 105 if (nodeCount > 0) { 106 for (i = 0; i < nodeCount; i++) { 107 Node currentNode = nodes.item(i); 108 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 109 if (SAMLUtilsCommon.debug.messageEnabled()) { 110 SAMLUtilsCommon.debug.message("Action: Wrong input"); 111 } 112 throw new SAMLRequesterException( 113 SAMLUtilsCommon.bundle.getString("wrongInput")); 114 } 115 } 116 } 117 _action = XMLUtils.getElementValue(element); 118 // check if the action is null. 119 if (_action == null) { 120 if (SAMLUtilsCommon.debug.messageEnabled()) { 121 SAMLUtilsCommon.debug.message("Action is null."); 122 } 123 throw new SAMLRequesterException( 124 SAMLUtilsCommon.bundle.getString("missingElementValue")); 125 } 126 if (!isValid(_action, _namespace)) { 127 if (SAMLUtilsCommon.debug.messageEnabled()) { 128 SAMLUtilsCommon.debug.message("Action is invalid"); 129 } 130 throw new SAMLRequesterException( 131 SAMLUtilsCommon.bundle.getString("invalidAction")); 132 } 133 } 134 135 /** 136 * Convenience constructor of <Action> 137 * @param namespace The attribute "namespace" of 138 * <code><Action></code> element 139 * @param action A String representing an action 140 * @exception SAMLException if there is an error in the sender or in 141 * the element definition. 142 */ 143 public Action(String namespace, String action) throws SAMLException { 144 if (namespace == null || namespace.length() == 0) { 145 if (SAMLUtilsCommon.debug.messageEnabled()) { 146 SAMLUtilsCommon.debug.message("Action:Take default " + 147 "Attribute Namespace."); 148 } 149 } else { 150 _namespace = namespace; 151 } 152 if (action == null || action.length() == 0) { 153 if (SAMLUtilsCommon.debug.messageEnabled()) { 154 SAMLUtilsCommon.debug.message("Action:Action is " + 155 "null or empty."); 156 } 157 throw new SAMLRequesterException( 158 SAMLUtilsCommon.bundle.getString("nullInput")); 159 } else { 160 _action = action; 161 } 162 if (!isValid(_action, _namespace)) { 163 if (SAMLUtilsCommon.debug.messageEnabled()) { 164 SAMLUtilsCommon.debug.message("Action is invalid"); 165 } 166 throw new SAMLRequesterException( 167 SAMLUtilsCommon.bundle.getString("invalidAction")); 168 } 169 } 170 171 /** 172 *Check if the input action string is valid within its specified namespace. 173 *@param action A String representing the action 174 *@param nameSpace The Actions element's namespace. There are four 175 * namespaces that are pre-defined. Action will be checked against 176 * these namespaces. 177 *(1) urn:oasis:names:tc:SAML:1.0:action:rwedc 178 *String used in the ActionNamespace attribute to refer to common sets of 179 *actions to perform on resources. 180 *Title: Read/Write/Execute/Delete/Control 181 *Defined actions: Read Write Execute Delete Control 182 *These actions are interpreted in the normal manner, i.e. 183 * Read: The subject may read the resource 184 * Write: The subject may modify the resource 185 * Execute: The subject may execute the resource 186 * Delete: The subject may delete the resource 187 * Control: The subject may specify the access control policy for the 188 * resource 189 *(2) urn:oasis:names:tc:SAML:1.0:action:rwedc-negation 190 *String used in the ActionNamespace attribute to refer to common sets of 191 *actions to perform on resources. 192 *Title: Read/Write/Execute/Delete/Control with Negation 193 *Defined actions: 194 *Read Write Execute Delete Control ~Read ~Write ~Execute ~Delete ~Control 195 * Read: The subject may read the resource 196 * Write: The subject may modify the resource 197 * Execute: The subject may execute the resource 198 * Delete: The subject may delete the resource 199 * Control: The subject may specify the access control policy for the 200 * resource 201 * ~Read: The subject may NOT read the resource 202 * ~Write: The subject may NOT modify the resource 203 * ~Execute: The subject may NOT execute the resource 204 * ~Delete: The subject may NOT delete the resource 205 * ~Control: The subject may NOT specify the access control policy for 206 * the resource 207 *An application MUST NOT authorize both an action and its negated form. 208 *(3) urn:oasis:names:tc:SAML:1.0:ghpp 209 *String used in the ActionNamespace attribute to refer to common sets of 210 *actions to perform on resources. 211 *Title: Get/Head/Put/Post 212 *Defined actions: 213 * GET HEAD PUT POST 214 *These actions bind to the corresponding HTTP operations. For example a 215 *subject authorized to perform the GET action on a resource is authorized 216 *to retrieve it. The GET and HEAD actions loosely correspond to the 217 *conventional read permission and the PUT and POST actions to the write 218 *permission. The correspondence is not exact however since a HTTP GET 219 *operation may cause data to be modified and a POST operation may cause 220 *modification to a resource other than the one specified in the request. 221 *For this reason a separate Action URI specifier is provided. 222 *(4) urn:oasis:names:tc:SAML:1.0:action:unix 223 *String used in the ActionNamespace attribute to refer to common sets of 224 *actions to perform on resources. 225 *Title: UNIX File Permissions 226 *Defined actions: 227 *The defined actions are the set of UNIX file access permissions expressed 228 *in the numeric (octal) notation. The action string is a four digit numeric 229 *code: extended user group world 230 *Where the extended access permission has the value 231 * +2 if sgid is set 232 * +4 if suid is set 233 *The user group and world access permissions have the value 234 * +1 if execute permission is granted 235 * +2 if write permission is granted 236 * +4 if read permission is granted 237 *For example 0754 denotes the UNIX file access permission: 238 *user read, write 239 *and execute, group read and execute and world read. 240 *@return A boolean representation if the action is valid within its 241 * specified name space. If the namespace param is not one of the 242 * four defined actions namespaces, true is returned. 243 */ 244 private boolean isValid(String action, String namespace) { 245 if (namespace.equals(SAMLConstants.ACTION_NAMESPACE)) { 246 if (action.equals("Read")|| action.equals("Write") || 247 action.equals("Execute") || action.equals("Delete") || 248 action.equals("Control")) { 249 return true; 250 } else { 251 return false; 252 } 253 } 254 255 if (namespace.equals(SAMLConstants.ACTION_NAMESPACE_NEGATION)) { 256 if (action.equals("Read") || action.equals("~Read") || 257 action.equals("Write") || action.equals("~Write") || 258 action.equals("Execute") || action.equals("~Execute") || 259 action.equals("Delete") || action.equals("~Delete") || 260 action.equals("Control") || action.equals("~Control")) { 261 return true; 262 } else { 263 return false; 264 } 265 } 266 267 if (namespace.equals(SAMLConstants.ACTION_NAMESPACE_GHPP)) { 268 if (action.equals("GET") || action.equals("HEAD") || 269 action.equals("PUT") || action.equals("POST")) { 270 return true; 271 } else { 272 return false; 273 } 274 } 275 276 if (namespace.equals(SAMLConstants.ACTION_NAMESPACE_UNIX)) { 277 int permissionNum = 0; 278 try{ 279 permissionNum = Integer.parseInt(action); 280 } catch (NumberFormatException ne) { 281 if (SAMLUtilsCommon.debug.messageEnabled()) { 282 SAMLUtilsCommon.debug.message("Actions: Unix " + 283 "file permissions " + 284 "error:" + ne.getMessage()); 285 } 286 return false; 287 } 288 int quota = permissionNum/1000; 289 int remain = permissionNum - 1000 * quota; 290 int tmp = 0; 291 if (quota == 0 || quota == 2 || quota == 4 || quota == 6) { 292 for (int i = 0; i < 3; i++) { 293 tmp = remain / 10; 294 quota = remain - tmp * 10; 295 if (quota < 0 || quota > 7) 296 return false; 297 remain = tmp; 298 } // end of for loop 299 return true; 300 } else { 301 return false; 302 } 303 } 304 return true; 305 } 306 307 /** 308 *Gets the action string 309 *@return A String representing the action 310 */ 311 public String getAction() { 312 return _action; 313 } 314 315 /** 316 *Gets the namespace of Action 317 *@return A String representing the name space of the action 318 */ 319 public String getNameSpace() { 320 return _namespace; 321 } 322 323 /** 324 *Creates a String representation of the <code>saml:Action</code> element 325 *@return A string containing the valid XML for this element 326 */ 327 public String toString() { 328 return (this.toString(true, false)); 329 } 330 331 /** 332 *Creates a String representation of the <code>saml:Action</code> element 333 *@param includeNS : Determines whether or not the namespace qualifier 334 * is prepended to the Element when converted 335 *@param declareNS : Determines whether or not the namespace 336 * is declared within the Element. 337 *@return A string containing the valid XML for this element 338 */ 339 public String toString(boolean includeNS, boolean declareNS) { 340 StringBuffer result = new StringBuffer(1000); 341 String prefix = ""; 342 String uri = ""; 343 if (includeNS) { 344 prefix = SAMLConstants.ASSERTION_PREFIX; 345 } 346 if (declareNS) { 347 uri = SAMLConstants.assertionDeclareStr; 348 } 349 350 result.append("<").append(prefix).append("Action "). 351 append(uri).append(" Namespace=\"").append(_namespace). 352 append("\">"); 353 result.append(_action); 354 result.append("</").append(prefix).append("Action>\n"); 355 return ((String)result.toString()); 356 } 357} 358