AuthLevelCondition.java revision e60a1cf74ca44a3bb3e3fe63b106e6ef6dca910f
/**
* 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: AuthLevelCondition.java,v 1.9 2009/05/26 08:06:23 kiran_gonipati Exp $
*
*/
/*
* Portions Copyright 2014 ForgeRock AS
*/
package com.sun.identity.policy.plugins;
import com.sun.identity.authentication.util.AMAuthUtils;
import com.sun.identity.policy.interfaces.Condition;
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.iplanet.sso.SSOToken;
import com.iplanet.sso.SSOException;
import com.sun.identity.shared.debug.Debug;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
/**
* This class <code>AuthLevelCondition</code> is a plugin implementation
* of <code>Condition</code> interface. This condition would imply policy
* applies if the <code>requestAuthLevel</code> is greater than or equal to the
* <code>AuthLevel</code> set in the Condition. <code>requestAuthLevel</code>
* is looked up from <code>env </code> map passed in the
* <code>getConditionDecision()</code> call. If it is not found in the
* <code>env</code> map, <code>AuthLevel</code> is looked up from single sign on
* token.
*
* @deprecated Use {@link org.forgerock.openam.entitlement.conditions.environment.AuthLevelCondition} instead.
*/
@Deprecated
public class AuthLevelCondition implements Condition {
private static final Debug DEBUG
= Debug.getInstance(PolicyManager.POLICY_DEBUG_NAME);
private Map properties;
private String authLevel; //realmQualifiedLevel
private String authRealm;
private int authLevelInt;
private static List propertyNames = new ArrayList(1);
static {
propertyNames.add(AUTH_LEVEL);
}
/** No argument constructor
*/
public AuthLevelCondition() {
}
/**
* Returns a list of property names for the condition.
*
* @return list of property names
*/
public List getPropertyNames() {
return (new ArrayList(propertyNames));
}
/**
* Returns the syntax for a property name
* @see com.sun.identity.policy.Syntax
*
* @param property property name
* @return <code>Syntax<code> for the property name
*/
public Syntax getPropertySyntax(String property) {
return Syntax.NONE;
}
/**
* Gets the display name for the property name.
* The <code>locale</code> variable could be used by the plugin to
* customize the display name for the given locale.
* The <code>locale</code> variable could be <code>null</code>, 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.
* @throws PolicyException if unable to get display name
*/
public String getDisplayName(String property, Locale locale)
throws PolicyException {
return "";
}
/**
* Returns 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 <code>Set</code> of valid values for the property.
* @exception PolicyException if unable to get the Syntax.
*/
public Set getValidValues(String property) throws PolicyException {
return Collections.EMPTY_SET;
}
/** Sets the properties of the condition.
* Evaluation of <code>ConditionDecision</code> is influenced by these
* properties.
*
* @param properties the properties of the condition that governs
* whether a policy applies. The properties should
* define value for the key <code>AUTH_LEVEL</code>. The value
* should be a Set with only one element. The element should be
* a String, parseable as an integer or an integer qaulified with
* realm name. Please note that properties is not cloned by
* the method.
*
* @throws PolicyException if properties is null or does not contain
* value for the key <code>AUTH_LEVEL</code> or the value of the
* key is not a Set with one String element that is parse-able as
* an integer
*
* @see #REQUEST_AUTH_LEVEL
* @see #getConditionDecision(SSOToken, Map)
*/
public void setProperties(Map properties) throws PolicyException {
this.properties = (Map)((HashMap) properties);
validateProperties();
}
/** Gets the properties of the condition.
* @return unmodifiable map view of properties that govern the
* evaluation of the condition decision
* @see #setProperties(Map)
*/
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
*
* @param token single-sign-on token of the user
*
* @param env request specific environment map of key/value pairs
* <code>AuthLevelCondition</code> looks for value of key
* <code>REQUEST_AUTH_LEVEL</code> in the map. The value should be
* an Integer or a set of <code>String</code>s.
* If it is a <code>Set</code> of <code>String</code>s, each element
* of the set has to be parseable as integer or should be a realm
* qualified integer. If the <code>env</code> parameter is null or
* does not define value for <code>REQUEST_AUTH_LEVEL</code>,
* the value for <code>REQUEST_AUTH_LEVEL</code> is obtained from
* the single sign on 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.
*
* The decision would imply policy is
* applicable if <code>AUTH_LEVEL</code> is greater than or equal to
* <code>REQUES_AUTH_LEVEL</code>. If <code>AUTH_LEVEL</code> is
* qualified with a realm name, <code>REQUEST_AUTH_LEVEL</code>
* values only with the matching realm name are compared. If the
* policy is not applicable as determined by the
* <code>Condition</code>, an <code>Advice</code> would be
* included in the <code>ConditionDecision</code> with key
* <code>AUTH_LEVEL_ADVICE</code> and value corresponding to
* <code>AUTH_LEVEL</code>
*
* Policy framework continues evaluating a policy only if it applies
* to the request as indicated by the <code>ConditionDecision</code>.
* Otherwise, further evaluation of the policy is skipped.
* However, the <code>Advice</code>s encapsulated in the
* <code>ConditionDecision</code> are aggregated and passed up, encapsulated
* in the <code>PolicyDecision</code>.
*
* @throws PolicyException if the condition has not been initialized
* with a successful call to <code>setProperties(Map)</code>
* and/or the value of <code>REQUEST_AUTH_LEVEL</code> could not
* be determined.
* @throws SSOException if the token is invalid
*
* @see #setProperties(Map)
* @see #AUTH_LEVEL
* @see #REQUEST_AUTH_LEVEL
* @see com.sun.identity.policy.ConditionDecision
* @see com.sun.identity.authentication.util.AMAuthUtils
* #getAuthenticatedLevels(SSOToken)
* @see com.sun.identity.authentication.util.AMAuthUtils
* #getRealmQualifiedAuthenticatedLevels(SSOToken)
*/
public ConditionDecision getConditionDecision(SSOToken token, Map env)
throws PolicyException, SSOException {
boolean allowed = false;
int maxRequestAuthLevel = Integer.MIN_VALUE;
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.getConditionDecision():"
+ "entering");
}
maxRequestAuthLevel = getMaxRequestAuthLevel(env);
if ((maxRequestAuthLevel == Integer.MIN_VALUE) && (token != null)) {
maxRequestAuthLevel = getMaxRequestAuthLevel(token);
}
if (maxRequestAuthLevel >= authLevelInt) {
allowed = true;
}
Map advices = new HashMap();
if (!allowed) {
Set adviceMessages = new HashSet(1);
adviceMessages.add(authLevel);
advices.put(AUTH_LEVEL_CONDITION_ADVICE, adviceMessages);
}
if (DEBUG.messageEnabled()) {
DEBUG.message("At AuthLevelCondition.getConditionDecision():"
+ "authLevel=" + authLevel
+ ",maxRequestAuthLevel=" + maxRequestAuthLevel
+ ",allowed = " + allowed
+ ",advices=" + advices);
}
return new ConditionDecision(allowed, advices);
}
/**
* Returns a copy of this object.
*
* @return a copy of this object
*/
public Object clone() {
AuthLevelCondition theClone = null;
try {
theClone = (AuthLevelCondition) 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 <code>setProperties
* </code> method. It checks for the presence of the required key
* <code>AUTH_LEVEL</code>, validates it and also makes sure no other
* invalid key is being set.
* @see #AUTH_LEVEL
*/
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("AuthLevelCondition.setProperties(),"
+ "properties=" + properties);
}
Set keySet = properties.keySet();
//Check if the required key(s) are defined
if ( !keySet.contains(AUTH_LEVEL) ) {
String args[] = { AUTH_LEVEL };
throw new PolicyException(
ResBundleUtils.rbName,"property_value_not_defined", args,
null);
}
//Check if all the keys are valid
Iterator keys = keySet.iterator();
while ( keys.hasNext()) {
String key = (String) keys.next();
if ( !AUTH_LEVEL.equals(key) ) {
String args[] = {key};
throw new PolicyException(
ResBundleUtils.rbName,
"attempt_to_set_invalid_property ",
args, null);
}
}
//validate AUTH_LEVEL
Set authLevelSet = (Set) properties.get(AUTH_LEVEL);
if ( authLevelSet != null ) {
validateAuthLevels(authLevelSet);
}
if (DEBUG.messageEnabled()) {
DEBUG.message("AuthLevelCondition.setProperties(),"
+ "authLevel=" + authLevel
+ ",authRealm=" + authRealm
+ ",authLevelInt=" + authLevelInt);
}
return true;
}
/**
* This method validates the auth levels set using the <code>setProperties
* </code> method. It is called from validateProperties() method.
* It validates <code>AUTH_LEVEL</code>.
* @see #AUTH_LEVEL
*/
private boolean validateAuthLevels(Set authLevelSet)
throws PolicyException {
if ( authLevelSet.isEmpty() || ( authLevelSet.size() > 1 ) ) {
String args[] = { AUTH_LEVEL };
throw new PolicyException(
ResBundleUtils.rbName,
"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;
}
}