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: ActionDecision.java,v 1.5 2008/06/25 05:43:43 qcheng Exp $ 026 * 027 */ 028 029/* 030 * Portions Copyrighted [2011] [ForgeRock AS] 031 */ 032package com.sun.identity.policy; 033 034import com.sun.identity.shared.debug.Debug; 035import com.sun.identity.shared.xml.XMLUtils; 036import java.util.Map; 037import java.util.HashMap; 038import java.util.Set; 039import java.util.HashSet; 040import java.util.Iterator; 041import org.w3c.dom.*; 042 043 044/** 045 * The <code>ActionDecision</code> class represents the action results of a 046 * policy evaluation. It has action values for a given <code>action</code> and 047 * <code>advice</code>. 048 * 049 * @supported.api 050 */ 051public class ActionDecision { 052 053 static final String ACTION_DECISION = "ActionDecision"; 054 static final String ADVICES = "Advices"; 055 static final String VALUES = "Values"; 056 static final String TIME_TO_LIVE = "timeToLive"; 057 static Debug debug = Debug.getInstance("amPolicy"); 058 059 private String actionName; 060 private Set values; 061 private long timeToLive = Long.MAX_VALUE; 062 private Map advices; 063 064 /** 065 * Difference of system clock on the client machine compared to 066 * policy server machine. Valid life of policy decisions are extended 067 * by this skew on the client side. 068 * Value for this is set by reading property 069 * com.sun.identity.policy.client.clockSkew 070 * from SystemProperties 071 * If the value is not defined in AMConfig.properties, 072 * this would default to 0. 073 */ 074 private static long clientClockSkew = 0; 075 076 /** 077 * No argument constructor 078 * @deprecated No replacement API provided. 079 * There should be no need to invoke this constructor. 080 */ 081 public ActionDecision() { 082 } 083 084 /** 085 * Constructor 086 * @param actionName name of the action. 087 * @param values a <code>Set></code> of <code>String</code> values for the 088 * action 089 * @supported.api 090 */ 091 public ActionDecision(String actionName, Set values) { 092 this.actionName = actionName; 093 this.values = values; 094 } 095 096 /** 097 * Constructor 098 * @param actionName action name 099 * @param values a <code>Set</code> of <code>String</code> values for the 100 * action 101 * @param advices <code>advices</code> associated with this action 102 * decision. The advice name is the key to the Map. The 103 * value is a set of advice message Strings corresponding 104 * to the advice name. 105 * @param timeToLive the GMT time in milliseconds since epoch 106 * when this object is to be treated as expired. 107 * That is the action values would likely be different 108 * after that time. 109 * @supported.api 110 */ 111 public ActionDecision(String actionName, Set values, Map advices, 112 long timeToLive 113 ) { 114 this.actionName = actionName; 115 this.values = values; 116 this.advices = advices; 117 this.timeToLive = timeToLive; 118 } 119 120 /** 121 * Gets the name of the action 122 * 123 * @return name of the action 124 * @supported.api 125 */ 126 public String getActionName() { 127 return actionName; 128 } 129 130 /** 131 * Sets the action values for the action. 132 * 133 * @param values a <code>Set</code> of String values 134 * @supported.api 135 */ 136 public void setValues(Set values) { 137 this.values = values; 138 } 139 140 /** 141 * Gets the action values for the action. 142 * 143 * @return a <code>Set>/code> of String values 144 * @supported.api 145 */ 146 public Set getValues() { 147 return values; 148 } 149 150 /** 151 * Gets the GMT time in milliseconds since epoch when this object is to 152 * be treated as expired. That is the action values would likely be 153 * different after that time. 154 * This is computed as a result of <code>SimpleTimeCondition(s)</code> 155 * specified in the Policy definition. 156 * 157 * @return long represeting the time to live for this object. 158 * @supported.api 159 */ 160 public long getTimeToLive() { 161 return timeToLive; 162 } 163 164 /** 165 * Sets the GMT time in milliseconds since epoch when this object is to 166 * be treated as expired. That is the action values would likely be 167 * different after that time. 168 * This is computed as a result of <code>SimpleTimeCondition(s)</code> 169 * specified in the Policy definition. 170 * 171 * @param timeToLive time to live 172 * @supported.api 173 */ 174 public void setTimeToLive(long timeToLive) { 175 this.timeToLive = timeToLive; 176 } 177 178 /** 179 * Sets <code>advices</code> associated with this <code>ActionDecision 180 * </code>. 181 * The advice name is the key to the <code>Map</code>. The 182 * value is a <code>Set</code> of advice message Strings corresponding to 183 * the advice name. The two possible advices are authentication 184 * level(<code>AuthLevel</code>) and authentication modules 185 * (<code>AuthSchemes</code>). The advice message Strings for 186 * <code>AuthLevel</code> are integer valued. 187 * 188 * @param advices map of advices 189 * @supported.api 190 */ 191 public void setAdvices(Map advices) { 192 this.advices = advices; 193 } 194 195 /** 196 * Returns a <code>Map</code> of <code>advices</code> associated with this 197 * object. 198 * The advice name is the key to the <code>Map</code>. The 199 * value is a <code>Set</code> of advice message Strings corresponding to 200 * the advice name. The two possible advices are authentication 201 * level(<code>AuthLevel</code>) and authentication modules 202 * (<code>AuthSchemes</code>). The advice message Strings for 203 * <code>AuthLevel</code> are integer valued. 204 * 205 * @return advices associated with this <code>ActionDecision</code>. 206 * @supported.api 207 */ 208 public Map getAdvices() { 209 return advices; 210 } 211 212 /** 213 * Gets a String representation of this object 214 * 215 * @return a String representation of this object 216 * @supported.api 217 */ 218 public String toString() { 219 return actionName + "=" + values; 220 } 221 222 /** 223 * Gets an XML representation of this object 224 * 225 * @return XML representation of this object 226 * @supported.api 227 */ 228 public String toXML() { 229 StringBuilder sb = new StringBuilder(300); 230 sb.append("<").append(ACTION_DECISION).append(" "); 231 sb.append(TIME_TO_LIVE).append("=").append( 232 PolicyUtils.quote(timeToLive)).append(">"); 233 sb.append(PolicyUtils.CRLF); 234 sb.append(PolicyUtils.attributeValuePairToXMLString(getActionName(), 235 values)); 236 sb.append("<").append(ADVICES).append(">").append(PolicyUtils.CRLF); 237 if (advices != null) { 238 sb.append(PolicyUtils.mapToXMLString(advices)); 239 } 240 sb.append("</").append(ADVICES).append(">").append(PolicyUtils.CRLF); 241 sb.append("</").append(ACTION_DECISION).append(">").append( 242 PolicyUtils.CRLF); 243 return sb.toString(); 244 } 245 246 /** 247 * Creates an ActionDecisions object given a w3c DOM node 248 * @param actionDecisionNode w3c DOM node for action decision 249 * 250 * @return ActionDecisions object created using the w3c DOM node 251 * @throws PolicyException if any error occurs during parsing. 252 */ 253 public static ActionDecision parseActionDecision(Node actionDecisionNode) 254 throws PolicyException { 255 ActionDecision actionDecision = null; 256 //process action name and values 257 Set nodeSet = XMLUtils.getChildNodes(actionDecisionNode, 258 PolicyUtils.ATTRIBUTE_VALUE_PAIR); 259 if ( (nodeSet == null) || (nodeSet.isEmpty()) ) { 260 debug.error("parseActionDecision: missing element " 261 + PolicyUtils.ATTRIBUTE_VALUE_PAIR); 262 return null; 263 } 264 Iterator nodes = nodeSet.iterator(); 265 Node node = (Node)nodes.next(); 266 String actionName = PolicyUtils.getAttributeName(node); 267 Set actionValues = PolicyUtils.getAttributeValues(node); 268 actionDecision = new ActionDecision(actionName, 269 actionValues); 270 271 //process timeToLive 272 long timeToLive = Long.MAX_VALUE; 273 String ttlString = XMLUtils.getNodeAttributeValue(actionDecisionNode, 274 ActionDecision.TIME_TO_LIVE) ; 275 if ( ttlString != null ) { 276 try { 277 timeToLive = Long.parseLong(ttlString); 278 if (timeToLive != Long.MAX_VALUE) { 279 timeToLive += clientClockSkew; 280 } 281 } catch (Exception e) { 282 debug.error("Error while parsing timeToLive in " 283 + " ActionDecision:" + ttlString); 284 Object [] args = { new Long(timeToLive) }; 285 throw new PolicyException(ResBundleUtils.rbName, 286 "invalid_time_to_live", 287 args,e); 288 } 289 } 290 actionDecision.setTimeToLive(timeToLive); 291 292 //process advices 293 Map advices = new HashMap(); 294 nodeSet = XMLUtils.getChildNodes(actionDecisionNode, 295 ActionDecision.ADVICES); 296 if (nodeSet != null) { 297 nodes = nodeSet.iterator(); 298 node = (Node) nodes.next(); 299 nodeSet = XMLUtils.getChildNodes(node, 300 PolicyUtils.ATTRIBUTE_VALUE_PAIR); 301 if ( nodeSet != null ) { 302 nodes = nodeSet.iterator(); 303 while ( nodes.hasNext() ) { 304 node = (Node) nodes.next(); 305 String adviceName = PolicyUtils.getAttributeName(node); 306 if ( adviceName != null ) { 307 Set adviceMessages = PolicyUtils. 308 getAttributeValues(node); 309 advices.put(adviceName, adviceMessages); 310 } 311 } 312 } 313 } 314 actionDecision.setAdvices(advices); 315 316 return actionDecision; 317 } 318 319 /** 320 * Creates and returns a copy of this object. 321 * 322 * @return a copy of this object 323 */ 324 public Object clone() { 325 ActionDecision clone = new ActionDecision(); 326 clone.actionName = actionName; 327 clone.timeToLive = timeToLive; 328 329 if (values != null) { 330 Iterator valuesIter = values.iterator(); 331 clone.values = new HashSet(values.size()); 332 while (valuesIter.hasNext()) { 333 clone.values.add(valuesIter.next()); 334 } 335 } 336 337 if (advices != null) { 338 Iterator adviceIter = advices.keySet().iterator(); 339 clone.advices = new HashMap(advices.size()); 340 341 while (adviceIter.hasNext()) { 342 String key = (String) adviceIter.next(); 343 clone.advices.put(key, advices.get(key)); 344 } 345 } 346 347 return clone; 348 } 349 350 /** 351 * Sets the client clock skew 352 * @param skew the time skew in milliseconds, serverTime - clientTime 353 */ 354 public static void setClientClockSkew(long skew) { 355 clientClockSkew = skew; 356 } 357 358}