Skip to content

Commit

Permalink
Require seq field in mongo ACls
Browse files Browse the repository at this point in the history
  • Loading branch information
Carson Anderson committed Feb 5, 2016
1 parent 5292646 commit 06086f3
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 15 deletions.
56 changes: 47 additions & 9 deletions auth_server/authz/acl_mongo.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package authz

import (
"errors"
"fmt"
"sync"
"time"
Expand All @@ -11,6 +12,13 @@ import (
"gopkg.in/mgo.v2/bson"
)

type MongoACL []MongoACLEntry

type MongoACLEntry struct {
ACLEntry `bson:",inline"`
Seq *int
}

type ACLMongoConfig struct {
MongoConfig *mgo_session.Config `yaml:"dial_info,omitempty"`
Collection string `yaml:"collection,omitempty"`
Expand All @@ -28,9 +36,9 @@ type aclMongoAuthorizer struct {
CacheTTL time.Duration `yaml:"cache_ttl,omitempty"`
}

// NewACLMongoAuthorizer creates a new ACL Mongo authorizer
// NewACLMongoAuthorizer creates a new ACL MongoDB authorizer
func NewACLMongoAuthorizer(c *ACLMongoConfig) (Authorizer, error) {
// Attempt to create new mongo session.
// Attempt to create new MongoDB session.
session, err := mgo_session.New(c.MongoConfig)
if err != nil {
return nil, err
Expand Down Expand Up @@ -67,7 +75,7 @@ func (ma *aclMongoAuthorizer) Authorize(ai *AuthRequestInfo) ([]string, error) {
// Validate ensures that any custom config options
// in a Config are set correctly.
func (c *ACLMongoConfig) Validate(configKey string) error {
//First validate the mongo config.
//First validate the MongoDB config.
if err := c.MongoConfig.Validate(configKey); err != nil {
return err
}
Expand Down Expand Up @@ -119,7 +127,7 @@ func (ma *aclMongoAuthorizer) continuouslyUpdateACLCache() {

func (ma *aclMongoAuthorizer) updateACLCache() error {
// Get ACL from MongoDB
var newACL ACL
var newACL MongoACL

// Copy our session
tmp_session := ma.session.Copy()
Expand All @@ -128,13 +136,43 @@ func (ma *aclMongoAuthorizer) updateACLCache() error {
defer tmp_session.Close()

collection := tmp_session.DB(ma.config.MongoConfig.DialInfo.Database).C(ma.config.Collection)
err := collection.Find(bson.M{}).All(&newACL)
if err != nil {

// Create sequence index obj
index := mgo.Index{
Key: []string{"seq"},
Unique: true,
DropDups: false, // Error on duplicate key document instead of drop.
}

// Enforce a sequence index. This is fine to do frequently per the docs:
// https://godoc.org/gopkg.in/mgo.v2#Collection.EnsureIndex:
// Once EnsureIndex returns successfully, following requests for the same index
// will not contact the server unless Collection.DropIndex is used to drop the same
// index, or Session.ResetIndexCache is called.
if err := collection.EnsureIndex(index); err != nil {
return err
}

// Get all ACLs that have the required key
if err := collection.Find(bson.M{}).Sort("seq").All(&newACL); err != nil {
return err
}

glog.V(2).Infof("Number of new ACL entries from MongoDB: %d", len(newACL))

newStaticAuthorizer, err := NewACLAuthorizer(newACL)
// It is possible that the top document in the collection exists with a nil Seq.
// if that's true we pull it out of the slice and complain about it.
if len(newACL) > 0 && newACL[0].Seq == nil {
topACL := newACL[0]
return errors.New(fmt.Sprintf("Seq not set for ACL entry: %+v", topACL))
}

var retACL ACL
for _, e := range newACL {
retACL = append(retACL, e.ACLEntry)
}

newStaticAuthorizer, err := NewACLAuthorizer(retACL)
if err != nil {
return err
}
Expand All @@ -144,7 +182,7 @@ func (ma *aclMongoAuthorizer) updateACLCache() error {
ma.staticAuthorizer = newStaticAuthorizer
ma.lock.Unlock()

glog.V(2).Infof("Got new ACL from MongoDB: %s", newACL)
glog.V(1).Infof("Installed new ACL from MongoDB (%d entries)", len(newACL))
glog.V(2).Infof("Got new ACL from MongoDB: %s", retACL)
glog.V(1).Infof("Installed new ACL from MongoDB (%d entries)", len(retACL))
return nil
}
17 changes: 11 additions & 6 deletions docs/Backend_MongoDB.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,20 @@ MongoDB quite easily. Below you can find a list of ACL entries that are ready to
be imported into MongoDB. Those ACL entries reflect what's specified in the
`example/reference.yml` file under the `acl` section (aka static ACL).

The added field of seq is used to provide a reliable order which MongoDB does not
guarantee by default, i.e. [Natural Sorting](https://docs.mongodb.org/manual/reference/method/cursor.sort/#return-natural-order).

``seq`` is a required field in all MongoDB ACL documents. Any documents without this key will be excluded. seq uniqeness is also enforced.

**reference_acl.json**

```json
{"match" : {"account" : "admin"}, "actions" : ["*"], "comment" : "Admin has full access to everything."}
{"match" : {"account" : "test", "name" : "test-*"}, "actions" : ["*"], "comment" : "User \"test\" has full access to test-* images but nothing else. (1)"}
{"match" : {"account" : "test"}, "actions" : [], "comment" : "User \"test\" has full access to test-* images but nothing else. (2)"}
{"match" : {"account" : "/.+/"}, "actions" : ["pull"], "comment" : "All logged in users can pull all images."}
{"match" : {"account" : "/.+/", "name" : "${account}/*"}, "actions" : ["*"], "comment" : "All logged in users can push all images that are in a namespace beginning with their name"}
{"match" : {"account" : "", "name" : "hello-world"}, "actions" : ["pull"], "comment" : "Anonymous users can pull \"hello-world\"."}
{"seq": 10, "match" : {"account" : "admin"}, "actions" : ["*"], "comment" : "Admin has full access to everything."}
{"seq": 20, "match" : {"account" : "test", "name" : "test-*"}, "actions" : ["*"], "comment" : "User \"test\" has full access to test-* images but nothing else. (1)"}
{"seq": 30, "match" : {"account" : "test"}, "actions" : [], "comment" : "User \"test\" has full access to test-* images but nothing else. (2)"}
{"seq": 40, "match" : {"account" : "/.+/"}, "actions" : ["pull"], "comment" : "All logged in users can pull all images."}
{"seq": 50, "match" : {"account" : "/.+/", "name" : "${account}/*"}, "actions" : ["*"], "comment" : "All logged in users can push all images that are in a namespace beginning with their name"}
{"seq": 60, "match" : {"account" : "", "name" : "hello-world"}, "actions" : ["pull"], "comment" : "Anonymous users can pull \"hello-world\"."}
```

**Note** that each document entry must span exactly one line or otherwise the
Expand Down

0 comments on commit 06086f3

Please sign in to comment.