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  }