AuthLevelCondition.java revision e60a1cf74ca44a3bb3e3fe63b106e6ef6dca910f
0N/A/**
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0N/A *
0N/A * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
0N/A *
0N/A * The contents of this file are subject to the terms
0N/A * of the Common Development and Distribution License
0N/A * (the License). You may not use this file except in
0N/A * compliance with the License.
0N/A *
0N/A * You can obtain a copy of the License at
0N/A * https://opensso.dev.java.net/public/CDDLv1.0.html or
0N/A * opensso/legal/CDDLv1.0.txt
0N/A * See the License for the specific language governing
0N/A * permission and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL
0N/A * Header Notice in each file and include the License file
873N/A * at opensso/legal/CDDLv1.0.txt.
0N/A * If applicable, add the following below the CDDL Header,
0N/A * with the fields enclosed by brackets [] replaced by
0N/A * your own identifying information:
0N/A * "Portions Copyrighted [year] [name of copyright owner]"
0N/A *
3231N/A * $Id: AuthLevelCondition.java,v 1.9 2009/05/26 08:06:23 kiran_gonipati Exp $
6197N/A *
0N/A */
0N/A/*
0N/A * Portions Copyright 2014 ForgeRock AS
0N/A */
0N/A
0N/A
0N/Apackage com.sun.identity.policy.plugins;
0N/A
6197N/Aimport com.sun.identity.authentication.util.AMAuthUtils;
0N/Aimport com.sun.identity.policy.interfaces.Condition;
0N/Aimport com.sun.identity.policy.ConditionDecision;
1689N/Aimport com.sun.identity.policy.PolicyException;
0N/Aimport com.sun.identity.policy.PolicyManager;
0N/Aimport com.sun.identity.policy.ResBundleUtils;
0N/Aimport com.sun.identity.policy.Syntax;
0N/Aimport com.iplanet.sso.SSOToken;
988N/Aimport com.iplanet.sso.SSOException;
1177N/Aimport com.sun.identity.shared.debug.Debug;
0N/A
0N/Aimport java.util.Set;
0N/Aimport java.util.HashSet;
0N/Aimport java.util.Map;
0N/Aimport java.util.HashMap;
0N/Aimport java.util.Iterator;
0N/Aimport java.util.Locale;
0N/Aimport java.util.List;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.Collections;
0N/A
0N/A/**
0N/A * This class <code>AuthLevelCondition</code> is a plugin implementation
0N/A * of <code>Condition</code> interface. This condition would imply policy
2095N/A * applies if the <code>requestAuthLevel</code> is greater than or equal to the
2095N/A * <code>AuthLevel</code> set in the Condition. <code>requestAuthLevel</code>
2095N/A * is looked up from <code>env </code> map passed in the
2095N/A * <code>getConditionDecision()</code> call. If it is not found in the
2095N/A * <code>env</code> map, <code>AuthLevel</code> is looked up from single sign on
2095N/A * token.
1689N/A *
0N/A * @deprecated Use {@link org.forgerock.openam.entitlement.conditions.environment.AuthLevelCondition} instead.
6197N/A */
0N/A@Deprecated
0N/Apublic class AuthLevelCondition implements Condition {
6197N/A
0N/A private static final Debug DEBUG
0N/A = Debug.getInstance(PolicyManager.POLICY_DEBUG_NAME);
6197N/A
0N/A private Map properties;
0N/A private String authLevel; //realmQualifiedLevel
0N/A private String authRealm;
0N/A private int authLevelInt;
0N/A
0N/A private static List propertyNames = new ArrayList(1);
0N/A
0N/A static {
0N/A propertyNames.add(AUTH_LEVEL);
0N/A }
0N/A
0N/A /** No argument constructor
0N/A */
0N/A public AuthLevelCondition() {
0N/A }
0N/A
0N/A /**
0N/A * Returns a list of property names for the condition.
0N/A *
0N/A * @return list of property names
0N/A */
0N/A public List getPropertyNames() {
0N/A return (new ArrayList(propertyNames));
0N/A }
0N/A
0N/A /**
0N/A * Returns the syntax for a property name
0N/A * @see com.sun.identity.policy.Syntax
0N/A *
0N/A * @param property property name
0N/A * @return <code>Syntax<code> for the property name
0N/A */
0N/A public Syntax getPropertySyntax(String property) {
0N/A return Syntax.NONE;
0N/A }
0N/A
0N/A /**
0N/A * Gets the display name for the property name.
0N/A * The <code>locale</code> variable could be used by the plugin to
0N/A * customize the display name for the given locale.
0N/A * The <code>locale</code> variable could be <code>null</code>, in which
0N/A * case the plugin must use the default locale.
0N/A *
6197N/A * @param property property name.
0N/A * @param locale locale for which the property name must be customized.
0N/A * @return display name for the property name.
0N/A * @throws PolicyException if unable to get display name
0N/A */
0N/A public String getDisplayName(String property, Locale locale)
0N/A throws PolicyException {
0N/A return "";
0N/A }
0N/A
0N/A /**
0N/A * Returns a set of valid values given the property name. This method
0N/A * is called if the property Syntax is either the SINGLE_CHOICE or
0N/A * MULTIPLE_CHOICE.
0N/A *
0N/A * @param property property name
0N/A * @return <code>Set</code> of valid values for the property.
0N/A * @exception PolicyException if unable to get the Syntax.
0N/A */
0N/A public Set getValidValues(String property) throws PolicyException {
0N/A return Collections.EMPTY_SET;
0N/A }
0N/A
0N/A /** Sets the properties of the condition.
0N/A * Evaluation of <code>ConditionDecision</code> is influenced by these
0N/A * properties.
0N/A *
0N/A * @param properties the properties of the condition that governs
0N/A * whether a policy applies. The properties should
0N/A * define value for the key <code>AUTH_LEVEL</code>. The value
0N/A * should be a Set with only one element. The element should be
0N/A * a String, parseable as an integer or an integer qaulified with
0N/A * realm name. Please note that properties is not cloned by
0N/A * the method.
0N/A *
0N/A * @throws PolicyException if properties is null or does not contain
0N/A * value for the key <code>AUTH_LEVEL</code> or the value of the
0N/A * key is not a Set with one String element that is parse-able as
0N/A * an integer
0N/A *
0N/A * @see #REQUEST_AUTH_LEVEL
0N/A * @see #getConditionDecision(SSOToken, Map)
0N/A */
0N/A public void setProperties(Map properties) throws PolicyException {
0N/A this.properties = (Map)((HashMap) properties);
0N/A validateProperties();
0N/A }
0N/A
0N/A /** Gets the properties of the condition.
0N/A * @return unmodifiable map view of properties that govern the
0N/A * evaluation of the condition decision
0N/A * @see #setProperties(Map)
0N/A */
0N/A public Map getProperties() {
0N/A return (properties == null)
0N/A ? null : Collections.unmodifiableMap(properties);
0N/A }
0N/A
0N/A /**
0N/A * Gets the decision computed by this condition object, based on the
0N/A * map of environment parameters
0N/A *
0N/A * @param token single-sign-on token of the user
0N/A *
0N/A * @param env request specific environment map of key/value pairs
0N/A * <code>AuthLevelCondition</code> looks for value of key
0N/A * <code>REQUEST_AUTH_LEVEL</code> in the map. The value should be
0N/A * an Integer or a set of <code>String</code>s.
0N/A * If it is a <code>Set</code> of <code>String</code>s, each element
0N/A * of the set has to be parseable as integer or should be a realm
0N/A * qualified integer. If the <code>env</code> parameter is null or
0N/A * does not define value for <code>REQUEST_AUTH_LEVEL</code>,
0N/A * the value for <code>REQUEST_AUTH_LEVEL</code> is obtained from
0N/A * the single sign on token of the user.
0N/A *
0N/A * @return the condition decision. The condition decision encapsulates
0N/A * whether a policy applies for the request and advice messages
0N/A * generated by the condition.
0N/A *
0N/A * The decision would imply policy is
0N/A * applicable if <code>AUTH_LEVEL</code> is greater than or equal to
0N/A * <code>REQUES_AUTH_LEVEL</code>. If <code>AUTH_LEVEL</code> is
0N/A * qualified with a realm name, <code>REQUEST_AUTH_LEVEL</code>
0N/A * values only with the matching realm name are compared. If the
0N/A * policy is not applicable as determined by the
0N/A * <code>Condition</code>, an <code>Advice</code> would be
0N/A * included in the <code>ConditionDecision</code> with key
0N/A * <code>AUTH_LEVEL_ADVICE</code> and value corresponding to
0N/A * <code>AUTH_LEVEL</code>
0N/A *
0N/A * Policy framework continues evaluating a policy only if it applies
0N/A * to the request as indicated by the <code>ConditionDecision</code>.
0N/A * Otherwise, further evaluation of the policy is skipped.
0N/A * However, the <code>Advice</code>s encapsulated in the
0N/A * <code>ConditionDecision</code> are aggregated and passed up, encapsulated
0N/A * in the <code>PolicyDecision</code>.
0N/A *
0N/A * @throws PolicyException if the condition has not been initialized
0N/A * with a successful call to <code>setProperties(Map)</code>
0N/A * and/or the value of <code>REQUEST_AUTH_LEVEL</code> could not
0N/A * be determined.
0N/A * @throws SSOException if the token is invalid
0N/A *
0N/A * @see #setProperties(Map)
0N/A * @see #AUTH_LEVEL
0N/A * @see #REQUEST_AUTH_LEVEL
0N/A * @see com.sun.identity.policy.ConditionDecision
0N/A * @see com.sun.identity.authentication.util.AMAuthUtils
0N/A * #getAuthenticatedLevels(SSOToken)
0N/A * @see com.sun.identity.authentication.util.AMAuthUtils
0N/A * #getRealmQualifiedAuthenticatedLevels(SSOToken)
0N/A */
0N/A public ConditionDecision getConditionDecision(SSOToken token, Map env)
0N/A throws PolicyException, SSOException {
0N/A boolean allowed = false;
988N/A int maxRequestAuthLevel = Integer.MIN_VALUE;
988N/A if (DEBUG.messageEnabled()) {
988N/A DEBUG.message("AuthLevelCondition.getConditionDecision():"
988N/A + "entering");
0N/A }
2095N/A
2095N/A maxRequestAuthLevel = getMaxRequestAuthLevel(env);
2095N/A if ((maxRequestAuthLevel == Integer.MIN_VALUE) && (token != null)) {
2095N/A maxRequestAuthLevel = getMaxRequestAuthLevel(token);
2095N/A }
0N/A
988N/A if (maxRequestAuthLevel >= authLevelInt) {
0N/A allowed = true;
0N/A }
0N/A
0N/A Map advices = new HashMap();
0N/A if (!allowed) {
0N/A Set adviceMessages = new HashSet(1);
0N/A adviceMessages.add(authLevel);
0N/A advices.put(AUTH_LEVEL_CONDITION_ADVICE, adviceMessages);
0N/A }
0N/A if (DEBUG.messageEnabled()) {
0N/A DEBUG.message("At AuthLevelCondition.getConditionDecision():"
0N/A + "authLevel=" + authLevel
0N/A + ",maxRequestAuthLevel=" + maxRequestAuthLevel
0N/A + ",allowed = " + allowed
0N/A + ",advices=" + advices);
0N/A }
0N/A return new ConditionDecision(allowed, advices);
0N/A }
0N/A
0N/A /**
0N/A * Returns a copy of this object.
0N/A *
0N/A * @return a copy of this object
0N/A */
0N/A public Object clone() {
0N/A AuthLevelCondition theClone = null;
0N/A try {
0N/A theClone = (AuthLevelCondition) super.clone();
0N/A } catch (CloneNotSupportedException e) {
0N/A // this should never happen
0N/A throw new InternalError();
0N/A }
0N/A if (properties != null) {
0N/A theClone.properties = new HashMap();
0N/A Iterator it = properties.keySet().iterator();
988N/A while (it.hasNext()) {
988N/A Object o = it.next();
988N/A Set values = new HashSet();
988N/A values.addAll((Set) properties.get(o));
0N/A theClone.properties.put(o, values);
2095N/A }
2095N/A }
2095N/A return theClone;
2095N/A }
2095N/A
0N/A /**
0N/A * This method validates the properties set using the <code>setProperties
988N/A * </code> method. It checks for the presence of the required key
0N/A * <code>AUTH_LEVEL</code>, validates it and also makes sure no other
0N/A * invalid key is being set.
0N/A * @see #AUTH_LEVEL
0N/A */
0N/A
0N/A private boolean validateProperties() throws PolicyException {
0N/A if ( (properties == null) || ( properties.keySet() == null) ) {
0N/A throw new PolicyException(
0N/A ResBundleUtils.rbName,
0N/A "properties_can_not_be_null_or_empty", null, null);
0N/A }
1689N/A
2095N/A if (DEBUG.messageEnabled()) {
2095N/A DEBUG.message("AuthLevelCondition.setProperties(),"
1689N/A + "properties=" + properties);
2095N/A }
2095N/A
2095N/A Set keySet = properties.keySet();
2095N/A //Check if the required key(s) are defined
2095N/A if ( !keySet.contains(AUTH_LEVEL) ) {
2095N/A String args[] = { AUTH_LEVEL };
2095N/A throw new PolicyException(
2095N/A ResBundleUtils.rbName,"property_value_not_defined", args,
1689N/A null);
2095N/A }
2095N/A
2095N/A //Check if all the keys are valid
2095N/A Iterator keys = keySet.iterator();
2095N/A while ( keys.hasNext()) {
2095N/A String key = (String) keys.next();
1689N/A if ( !AUTH_LEVEL.equals(key) ) {
2095N/A String args[] = {key};
2095N/A throw new PolicyException(
1689N/A ResBundleUtils.rbName,
1689N/A "attempt_to_set_invalid_property ",
1689N/A args, null);
2095N/A }
2095N/A }
1689N/A
2095N/A //validate AUTH_LEVEL
2095N/A Set authLevelSet = (Set) properties.get(AUTH_LEVEL);
2095N/A if ( authLevelSet != null ) {
2095N/A validateAuthLevels(authLevelSet);
2095N/A }
2095N/A
2095N/A if (DEBUG.messageEnabled()) {
2095N/A DEBUG.message("AuthLevelCondition.setProperties(),"
2095N/A + "authLevel=" + authLevel
2095N/A + ",authRealm=" + authRealm
2095N/A + ",authLevelInt=" + authLevelInt);
2095N/A }
2095N/A return true;
1689N/A
2095N/A }
2095N/A
2095N/A /**
2095N/A * This method validates the auth levels set using the <code>setProperties
2095N/A * </code> method. It is called from validateProperties() method.
2095N/A * It validates <code>AUTH_LEVEL</code>.
2095N/A * @see #AUTH_LEVEL
2095N/A */
2095N/A private boolean validateAuthLevels(Set authLevelSet)
1689N/A throws PolicyException {
1689N/A if ( authLevelSet.isEmpty() || ( authLevelSet.size() > 1 ) ) {
1689N/A String args[] = { AUTH_LEVEL };
1689N/A throw new PolicyException(
0N/A ResBundleUtils.rbName,
0N/A "property_does_not_allow_empty_or_multiple_values",
args, null);
}
Iterator authLevels = authLevelSet.iterator();
authLevel = (String) authLevels.next();
try {
authRealm = AMAuthUtils.getRealmFromRealmQualifiedData(authLevel);
String authLevelIntString
= AMAuthUtils.getDataFromRealmQualifiedData(authLevel);
authLevelInt = Integer.parseInt(authLevelIntString);
} catch (NumberFormatException e) {
String args[] = { AUTH_LEVEL };
throw new PolicyException(
ResBundleUtils.rbName, "property_is_not_an_Integer",
args, null);
}
return true;
}
/**
* gets the maximum auth level specified for the REQUEST_AUTH_LEVEL
* property in the environment Map.
* @see #REQUEST_AUTH_LEVEL
*/
private int getMaxRequestAuthLevel(Map env)
throws PolicyException {
int maxAuthLevel = Integer.MIN_VALUE;
int currentAuthLevel = Integer.MIN_VALUE;
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "envMap,realm): entering: envMap= " + env
+ ", authRealm= " + authRealm
+ ", conditionAuthLevel= " + authLevel);
}
Object envAuthLevelObject = env.get(REQUEST_AUTH_LEVEL);
if (envAuthLevelObject != null) {
if(envAuthLevelObject instanceof Integer) {
if ((authRealm == null) || (authRealm.length() == 0)) {
maxAuthLevel = ((Integer)envAuthLevelObject).intValue();
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition."
+"getMaxRequestAuthLevel():Integer level in env= "
+ maxAuthLevel);
}
}
} else if (envAuthLevelObject instanceof Set) {
Set envAuthLevelSet = (Set)envAuthLevelObject;
if (!envAuthLevelSet.isEmpty()) {
Iterator iter = envAuthLevelSet.iterator();
while (iter.hasNext()) {
Object envAuthLevelElement = iter.next();
if (!(envAuthLevelElement instanceof String)) {
if (DEBUG.warningEnabled()) {
DEBUG.warning("AuthLevelCondition."
+ "getMaxRequestAuthLevel():"
+ "requestAuthLevel Set element"
+ " not String");
}
throw new PolicyException(
ResBundleUtils.rbName,
"request_authlevel_in_env_set_element_not_string",
null, null);
} else {
String qualifiedLevel = (String)envAuthLevelElement;
currentAuthLevel = getAuthLevel(qualifiedLevel);
if ((authRealm == null)
|| authRealm.length() == 0) {
if(currentAuthLevel > maxAuthLevel) {
maxAuthLevel = currentAuthLevel;
}
} else {
String realmString = AMAuthUtils.
getRealmFromRealmQualifiedData(
qualifiedLevel);
if(authRealm.equals(realmString)
&& (currentAuthLevel > maxAuthLevel)) {
maxAuthLevel = currentAuthLevel;
}
}
}
}
}
} else {
if (DEBUG.warningEnabled()) {
DEBUG.warning("AuthLevelCondition.getMaxRequestAuthLevel():"
+ "requestAuthLevel in env neither"
+ " Integer nor Set");
}
throw new PolicyException(
ResBundleUtils.rbName,
"request_authlevel_in_env_not_Integer_or_set",
null, null);
}
}
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "): returning: maxAuthLevel=" + maxAuthLevel);
}
return maxAuthLevel;
}
/**
* gets the maximum auth level specified for the REQUEST_AUTH_LEVEL
* property in the SSO token.
* @see #REQUEST_AUTH_LEVEL
*/
private int getMaxRequestAuthLevel(SSOToken token)
throws PolicyException, SSOException {
int maxAuthLevel = Integer.MIN_VALUE;
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "token,authRealm): entering:"
+ " authRealm = " + authRealm
+ ", conditionAuthLevel= " + authLevel);
}
if ((authRealm == null) || authRealm.length() == 0) {
Set levels
= AMAuthUtils.getAuthenticatedLevels(token);
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "): levels from token= "
+ levels);
}
if ((levels != null) && (!levels.isEmpty())) {
Iterator iter = levels.iterator();
while (iter.hasNext()) {
String levelString = (String)iter.next();
int level = getAuthLevel(levelString);
maxAuthLevel = (level > maxAuthLevel)? level : maxAuthLevel;
}
}
} else {
Set qualifiedLevels = null;
if (token != null) {
qualifiedLevels =
AMAuthUtils.getRealmQualifiedAuthenticatedLevels(token);
}
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "): qualifiedLeves from token= "
+ qualifiedLevels);
}
if ((qualifiedLevels != null) && (!qualifiedLevels.isEmpty())) {
Iterator iter = qualifiedLevels.iterator();
while (iter.hasNext()) {
String qualifiedLevel = (String)iter.next();
String realm = AMAuthUtils.getRealmFromRealmQualifiedData(
qualifiedLevel);
if (authRealm.equals(realm)) {
int level = getAuthLevel(qualifiedLevel);
maxAuthLevel = (level > maxAuthLevel)? level
: maxAuthLevel;
}
}
}
}
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getMaxRequestAuthLevel("
+ "): returning:"
+ " maxAuthLevel= " + maxAuthLevel);
}
return maxAuthLevel;
}
/**
* Extract the integer auth level from String realm qualified
* ( realm:level) String.
*/
private int getAuthLevel(String qualifiedLevel)
throws PolicyException {
int levelInt = 0;
String levelString
= AMAuthUtils.getDataFromRealmQualifiedData(qualifiedLevel);
try {
levelInt = Integer.parseInt(levelString);
} catch (NumberFormatException nfe) {
if (DEBUG.warningEnabled()) {
DEBUG.warning("AuthLevelCondition.getAuthLevel(qualifiedLevel):"
+ "got NumberFormatException:"
+ "qualifiedLevel=" + qualifiedLevel
+ ", levelString = " + levelString);
}
Object[] args = {levelString};
throw new PolicyException(
ResBundleUtils.rbName, "auth_level_not_integer",
args, nfe);
}
return levelInt;
}
}