/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: SessionCondition.java,v 1.4 2008/06/25 05:43:52 qcheng Exp $ * * Portions Copyright 2014-2016 ForgeRock AS. */ package com.sun.identity.policy.plugins; import static org.forgerock.openam.utils.Time.*; import com.sun.identity.shared.debug.Debug; import com.sun.identity.shared.locale.AMResourceBundleCache; import com.sun.identity.shared.datastruct.OrderedSet; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.iplanet.sso.SSOTokenManager; import com.sun.identity.shared.DateUtils; import com.sun.identity.policy.ConditionDecision; import com.sun.identity.policy.PolicyException; import com.sun.identity.policy.PolicyManager; import com.sun.identity.policy.ResBundleUtils; import com.sun.identity.policy.Syntax; import com.sun.identity.policy.interfaces.Condition; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.ResourceBundle; /** * The class SessionCondition is a plugin implementation * of Condition. This lets you define the maximum * user session time during which a policy applies. There is an option * to terminate the user session if the session time exceeds the * maximum allowed. * * @deprecated Use {@link org.forgerock.openam.entitlement.conditions.environment.SessionCondition} instead. */ @Deprecated public class SessionCondition implements Condition { /** * Key that is used to define the user session creation time * of the request. This is passed in to the env parameter while * invoking getConditionDecision method of the * SessionCondition. Value for the key should be a * Long whose value is time in milliseconds since epoch. */ public static final String REQUEST_SESSION_CREATION_TIME = "requestSessionCreationTime"; /** * Key that is used to identify the advice messages from this * condition. */ public static final String SESSION_CONDITION_ADVICE = "SessionConditionAdvice"; /** * Key that is used in the Advice to identify the session was * terminated. */ public static final String ADVICE_TERMINATE_SESSION = "terminateSession"; /** * Key that is used in the Advice to identify the condition * decision is deny. */ public static final String ADVICE_DENY = "deny"; private static final String SSOTOKEN_PROPERTY_AUTHINSTANT = "authInstant"; private static final String SESSION_CONDITION_TRUE_VALUE = "session_condition_true_value"; private static final String SESSION_CONDITION_FALSE_VALUE = "session_condition_false_value"; private Map properties; private long maxSessionTime; private boolean terminateSession; private static Debug debug = Debug.getInstance(PolicyManager.POLICY_DEBUG_NAME); private static List propertyNames = new ArrayList(2); private static AMResourceBundleCache amCache = AMResourceBundleCache.getInstance(); static { propertyNames.add(MAX_SESSION_TIME); propertyNames.add(TERMINATE_SESSION); } /** * No argument constructor. */ public SessionCondition() { } /** * Gets a list of property names for the condition. * * @return list of property names */ public List getPropertyNames() { return (new ArrayList(propertyNames)); } /** * Gets the Syntax for a property name. * * @param property property name * @return Syntax for the property name * * @see com.sun.identity.policy.Syntax */ public Syntax getPropertySyntax(String property) { if (property.equals(TERMINATE_SESSION)) { return Syntax.SINGLE_CHOICE; } return Syntax.ANY; } /** * Gets the display name for the property name. * The locale variable could be used by the plugin to * customize the display name for the given locale. * The locale variable could be null, in which * case the plugin must use the default locale. * * @param property property name * @param locale locale for which the property name must be customized * @return display name for the property name * @exception PolicyException if unable to get the diplay name. */ public String getDisplayName(String property, java.util.Locale locale) throws PolicyException { ResourceBundle rb = amCache.getResBundle(ResBundleUtils.rbName, locale); return com.sun.identity.shared.locale.Locale.getString(rb, property); } /** * Gets a set of valid values given the property name. This method * is called if the property Syntax is either the * SINGLE_CHOICE or MULTIPLE_CHOICE. * * @param property property name * @return set of valid values for the property * * @exception PolicyException if unable to get the Syntax */ public Set getValidValues(String property) throws PolicyException { if (property.equals(TERMINATE_SESSION)) { // use OrderedSet to ensure the default is "false" Set values = new OrderedSet(); values.add(SESSION_CONDITION_FALSE_VALUE); values.add(SESSION_CONDITION_TRUE_VALUE); return values; } return Collections.EMPTY_SET; } /** * Sets the properties of the condition. * Evaluation of ConditionDecision is influenced * by these properties. * * @param properties the properties of the condition that governs * whether a policy applies. The properties should define * value for MAX_SESSION_TIME and optionally * TERMINATE_SESSION. * The value should be a Set of string values. The value for * MAX_SESSION_TIME should be parse-able as * an Integer * * @throws PolicyException if properties is null or does not contain * valid value for MAX_SESSION_TIME */ public void setProperties(Map properties) throws PolicyException { this.properties = properties; validateProperties(); } /** * Gets the properties of the condition. * @return unmodifiable Map view of the properties that govern * the evaluation of the condition. * Please note that properties is not cloned before returning */ public Map getProperties() { return (properties == null) ? null : Collections.unmodifiableMap(properties); } /** * Gets the decision computed by this condition object, based on the * map of environment parameters or the user token. If the value of * TERMINATE_SESSION is true and the condition * evaluation is false, it terminates the user session. * * @param token single-sign-on token of the user * @param env request specific environment map of key/value pair. This * condition looks for value of key * REQUEST_SESSION_CREATION_TIME in the map. And the * value should be a Long. If the env is * null of does not define value for * REQUEST_SESSION_CREATION_TIME, the * value will be obtained from SSO token of the user * @return The condition decision. The condition decision encapsulates * whether a policy applies for the request and advice messages * generated by the condition. * Policy framework continues evaluating a policy only if it * applies to the request as indicated by the condition decision. * Otherwise, further evaluation of the policy is skipped. * However, the advice messages encapsulated in the * condition decision are aggregated and passed up, encapsulated in * the policy decision * * @throws PolicyException if the condition has not been initialized * @throws SSOException if the SSO token is invalid or there is error when trying to destroy the SSO token * * @see com.sun.identity.policy.ConditionDecision */ public ConditionDecision getConditionDecision(SSOToken token, Map env) throws PolicyException, SSOException { boolean allowed = false; Long requestSessionCreationTime = null; if (token == null) { return new ConditionDecision(true, Long.MAX_VALUE); } if (env != null) { try { requestSessionCreationTime = (Long) env.get(REQUEST_SESSION_CREATION_TIME); } catch (ClassCastException e) { String args[] = {REQUEST_SESSION_CREATION_TIME}; throw new PolicyException( ResBundleUtils.rbName, "property_is_not_a_Long", args, null); } } long tokenCreationTime; if (requestSessionCreationTime != null) { tokenCreationTime = requestSessionCreationTime.longValue(); } else { try { tokenCreationTime = (DateUtils.stringToDate(token.getProperty( SSOTOKEN_PROPERTY_AUTHINSTANT))).getTime(); } catch (ParseException e) { throw new PolicyException( ResBundleUtils.rbName, "unable_to_parse_ssotoken_authinstant", null, e); } } long currentTime = currentTimeMillis(); long timeToLive = Long.MAX_VALUE; long expiredTime = tokenCreationTime + maxSessionTime; if (debug.messageEnabled()) { debug.message( new StringBuffer("SessionCondition.getConditionDecision():") .append("\n currentTime: ").append(currentTime) .append("\n expiredTime: ").append(expiredTime).toString()); } ConditionDecision conditionDecision = null; if (currentTime < expiredTime) { allowed = true; timeToLive = expiredTime; conditionDecision = new ConditionDecision(allowed, timeToLive); } else { Map advices = new HashMap(1); Set adviceMessages = null; if (terminateSession) { // set advice message adviceMessages = new HashSet(2); adviceMessages.add(ADVICE_DENY); adviceMessages.add(ADVICE_TERMINATE_SESSION); // terminate token session try { SSOTokenManager.getInstance().destroyToken(token); if (debug.messageEnabled()) { debug.message( "SessionCondition.getConditionDecision(): " + "successfully terminated user session!"); } } catch (SSOException ssoEx) { if (debug.warningEnabled()) { debug.warning( "SessionCondition.getConditionDecision(): " + "failed to terminate user session!", ssoEx); } } } else { // set advice message adviceMessages = new HashSet(1); adviceMessages.add(ADVICE_DENY); } advices.put(SESSION_CONDITION_ADVICE, adviceMessages); conditionDecision = new ConditionDecision(allowed, timeToLive, advices); } return conditionDecision; } /** * Creates and returns a copy of this object. * * @return a copy of this object */ public Object clone() { SessionCondition theClone = null; try { theClone = (SessionCondition) super.clone(); } catch (CloneNotSupportedException e) { // this should never happen throw new InternalError(); } if (properties != null) { theClone.properties = new HashMap(); Iterator it = properties.keySet().iterator(); while (it.hasNext()) { Object o = it.next(); Set values = new HashSet(); values.addAll((Set) properties.get(o)); theClone.properties.put(o, values); } } return theClone; } /** * This method validates the properties set using the setProperties * method. It checks for the presence of the required key * MAX_SESSION_TIME, validates it and also makes sure no other * invalid key is being set. It also looks for optional key * TERMINATE_SESSION and ensures its value is valid. * @see #MAX_SESSION_TIME * @see #TERMINATE_SESSION */ private boolean validateProperties() throws PolicyException { if ((properties == null) || (properties.keySet() == null)) { throw new PolicyException( ResBundleUtils.rbName, "properties_can_not_be_null_or_empty", null, null); } if (debug.messageEnabled()) { debug.message("SessionCondition.validateProperties(): " + "properties: " + properties); } // validate and get max session time String value = getPropertyStringValue(MAX_SESSION_TIME, true); try { int i = Integer.parseInt(value); if (i > 0) { maxSessionTime = i * 60000; } else { String args[] = {MAX_SESSION_TIME, value}; throw new PolicyException( ResBundleUtils.rbName, "invalid_property_value", args, null); } } catch (NumberFormatException e) { String args[] = {MAX_SESSION_TIME}; throw new PolicyException( ResBundleUtils.rbName, "property_is_not_an_Integer", args, null); } // get value for terminate session value = getPropertyStringValue(TERMINATE_SESSION, false); if (value != null && value.equals(SESSION_CONDITION_TRUE_VALUE)) { terminateSession = true; } return true; } /** * Utility method to return the propertyName value * from the properties map. */ private String getPropertyStringValue( String propertyName, boolean required) throws PolicyException { Set values = (Set) properties.get(propertyName); if (values == null || values.isEmpty()) { if (required) { String args[] = {propertyName}; throw new PolicyException( ResBundleUtils.rbName,"property_value_not_defined", args, null); } else { return null; } } return ((String) values.iterator().next()); } }