com.comcast.cmb.common.model.CMBPolicy.java Source code

Java tutorial

Introduction

Here is the source code for com.comcast.cmb.common.model.CMBPolicy.java

Source

/**
 * Copyright 2012 Comcast Corporation
 * 
 * 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.comcast.cmb.common.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.comcast.cmb.common.util.CMBErrorCodes;
import com.comcast.cmb.common.util.CMBException;

/**
 * Class used to represent a policy for CNS and CQS. Each Policy has a list of Statements.
 * @author bwolf, vvenkatraman, baosen, tina
 */
public class CMBPolicy {

    public static final List<String> POLICY_ATTRIBUTES = Arrays.asList("Version", "Id", "Statement");
    public static final List<String> STATEMENT_ATTRIBUTES = Arrays.asList("Sid", "Effect", "Principal", "Action",
            "Resource", "Condition");

    public enum SERVICE {
        CQS, CNS
    };

    public static final List<String> CQS_ACTIONS = Arrays.asList("AddPermission", "ChangeMessageVisibility",
            "ChangeMessageVisibilityBatch", "CreateQueue", "DeleteMessage", "DeleteMessageBatch", "DeleteQueue",
            "GetQueueAttributes", "GetQueueUrl", "ListQueues", "ReceiveMessage", "RemovePermission", "SendMessage",
            "SendMessageBatch", "SetQueueAttributes");
    public static final List<String> CNS_ACTIONS = Arrays.asList("AddPermission", "ConfirmSubscription",
            "CreateTopic", "DeleteTopic", "GetSubscriptionAttributes", "GetTopicAttributes", "ListSubscriptions",
            "ListSubscriptionsByTopic", "ListTopics", "Publish", "RemovePermission", "SetSubscriptionAttributes",
            "SetTopicAttributes", "Subscribe", "Unsubscribe");

    protected List<CMBStatement> statements = null;

    protected String id;
    protected String version;

    /**
     * construct a new policy
     */
    public CMBPolicy() {

        this.id = UUID.randomUUID().toString();
        this.version = "2012-09-13";
        this.statements = new ArrayList<CMBStatement>();
    }

    /**
     * parse the policy string to fill statements
     * @param policy  json encoded string of policy
     * @throws Exception 
     */
    public CMBPolicy(String policyString) throws Exception {
        this();
        fromString(policyString);
    }

    /**
     * Add a statement to this policy identified by sid. One cannot override an existing statement
     * @param service
     * @param sid
     * @param effect
     * @param userList
     * @param actionList
     * @param resource
     * @param condition
     * @return true if statement was added, false otherwise
     * @throws CMBException
     */
    public boolean addStatement(SERVICE service, String sid, String effect, List<String> userList,
            List<String> actionList, String resource, CMBCondition condition) throws CMBException {

        if (this.statements.size() > 0) { // no duplicate label can be set

            for (CMBStatement stmt : this.statements) {

                if (stmt.getSid().equals(sid)) {
                    return false;
                }
            }
        }

        List<String> normalizedActionList = new ArrayList<String>();

        for (String action : actionList) {

            if (action.equals("")) {
                throw new CMBException(CMBErrorCodes.ValidationError, "Blank action parameter is invalid");
            }

            if (!CNS_ACTIONS.contains(action) && !CQS_ACTIONS.contains(action) && !action.equals("*")) {
                throw new CMBException(CMBErrorCodes.InvalidParameterValue, "Invalid action parameter " + action);
            }

            normalizedActionList.add(action.contains(":") ? action : service + ":" + action);
        }

        this.statements.add(new CMBStatement(sid, effect, userList, normalizedActionList, resource, condition));

        return true;
    }

    /**
     * 
     * @param sid
     * @return true if statement was removed/false otherwise
     */
    public boolean removeStatement(String sid) {

        if (this.statements.size() > 0) {
            for (Iterator<CMBStatement> it = statements.iterator(); it.hasNext();) {
                CMBStatement stmt = it.next();
                if (stmt.getSid().equals(sid)) {
                    it.remove();
                    return true;
                }
            }
        }

        return false;
    }

    public List<CMBStatement> getStatements() {
        return this.statements;
    }

    /**
     * check all statements matching user/action, return false upon the first Deny effect 
     * or no Allow effect; otherwise return true.
     * @param user
     * @param action
     * @return
     */
    public boolean isAllowed(User user, String action) {

        if (statements == null) {
            return false;
        }

        boolean allow = false;
        String actionPrefix = action.substring(0, action.lastIndexOf(':') + 1);

        for (CMBStatement stmt : statements) {

            if (stmt.getAction().contains(action) || stmt.getAction().contains(actionPrefix + "*")) {

                if (stmt.getPrincipal().contains(user.getUserId()) || stmt.getPrincipal().contains("*")) {

                    if (stmt.getEffect() == CMBStatement.EFFECT.Deny) {
                        return false;
                    } else {
                        allow = true;
                    }
                }
            }
        }

        return allow;
    }

    @Override
    public String toString() {

        StringBuffer out = new StringBuffer();

        out.append("{\n").append("\"Version\": \"").append(this.version).append("\",\n");
        out.append("\"Id\": \"").append(this.id).append("\",\n");
        out.append("\"Statement\": [\n");
        int count = 0;

        for (CMBStatement stmt : this.statements) {
            out.append("{\n").append(stmt.toString()).append("}");
            count++;
            out.append(count != this.statements.size() ? ",\n" : "\n");
        }

        out.append("]\n").append("}");

        return out.toString();
    }

    /**
     * Parse and populate this object given policyString
     * @param policyString
     * @throws Exception
     */
    public void fromString(String policyString) throws Exception {

        if (policyString == null || policyString.isEmpty()) {
            return;
        }

        // check if valid json

        JSONObject json = new JSONObject(policyString);

        // validate semantics

        Iterator<String> policyIterator = json.keys();

        while (policyIterator.hasNext()) {

            String policyAttribute = policyIterator.next();

            if (!CMBPolicy.POLICY_ATTRIBUTES.contains(policyAttribute)) {
                throw new CMBException(CMBErrorCodes.InvalidAttributeValue,
                        "Invalid value for the parameter Policy");
            }

        }

        JSONArray stmts = json.getJSONArray("Statement");

        if (stmts != null) {

            for (int i = 0; i < stmts.length(); i++) {

                Iterator<String> stmtIterator = stmts.getJSONObject(i).keys();

                while (stmtIterator.hasNext()) {

                    String statementAttribute = stmtIterator.next();

                    if (!CMBPolicy.STATEMENT_ATTRIBUTES.contains(statementAttribute)) {
                        throw new CMBException(CMBErrorCodes.InvalidAttributeValue,
                                "Invalid value for the parameter Policy");
                    }
                }
            }
        }

        // parse content

        this.statements = new ArrayList<CMBStatement>();

        if (json.has("Id")) {
            id = json.getString("Id");
        }

        version = json.getString("Version");

        for (int i = 0; i < stmts.length(); i++) {

            JSONObject obj = (JSONObject) stmts.get(i);
            CMBStatement statement = new CMBStatement();

            statement.setSid(obj.getString("Sid"));
            statement.setEffect(obj.getString("Effect"));

            if (obj.has("Condition")) {
                statement.setCondition(new CMBCondition(obj.getString("Condition")));
            }

            String principal = obj.getJSONObject("Principal").getString(CMBStatement.PRINCIPAL_FIELD);

            if (principal.contains("[")) {
                List<String> accessList = getStringList(
                        obj.getJSONObject("Principal").getJSONArray(CMBStatement.PRINCIPAL_FIELD));
                statement.setPrincipal(accessList);
            } else {
                statement.setPrincipal(Arrays.asList(principal));
            }

            String action = obj.getString("Action");

            if (action.contains("[")) {
                List<String> actionList = getStringList(obj.getJSONArray("Action"));
                statement.setAction(actionList);
            } else {
                statement.setAction(Arrays.asList(action));
            }

            if (obj.has("Resource")) {
                statement.setResource(obj.getString("Resource"));
            }

            this.statements.add(statement);
        }
    }

    private List<String> getStringList(JSONArray jsonArr) throws JSONException {

        List<String> list = new ArrayList<String>();

        for (int i = 0; i < jsonArr.length(); i++) {
            list.add((String) jsonArr.get(i));
        }

        return list;
    }
}