github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/acl_guard.go (about) 1 // Copyright (c) 2014, Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tao 16 17 import ( 18 "crypto/sha256" 19 "errors" 20 "io/ioutil" 21 "os" 22 "strings" 23 24 "github.com/golang/glog" 25 "github.com/golang/protobuf/proto" 26 "github.com/jlmucb/cloudproxy/go/tao/auth" 27 ) 28 29 // An ACLGuard is an implementation of tao.Guard that uses an ACL to make 30 // authorization decisions. All rules are immediately converted to strings when 31 // they are added, and they are never converted back to auth.ast form. Any 32 // policy that requires more than string comparison should use DatalogGuard. 33 type ACLGuard struct { 34 Config ACLGuardDetails 35 ACL []string 36 Key *Verifier 37 } 38 39 // ACLGuardSigningContext is the context used for ACL-file signatures. 40 const ACLGuardSigningContext = "tao.ACLGuard Version 1" 41 const aclGuardFileMode os.FileMode = 0600 42 43 // NewACLGuard produces a Guard implementation that implements ACLGuard. 44 func NewACLGuard(key *Verifier, config ACLGuardDetails) Guard { 45 return &ACLGuard{Config: config, Key: key} 46 } 47 48 // Subprincipal returns a unique subprincipal for this policy. 49 func (a *ACLGuard) Subprincipal() auth.SubPrin { 50 if a.Key == nil { 51 acls := &ACLSet{Entries: a.ACL} 52 ser, err := proto.Marshal(acls) 53 if err != nil { 54 return nil 55 } 56 hash := sha256.Sum256(ser) 57 e := auth.PrinExt{Name: "ACLGuard", Arg: []auth.Term{auth.Bytes(hash[:])}} 58 return auth.SubPrin{e} 59 } 60 e := auth.PrinExt{Name: "ACLGuard", Arg: []auth.Term{a.Key.ToPrincipal()}} 61 return auth.SubPrin{e} 62 } 63 64 // GetSignedACLSet serializes and signs the ACL set and returns a SignedACLSet 65 // pointer. 66 func (a *ACLGuard) GetSignedACLSet(signer *Signer) (*SignedACLSet, error) { 67 acls := &ACLSet{Entries: a.ACL} 68 ser, err := proto.Marshal(acls) 69 if err != nil { 70 return nil, err 71 } 72 73 sig, err := signer.Sign(ser, ACLGuardSigningContext) 74 if err != nil { 75 return nil, err 76 } 77 sdb := &SignedACLSet{ 78 SerializedAclset: ser, 79 Signature: sig, 80 } 81 return sdb, nil 82 } 83 84 // Save writes all persistent policy data to disk, signed by key. 85 func (a *ACLGuard) Save(signer *Signer) error { 86 sdb, err := a.GetSignedACLSet(signer) 87 if err != nil { 88 return err 89 } 90 b, err := proto.Marshal(sdb) 91 if err != nil { 92 return err 93 } 94 if err := ioutil.WriteFile(a.Config.GetSignedAclsPath(), b, aclGuardFileMode); err != nil { 95 return err 96 } 97 98 return nil 99 } 100 101 // LoadACLGuard restores a set of rules saved with Save. It replaces any rules 102 // in the ACLGuard with the rules it loaded. In the process, it also checks the 103 // signature created during the Save process. 104 func LoadACLGuard(key *Verifier, config ACLGuardDetails) (Guard, error) { 105 b, err := ioutil.ReadFile(config.GetSignedAclsPath()) 106 if err != nil { 107 return nil, err 108 } 109 110 var sigACL SignedACLSet 111 if err := proto.Unmarshal(b, &sigACL); err != nil { 112 return nil, err 113 } 114 115 ok, err := key.Verify(sigACL.SerializedAclset, ACLGuardSigningContext, sigACL.Signature) 116 if err != nil { 117 return nil, err 118 } 119 120 if !ok { 121 return nil, errors.New("the signature on the file didn't pass verification") 122 } 123 124 var acls ACLSet 125 if err := proto.Unmarshal(sigACL.SerializedAclset, &acls); err != nil { 126 return nil, err 127 } 128 a := &ACLGuard{Config: config, Key: key} 129 a.ACL = acls.Entries 130 return a, nil 131 } 132 133 func createPredicateString(name auth.Prin, op string, args []string) string { 134 p := auth.Pred{ 135 Name: "Authorized", 136 Arg: make([]auth.Term, len(args)+2), 137 } 138 p.Arg[0] = name 139 p.Arg[1] = auth.Str(op) 140 for i, s := range args { 141 p.Arg[i+2] = auth.Str(s) 142 } 143 144 return p.String() 145 } 146 147 // Authorize adds an authorization for a principal to perform an 148 // operation. 149 func (a *ACLGuard) Authorize(name auth.Prin, op string, args []string) error { 150 a.ACL = append(a.ACL, createPredicateString(name, op, args)) 151 return nil 152 } 153 154 // Retract removes an authorization for a principal to perform an 155 // operation, essentially reversing the effect of an Authorize() call 156 // with identical name, op, and args. Note: this reverses the effect of 157 // an Authorize() call with identical parameters of the equivalent 158 // AddRule() call. However, particularly when expressive policies are 159 // supported (e.g., an "authorize all" rule), other rules may still be 160 // in place authorizing the principal to perform the operation. 161 func (a *ACLGuard) Retract(name auth.Prin, op string, args []string) error { 162 ps := createPredicateString(name, op, args) 163 i := 0 164 for i < len(a.ACL) { 165 if ps == a.ACL[i] { 166 a.ACL[i], a.ACL, i = a.ACL[len(a.ACL)-1], a.ACL[:len(a.ACL)-1], i-1 167 } 168 169 i++ 170 } 171 return nil 172 } 173 174 // IsAuthorized checks whether a principal is authorized to perform an 175 // operation. 176 func (a *ACLGuard) IsAuthorized(name auth.Prin, op string, args []string) bool { 177 ps := createPredicateString(name, op, args) 178 for _, s := range a.ACL { 179 if s == ps { 180 return true 181 } 182 } 183 return false 184 } 185 186 // AddRule adds a policy rule. Subclasses should support at least rules 187 // of the form: Authorized(P, op, args...). This is equivalent to 188 // calling Authorize(P, op, args...) with each of the arguments 189 // converted to either a string or integer. 190 func (a *ACLGuard) AddRule(rule string) error { 191 glog.Infof("Adding rule '%s'", rule) 192 a.ACL = append(a.ACL, rule) 193 return nil 194 } 195 196 // RetractRule removes a rule previously added via AddRule() or the 197 // equivalent Authorize() call. 198 func (a *ACLGuard) RetractRule(rule string) error { 199 i := 0 200 for i < len(a.ACL) { 201 if rule == a.ACL[i] { 202 a.ACL[i], a.ACL, i = a.ACL[len(a.ACL)-1], a.ACL[:len(a.ACL)-1], i-1 203 } 204 205 i++ 206 } 207 return nil 208 } 209 210 // Clear removes all rules. 211 func (a *ACLGuard) Clear() error { 212 a.ACL = make([]string, 0) 213 return nil 214 } 215 216 // Query the policy. Implementations of this interface should support 217 // at least queries of the form: Authorized(P, op, args...). 218 func (a *ACLGuard) Query(query string) (bool, error) { 219 for _, s := range a.ACL { 220 if query == s { 221 return true, nil 222 } 223 } 224 225 return false, nil 226 } 227 228 // RuleCount returns a count of the total number of rules. 229 func (a *ACLGuard) RuleCount() int { 230 return len(a.ACL) 231 } 232 233 // GetRule returns the ith policy rule, if it exists. 234 func (a *ACLGuard) GetRule(i int) string { 235 if i >= len(a.ACL) || i < 0 { 236 return "" 237 } 238 return a.ACL[i] 239 } 240 241 // RuleDebugString returns a debug string for the ith policy rule, if 242 // it exists. 243 func (a *ACLGuard) RuleDebugString(i int) string { 244 return a.GetRule(i) 245 } 246 247 // String returns a string suitable for showing users authorization 248 // info. 249 func (a *ACLGuard) String() string { 250 return "ACLGuard{\n" + strings.Join(a.ACL, "\n") + "\n}" 251 }