Package com.cloud.bridge.util

Source Code of com.cloud.bridge.util.PolicyParser

/*
* 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.util;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.json.simple.parser.ContentHandler;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import com.cloud.bridge.service.core.s3.S3BucketPolicy;
import com.cloud.bridge.service.core.s3.S3ConditionFactory;
import com.cloud.bridge.service.core.s3.S3PolicyAction;
import com.cloud.bridge.service.core.s3.S3PolicyCondition;
import com.cloud.bridge.service.core.s3.S3PolicyConditionBlock;
import com.cloud.bridge.service.core.s3.S3PolicyPrincipal;
import com.cloud.bridge.service.core.s3.S3PolicyStatement;
import com.cloud.bridge.service.core.s3.S3BucketPolicy.PolicyAccess;
import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions;
import com.cloud.bridge.service.core.s3.S3PolicyCondition.ConditionKeys;
import com.cloud.bridge.service.exception.PermissionDeniedException;

/**
* This class uses the JSON simple parser to convert the JSON of a Bucket Policy
* into internal objects.
*
* Another way to implement this by use of a stack to keep track of where the current
* parsing is being done.   However, since we are only handling a limited JSON sequence
* here simple counts and flags will do the same as a stack.
*/
public class PolicyParser {
    protected final static Logger logger = Logger.getLogger(PolicyParser.class);

  private S3BucketPolicy bucketPolicy = null;
  private S3PolicyPrincipal principals = null;
  private S3PolicyStatement statement = null;
  private S3PolicyAction actions = null;
  private S3PolicyAction convertActions = new S3PolicyAction();
  private S3PolicyCondition condition = null;
  private S3ConditionFactory condFactory = null;
  private S3PolicyConditionBlock block = null;
  private PolicyActions notAction = PolicyActions.UnknownAction;
  private String id =  null;
  private String sid = null;
  private String effect = null;
  private String resource = null;
  private String condKey = null;   // -> the next key in a condition
  private String toUser = null;    // -> text to user of a problem
  private List<String> valueList = new ArrayList<String>();
 
  private JSONParser jparser = null;
  private int entryNesting = 0;    // -> startObjectEntry() .. nesting count
  private int condNested = 0;      // -> at what level of nesting is the condition defined
  private int keyNested = 0;       // -> at what level of nesting is the condition key defined
 
  private boolean inId  = false;   // -> currently in an "Id" element
  private boolean inSid = false;
  private boolean inAWS = false;
  private boolean inEffect = false;
  private boolean inResource = false
  private boolean inNotAction = false;
  private boolean inVersion = false;
  private boolean inStatement = false;
 
 
  public PolicyParser()
  {
    jparser = new JSONParser();
    condFactory = new S3ConditionFactory();
  }

  ContentHandler myHandler = new ContentHandler()
  {
    public boolean endArray() throws ParseException
    {
      logger.debug( "endArray()" );
      return true;
    }

    public void endJSON() throws ParseException, PermissionDeniedException
    {
      logger.debug( "endJSON()" );
     
      if (null != statement)
      {
        //System.out.println( "endJSON() - statement");
        if (null != block) {
          block.verify();
          statement.setConditionBlock( block );
        }       
          if (null != bucketPolicy) {
            statement.verify();
            bucketPolicy.addStatement( statement );
          }
          statement = null;
          block = null;
      }
    }

    public boolean endObject() throws ParseException, PermissionDeniedException
    {
      logger.debug( "endObject(), nesting: " + entryNesting );
     
      if (null != statement && 1 >= entryNesting)
      {
        //System.out.println( "endObject() - statement");
        if (null != block) {
          block.verify();
          statement.setConditionBlock( block );
        }     
        if (null != bucketPolicy) {
          statement.verify();
          bucketPolicy.addStatement( statement );
        }
        statement = null;
        block = null;
      }
     
      if (0 == entryNesting) inStatement = false;
      return true;
    }

    public boolean endObjectEntry() throws ParseException, PermissionDeniedException
    {
      logger.debug( "endObjectEntry(), nesting: " + entryNesting );
     
           if (inSid) {
         if (null != statement) statement.setSid( sid );
         inSid = false;
      }
        else if (inEffect)
        {
           if (null != statement)
           {
                  if (effect.equalsIgnoreCase("Allow")) statement.setEffect( PolicyAccess.ALLOW );
             else if (effect.equalsIgnoreCase("Deny" )) statement.setEffect( PolicyAccess.DENY  );
             else badPolicy( "Effect", effect );
           }
           inEffect = false;
      }
      else if (inResource)
      {
         if (null != statement && resource.startsWith("arn:aws:s3:::"))
         {
           String resourcePath = resource.substring(13);
           verifySameBucket( resourcePath );
           statement.setResource( resourcePath );
         }
         inResource = false;
      }
      else if (inNotAction)
      {
         if (null != statement) statement.setNotAction( notAction );
         inNotAction = false;
      }
      else if (inVersion)
      {
         inVersion = false;
      }
      else if (inId)
      {
         if (null != bucketPolicy) bucketPolicy.setId( id );
         inId = false;
      }
      else if (null != actions)
      {
         if (null != statement) statement.setActions( actions );
         actions = null;
      }
      else if (null != principals)
      {
         if (inAWS && null != statement) statement.setPrincipals( principals );
           principals = null;
      }
      else if (null != condition)
      {
         //System.out.println( "in condition: " + condNested + " " + entryNesting + " " + keyNested );
         // -> is it just the current key that is done?
         try {
             if (keyNested == entryNesting)
             {
               String[] values = valueList.toArray(new String[0]);
               ConditionKeys tempKey = S3PolicyCondition.toConditionKeys( condKey );
               if (ConditionKeys.UnknownKey == tempKey) badPolicy( "Condition Key", condKey );
               condition.setKey( tempKey, values );              
               valueList.clear();
               condKey = null;
             }
         }
         catch( ParseException e ) {
                    logger.error("Policy Parser condition error: ", e);
                    throw e;
         }
         catch( Exception e) {
                    logger.error("Policy Parser condition error: ", e);
                    badPolicy("Condition Key (" + condKey + ")", e.toString());
         }
        
         // -> is the condition completely done?
         if (condNested == entryNesting) {
           condition.verify();
           block.addCondition( condition );
           condition = null;
         }
      }
      else if (null != statement && 1 == entryNesting)
      {
         if (null != block) {
           block.verify();
           statement.setConditionBlock( block );
         }        
         if (null != bucketPolicy) {
           statement.verify();
           bucketPolicy.addStatement( statement );
         }
         statement = null;
         block = null;
      }
          
        entryNesting--;
      return true;
    }

    public boolean primitive(Object value) throws ParseException, PermissionDeniedException
    {
      logger.debug( "primitive(): " + value );
     
           if (inSid) {
             sid = (String)value;
           }
      else if (inEffect) {
         effect = (String)value;
      }
      else if (inResource) {
         resource = (String)value;
      }
      else if (inNotAction) {
         notAction = convertActions.toPolicyActions((String)value);
           if (notAction == PolicyActions.UnknownAction) badPolicy( "NotAction", (String)value );
      }
      else if (inId) {
         id = (String)value;
      }
      else if (null != actions) {
         PolicyActions tempAction = convertActions.toPolicyActions((String)value);
           if (tempAction == PolicyActions.UnknownAction) badPolicy( "Action", (String)value );
         actions.addAction( tempAction );
      }
      else if (null != principals) {
         principals.addPrincipal( (String)value );
      }
      else if (null != condition) {
         // -> a condition key can have one or more values
         valueList.add( (String)value );
      }
      else if (inVersion) {
           String version = (String)value;
           if (!version.equals( "2008-10-17" )) badPolicy( "Version", (String)value );
        }

      return true;
    }

    public boolean startArray() throws ParseException
    {
      logger.debug( "startArray()" );
      return true;
    }

    public void startJSON() throws ParseException
    {
      logger.debug( "startJSON()" );
    }

    public boolean startObject() throws ParseException
    {
      logger.debug( "startObject(), nesting: " + entryNesting );
     
      if (1 == entryNesting && inStatement) statement = new S3PolicyStatement();
     
      return true;
    }

    /**
     * Note: A statement does not have to have a condition block to be valid.
     */
    public boolean startObjectEntry(String key) throws ParseException
    {
      entryNesting++;
      logger.debug( "startObjectEntry(), key: [" + key + "]" );
 
      inSid = false; inAWS = false; inEffect = false; inResource = false;
      inNotAction = false; inVersion = false; inId = false;
     
           if (key.equalsIgnoreCase( "Statement" )) inStatement = true;
      else if (key.equalsIgnoreCase( "Action"    )) actions = new S3PolicyAction();
      else if (key.equalsIgnoreCase( "Principal" )) principals = new S3PolicyPrincipal();
      else if (key.equalsIgnoreCase( "Condition" )) block = new S3PolicyConditionBlock();
      else if (key.equalsIgnoreCase( "AWS"           ) && null != principals) inAWS = true;
      else if (key.equalsIgnoreCase( "CanonicalUser" ) && null != principals) inAWS = true;
      else if (key.equalsIgnoreCase( "Sid"       )) inSid = true;
      else if (key.equalsIgnoreCase( "Effect"    )) inEffect = true;
      else if (key.equalsIgnoreCase( "Resource"  )) inResource = true;
      else if (key.equalsIgnoreCase( "NotAction" )) inNotAction = true;
      else if (key.equalsIgnoreCase( "Version"   )) inVersion = true;
      else if (key.equalsIgnoreCase( "Id"        )) inId = true;
      else if (null != condition) {
         condKey = key;
         keyNested = entryNesting;
      }
      else if (null != block) {
         condition  = condFactory.createCondition( key );
         condNested = entryNesting;
           if (null == condition) badPolicy( "Condition type", key );
      }
      else logger.debug( "startObjectEntry() no match" );
          
      return true;
    }
  };         

 
  public S3BucketPolicy parse( String policy, String bucketName ) throws ParseException, PermissionDeniedException
 
    bucketPolicy = new S3BucketPolicy();
    bucketPolicy.setBucketName( bucketName );
      jparser.parse(policy, myHandler);
      return bucketPolicy;
  }
 
 
  /**
   * From Amazon on S3 Policies:
   * "Each policy must cover only a single bucket and resources within that bucket (when writing a
   * policy, don't include statements that refer to other buckets or resources in other buckets)"
   *
   * @param resourcePath
   */
  private void verifySameBucket( String resourcePath ) throws PermissionDeniedException
  {
    String testBucketName = resourcePath;
    String bucketName = bucketPolicy.getBucketName();
   
    // -> extract just the bucket name
    int offset = testBucketName.indexOf( "/" );
    if (-1 != offset) testBucketName = testBucketName.substring( 0, offset );
   
    if (!testBucketName.equals( bucketName ))
      throw new PermissionDeniedException( "The S3 Bucket Policy must only refer to the single bucket: \"" + bucketName  +
          "\", but it referres to the following resource: \"" + resourcePath + "\"" );
  }
 
  public static void badPolicy( String place, String badValue ) throws ParseException
  {
        String toUser = new String( "S3 Bucket Policy " + place + " of: \"" + badValue + "\" is unknown" );
     throw new ParseException( ParseException.ERROR_UNEXPECTED_TOKEN, toUser );
  }
}
TOP

Related Classes of com.cloud.bridge.util.PolicyParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.