/*
* Copyright 2011 Cloud.com, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloud.bridge.service.core.s3;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.DatatypeConverter;
import org.apache.log4j.Logger;
import com.cloud.bridge.service.exception.PermissionDeniedException;
import com.cloud.bridge.util.DateHelper;
public class S3PolicyDateCondition extends S3PolicyCondition {
protected final static Logger logger = Logger.getLogger(S3PolicyDateCondition.class);
private Map<ConditionKeys,Calendar[]> keys = new HashMap<ConditionKeys,Calendar[]>();
public S3PolicyDateCondition() {
}
/**
* Return a set holding all the condition keys kept in this object.
* @return Set<String>
*/
public Set<ConditionKeys> getAllKeys() {
return keys.keySet();
}
/**
* After calling getAllKeys(), pass in each key from that result to get
* the key's associated list of values.
* @param key
* @return Calendar[]
*/
public Calendar[] getKeyValues(ConditionKeys key) {
return keys.get(key);
}
/**
* Convert the key's values into the type depending on the what the condition expects.
* @throws ParseException
*/
public void setKey(ConditionKeys key, String[] values) throws ParseException {
Calendar[] dates = new Calendar[ values.length ];
// -> aws:EpochTime - Number of seconds since epoch is supported here and can also be used in a numeric condition
if ( ConditionKeys.EpochTime == key )
{
for( int i=0; i < values.length; i++ ) {
long epochTime = Long.parseLong( values[i] );
dates[i] = DateHelper.toCalendar( new Date( epochTime ));
}
}
else
{ for( int i=0; i < values.length; i++ )
dates[i] = DateHelper.toCalendar( DateHelper.parseISO8601DateString( values[i] ));
}
keys.put(key, dates);
}
/**
* Evaluation logic is as follows:
* 1) An 'AND' operation is used over all defined keys
* 2) An 'OR' operation is used over all key values
*
* Each condition has one or more keys, and each keys have one or more values to test.
*/
public boolean isTrue(S3PolicyContext context, String SID)
{
// -> improperly defined condition evaluates to false
Set<ConditionKeys> keySet = getAllKeys();
if (null == keySet) return false;
Iterator<ConditionKeys> itr = keySet.iterator();
if (!itr.hasNext()) return false;
// -> time to compare with is taken when the condition is evaluated
Calendar tod = Calendar.getInstance();
while( itr.hasNext())
{
ConditionKeys keyName = itr.next();
Calendar[] valueList = getKeyValues( keyName );
boolean keyResult = false;
// -> stop when we hit the first true key value (i.e., key values are 'OR'ed together)
for( int i=0; i < valueList.length && !keyResult; i++ )
{
int difference = tod.compareTo( valueList[i] );
switch( condition ) {
case DateEquals:
if (0 == difference) keyResult = true;
break;
case DateNotEquals:
if (0 != difference) keyResult = true;
break;
case DateLessThan:
if (0 > difference) keyResult = true;
break;
case DateLessThanEquals:
if (0 > difference || 0 == difference) keyResult = true;
break;
case DateGreaterThan:
if (0 < difference) keyResult = true;
break;
case DateGreaterThanEquals:
if (0 < difference || 0 == difference) keyResult = true;
break;
default:
return false;
}
logger.info( "S3PolicyDateCondition eval - SID: " + SID + ", " + condition + ", key: " + keyName + ", valuePassedIn: " + DatatypeConverter.printDateTime(tod) + ", valueInRule: " + DatatypeConverter.printDateTime(valueList[i]) + ", result: " + keyResult );
}
// -> if all key values are, false then that key is false and then the entire condition is then false
if (!keyResult) return false;
}
return true;
}
public void verify() throws PermissionDeniedException
{
if (0 == keys.size())
throw new PermissionDeniedException( "S3 Bucket Policy Date Condition needs at least one key-value pairs" );
}
public String toString()
{
StringBuffer value = new StringBuffer();
Set<ConditionKeys> keySet = getAllKeys();
if (null == keySet) return "";
Iterator<ConditionKeys> itr = keySet.iterator();
value.append( condition + " (a date condition): \n" );
while( itr.hasNext()) {
ConditionKeys keyName = itr.next();
value.append( keyName );
value.append( ": \n" );
Calendar[] valueList = getKeyValues( keyName );
for( int i=0; i < valueList.length; i++ ) {
if (0 < i) value.append( "\n" );
value.append( DatatypeConverter.printDateTime( valueList[i] ));
}
value.append( "\n\n" );
}
return value.toString();
}
}