github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/userpermission.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"gopkg.in/mgo.v2"
    11  	"gopkg.in/mgo.v2/bson"
    12  	"gopkg.in/mgo.v2/txn"
    13  
    14  	"github.com/juju/juju/permission"
    15  )
    16  
    17  // permission represents the permission a user has
    18  // on a given scope.
    19  type userPermission struct {
    20  	doc permissionDoc
    21  }
    22  
    23  type permissionDoc struct {
    24  	ID string `bson:"_id"`
    25  	// ObjectGlobalKey holds the id for the object of the permission.
    26  	// ie. a model globalKey or a controller globalKey.
    27  	ObjectGlobalKey string `bson:"object-global-key"`
    28  	// SubjectGlobalKey holds the id for the user/group that is given permission.
    29  	SubjectGlobalKey string `bson:"subject-global-key"`
    30  	// Access is the permission level.
    31  	Access string `bson:"access"`
    32  }
    33  
    34  func stringToAccess(a string) permission.Access {
    35  	return permission.Access(a)
    36  }
    37  
    38  func accessToString(a permission.Access) string {
    39  	return string(a)
    40  }
    41  
    42  // userPermission returns a Permission for the given Subject and User.
    43  func (st *State) userPermission(objectGlobalKey, subjectGlobalKey string) (*userPermission, error) {
    44  	result := &userPermission{}
    45  	permissions, closer := st.getCollection(permissionsC)
    46  	defer closer()
    47  
    48  	id := permissionID(objectGlobalKey, subjectGlobalKey)
    49  	err := permissions.FindId(id).One(&result.doc)
    50  	if err == mgo.ErrNotFound {
    51  		return nil, errors.NotFoundf("user permissions for user %q", id)
    52  	}
    53  	return result, nil
    54  }
    55  
    56  // controllerUserPermission returns a Permission for the given Subject and User.
    57  func (st *State) controllerUserPermission(objectGlobalKey, subjectGlobalKey string) (*userPermission, error) {
    58  	result := &userPermission{}
    59  
    60  	permissions, closer := st.getCollection(permissionsC)
    61  	defer closer()
    62  
    63  	id := permissionID(objectGlobalKey, subjectGlobalKey)
    64  	err := permissions.FindId(id).One(&result.doc)
    65  	if err == mgo.ErrNotFound {
    66  		return nil, errors.NotFoundf("user permissions for user %q", id)
    67  	}
    68  	return result, nil
    69  }
    70  
    71  // isReadOnly returns whether or not the user has write access or only
    72  // read access to the model.
    73  func (p *userPermission) isReadOnly() bool {
    74  	return stringToAccess(p.doc.Access) == permission.UndefinedAccess || stringToAccess(p.doc.Access) == permission.ReadAccess
    75  }
    76  
    77  // isAdmin is a convenience method that
    78  // returns whether or not the user has permission.AdminAccess.
    79  func (p *userPermission) isAdmin() bool {
    80  	return stringToAccess(p.doc.Access) == permission.AdminAccess
    81  }
    82  
    83  // isReadWrite is a convenience method that
    84  // returns whether or not the user has permission.WriteAccess.
    85  func (p *userPermission) isReadWrite() bool {
    86  	return stringToAccess(p.doc.Access) == permission.WriteAccess
    87  }
    88  
    89  func (p *userPermission) access() permission.Access {
    90  	return stringToAccess(p.doc.Access)
    91  }
    92  
    93  func permissionID(objectGlobalKey, subjectGlobalKey string) string {
    94  	// example: e#:deadbeef#us#jim
    95  	// e: object global key
    96  	// deadbeef: object uuid
    97  	// us#jim: subject global key
    98  	// the first element (e in this example) is the global key for the object
    99  	// (model in this example)
   100  	// the second, is the : prefixed model uuid
   101  	// the third, in this example is a user with name jim, hence the globalKey
   102  	// ( a user global key) being us#jim.
   103  	// another example, now with controller and user maria:
   104  	// c#:deadbeef#us#maria
   105  	// c: object global key, in this case controller.
   106  	// :deadbeef controller uuid
   107  	// us#maria: its the user global key for maria.
   108  	// if this where for model, it would be e#us#maria
   109  	return fmt.Sprintf("%s#%s", objectGlobalKey, subjectGlobalKey)
   110  }
   111  
   112  func updatePermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op {
   113  	return txn.Op{
   114  		C:      permissionsC,
   115  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   116  		Assert: txn.DocExists,
   117  		Update: bson.D{{"$set", bson.D{{"access", accessToString(access)}}}},
   118  	}
   119  }
   120  
   121  func removePermissionOp(objectGlobalKey, subjectGlobalKey string) txn.Op {
   122  	return txn.Op{
   123  		C:      permissionsC,
   124  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   125  		Assert: txn.DocExists,
   126  		Remove: true,
   127  	}
   128  
   129  }
   130  func createPermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op {
   131  	doc := &permissionDoc{
   132  		ID:               permissionID(objectGlobalKey, subjectGlobalKey),
   133  		SubjectGlobalKey: subjectGlobalKey,
   134  		ObjectGlobalKey:  objectGlobalKey,
   135  		Access:           accessToString(access),
   136  	}
   137  	return txn.Op{
   138  		C:      permissionsC,
   139  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   140  		Assert: txn.DocMissing,
   141  		Insert: doc,
   142  	}
   143  }