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 }