github.com/apremalal/vamps-core@v1.0.1-0.20161221121535-d430b56ec174/controllers/policy_controller.go (about)

     1  package controllers
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  
     7  	"encoding/json"
     8  	"errors"
     9  	"strconv"
    10  
    11  	log "github.com/Sirupsen/logrus"
    12  	"github.com/vedicsoft/vamps-core/commons"
    13  )
    14  
    15  const GET_USER_POLICIES = `SELECT policy FROM vs_policies WHERE policyid IN( SELECT policyid from vs_role_policies WHERE
    16  							roleid IN (SELECT roleid FROM vs_user_roles WHERE userid=?))`
    17  
    18  const SPLIT_SYMBOL string = "."
    19  const ALL_SYMBOL string = "*"
    20  const ALL_ALL_SYMBOL string = "**"
    21  const (
    22  	FAIL        int = 2
    23  	PASS        int = 1
    24  	NO_DECISION     = 0
    25  )
    26  
    27  type Statement struct {
    28  	Effect    string   `json:"effect"`
    29  	Actions   []string `json:"actions"`
    30  	Resources []string `json:"resources"`
    31  }
    32  
    33  type VAMPSPolicy struct {
    34  	PolicyID   int         `json:"id"`
    35  	Name       string      `json:"name"`
    36  	Statements []Statement `json:"statements"`
    37  }
    38  
    39  func (policy *VAMPSPolicy) evaluate(requestedAction, requestedResource string) int {
    40  	log.Debugf("starting policy %s evaluation for action %s and resource %s", policy.Name, requestedAction,
    41  		requestedResource)
    42  	decision := NO_DECISION
    43  	for _, statement := range policy.Statements {
    44  		if assertAction(statement.Actions, requestedAction) == PASS {
    45  			if assertResource(statement.Resources, requestedResource) == PASS {
    46  				if statement.Effect == "denied" {
    47  					return FAIL
    48  				} else {
    49  					decision = PASS
    50  				}
    51  			}
    52  		}
    53  	}
    54  	return decision
    55  }
    56  
    57  func assertAction(policyActions []string, requestedAction string) int {
    58  	k := strings.Split(requestedAction, SPLIT_SYMBOL)
    59  	for _, policyItem := range policyActions {
    60  		checkLength := len(k)
    61  		var matches int
    62  		p := strings.Split(policyItem, SPLIT_SYMBOL)
    63  		n := len(p)
    64  		if n < checkLength && p[n-2] == ALL_ALL_SYMBOL {
    65  			checkLength = n
    66  		}
    67  
    68  		for j := 0; j < checkLength; j++ {
    69  			if k[j] != p[j] && p[j] != ALL_SYMBOL && p[j] != ALL_ALL_SYMBOL {
    70  				break
    71  			} else if p[j] == ALL_SYMBOL || k[j] == p[j] {
    72  				matches++
    73  				continue
    74  			} else if p[j] == ALL_ALL_SYMBOL && (k[len(k)-1] == p[n-1] || p[n-1] == ALL_ALL_SYMBOL) {
    75  				log.Debugf("requested action: %s matched with policy action: %s \n", requestedAction, policyItem)
    76  				return PASS
    77  			}
    78  		}
    79  		if matches > 0 && matches == checkLength {
    80  			log.Debugf("requested action: %s matched with policy action: %s \n", requestedAction, policyItem)
    81  			return PASS
    82  		}
    83  	}
    84  	return NO_DECISION
    85  }
    86  
    87  func assertResource(policyItems []string, requestedItem string) int {
    88  	k := strings.Split(requestedItem, SPLIT_SYMBOL)
    89  	for _, policyItem := range policyItems {
    90  		checkLength := len(k)
    91  		var matches int
    92  		p := strings.Split(policyItem, SPLIT_SYMBOL)
    93  		n := len(p)
    94  		if n < checkLength && p[n-1] == ALL_ALL_SYMBOL {
    95  			checkLength = n
    96  		}
    97  		for j := 0; j < checkLength; j++ {
    98  			if k[j] != p[j] && p[j] != ALL_SYMBOL && p[j] != ALL_ALL_SYMBOL {
    99  
   100  				break
   101  			} else if p[j] == ALL_SYMBOL || k[j] == p[j] {
   102  				matches++
   103  				continue
   104  			} else if p[j] == ALL_ALL_SYMBOL {
   105  				log.Debugf("requested resource: %s matched with policy resource: %s \n", requestedItem, policyItem)
   106  				return PASS
   107  			}
   108  		}
   109  
   110  		if matches > 0 && matches == checkLength {
   111  			log.Debugf("requested resource: %s matched with policy resource: %s \n", requestedItem, policyItem)
   112  			return PASS
   113  		}
   114  	}
   115  	return NO_DECISION
   116  }
   117  
   118  func (p *VAMPSPolicy) IsValid() bool {
   119  	return false
   120  }
   121  
   122  func getUserPolicies(userID int) ([]VAMPSPolicy, error) {
   123  	dbMap := commons.GetDBConnection(commons.PLATFORM_DB)
   124  	var policies []VAMPSPolicy
   125  	var strPolicies []string
   126  	_, err := dbMap.Select(&strPolicies, GET_USER_POLICIES, userID)
   127  	if err != nil {
   128  		errMsg := "error occurred while getting user policies for user:  stack trace: " + err.Error()
   129  		return policies, errors.New(errMsg)
   130  	}
   131  	policies = make([]VAMPSPolicy, len(strPolicies))
   132  	for i, strPolicy := range strPolicies {
   133  		if len(strPolicy) > 0 {
   134  			err = json.Unmarshal([]byte(strPolicy), &policies[i])
   135  			if err != nil {
   136  				return policies, errors.New("error occurred while unmarshalling policy json: " + err.Error())
   137  			}
   138  		} else {
   139  			return policies, errors.New("invalid policy found for userid:" + strconv.Itoa(userID))
   140  		}
   141  	}
   142  	return policies, nil
   143  }
   144  
   145  func isAuthorized2(tenantID int, userID int, r *http.Request) (bool, error) {
   146  	//resourcePrefix := commons.ServerConfigurations.Prefix
   147  
   148  	requestedResource := strings.ToLower(strings.TrimPrefix(strings.Replace(r.URL.Path, "/", ".", -1), "."))
   149  	requestedAction := strings.ToLower(requestedResource + SPLIT_SYMBOL + r.Method)
   150  
   151  	userPolicies, err := getUserPolicies(userID)
   152  	if err != nil {
   153  		return false, errors.New("unable to get user policies  stack trace:" + err.Error())
   154  	}
   155  	isAuthorized := false
   156  	for _, userPolicy := range userPolicies {
   157  		result := userPolicy.evaluate(requestedAction, requestedResource)
   158  		if result == FAIL {
   159  			log.Debugf("authorization failed for policy %s for action %s and resource %s", userPolicy.Name,
   160  				requestedAction, requestedResource)
   161  			isAuthorized = false
   162  			break
   163  		} else if result == PASS {
   164  			log.Debugf("authorization passed for policy %s for action %s and resource %s", userPolicy.Name,
   165  				requestedAction, requestedResource)
   166  			isAuthorized = true
   167  		} else {
   168  			log.Debugf("authorization nutral for policy %s for action %s and resource %s", userPolicy.Name,
   169  				requestedAction, requestedResource)
   170  		}
   171  	}
   172  	return isAuthorized, nil
   173  }