Beispiel #1
0
func TestRebuildRoleChannels(t *testing.T) {
	computer := mockComputer{channels: ch.AtSequence(ch.SetOf("derived1", "derived2"), 1)}
	auth := NewAuthenticator(gTestBucket, &computer)
	role, _ := auth.NewRole("testRole", ch.SetOf("explicit1"))
	err := auth.InvalidateChannels(role)
	assert.Equals(t, err, nil)

	role2, err := auth.GetRole("testRole")
	assert.Equals(t, err, nil)
	assert.DeepEquals(t, role2.Channels(), ch.AtSequence(ch.SetOf("explicit1", "derived1", "derived2"), 1))
}
Beispiel #2
0
func TestRebuildUserChannels(t *testing.T) {
	computer := mockComputer{channels: ch.AtSequence(ch.SetOf("derived1", "derived2"), 1)}
	auth := NewAuthenticator(gTestBucket, &computer)
	user, _ := auth.NewUser("testUser", "password", ch.SetOf("explicit1"))
	user.setChannels(nil)
	err := auth.Save(user)
	assert.Equals(t, err, nil)
	//
	user2, err := auth.GetUser("testUser")
	assert.Equals(t, err, nil)
	log.Printf("Channels = %s", user2.Channels())
	assert.DeepEquals(t, user2.Channels(), ch.AtSequence(ch.SetOf("explicit1", "derived1", "derived2"), 1))
}
Beispiel #3
0
func TestRebuildUserRoles(t *testing.T) {
	computer := mockComputer{roles: ch.AtSequence(base.SetOf("role1", "role2"), 3)}
	auth := NewAuthenticator(gTestBucket, &computer)
	user, _ := auth.NewUser("testUser", "letmein", nil)
	user.SetExplicitRoles(ch.TimedSet{"role3": 1, "role1": 1})
	err := auth.InvalidateRoles(user)
	assert.Equals(t, err, nil)

	user2, err := auth.GetUser("testUser")
	assert.Equals(t, err, nil)
	expected := ch.AtSequence(base.SetOf("role1", "role3"), 1)
	expected.AddChannel("role2", 3)
	assert.DeepEquals(t, user2.RoleNames(), expected)
}
Beispiel #4
0
// Updates a document's channel/role UserAccessMap with new access settings from an AccessMap.
// Returns an array of the user/role names whose access has changed as a result.
func (accessMap *UserAccessMap) updateAccess(doc *document, newAccess channels.AccessMap) (changedUsers []string) {
	// Update users already appearing in doc.Access:
	for name, access := range *accessMap {
		if access.UpdateAtSequence(newAccess[name], doc.Sequence) {
			if len(access) == 0 {
				delete(*accessMap, name)
			}
			changedUsers = append(changedUsers, name)
		}
	}
	// Add new users who are in newAccess but not accessMap:
	for name, access := range newAccess {
		if _, existed := (*accessMap)[name]; !existed {
			if *accessMap == nil {
				*accessMap = UserAccessMap{}
			}
			(*accessMap)[name] = channels.AtSequence(access, doc.Sequence)
			changedUsers = append(changedUsers, name)
		}
	}
	if changedUsers != nil {
		what := "channel"
		if accessMap == &doc.RoleAccess {
			what = "role"
		}
		base.LogTo("Access", "Doc %q grants %s access: %v", doc.ID, what, *accessMap)
	}
	return changedUsers
}
Beispiel #5
0
func (rt *restTester) setAdminParty(partyTime bool) {
	a := rt.ServerContext().Database("db").Authenticator()
	guest, _ := a.GetUser("")
	guest.SetDisabled(!partyTime)
	var chans channels.TimedSet
	if partyTime {
		chans = channels.AtSequence(base.SetOf("*"), 1)
	}
	guest.SetExplicitChannels(chans)
	a.Save(guest)
}
Beispiel #6
0
func (auth *Authenticator) defaultGuestUser() User {
	user := &userImpl{
		roleImpl: roleImpl{
			ExplicitChannels_: ch.AtSequence(ch.SetOf(), 1),
		},
		userImplBody: userImplBody{
			Disabled_: true,
		},
		auth: auth,
	}
	user.Channels_ = user.ExplicitChannels_.Copy()
	return user
}
Beispiel #7
0
func TestRoleInheritance(t *testing.T) {
	// Create some roles:
	auth := NewAuthenticator(gTestBucket, nil)
	role, _ := auth.NewRole("square", ch.SetOf("dull", "duller", "dullest"))
	assert.Equals(t, auth.Save(role), nil)
	role, _ = auth.NewRole("frood", ch.SetOf("hoopy", "hoopier", "hoopiest"))
	assert.Equals(t, auth.Save(role), nil)

	user, _ := auth.NewUser("arthur", "password", ch.SetOf("britain"))
	user.(*userImpl).setRoleNames([]string{"square", "nonexistent", "frood"})
	assert.DeepEquals(t, user.RoleNames(), []string{"square", "nonexistent", "frood"})
	auth.Save(user)

	user2, err := auth.GetUser("arthur")
	assert.Equals(t, err, nil)
	log.Printf("Channels = %s", user2.Channels())
	assert.DeepEquals(t, user2.Channels(), ch.AtSequence(ch.SetOf("britain"), 1))
	assert.DeepEquals(t, user2.InheritedChannels(),
		ch.AtSequence(ch.SetOf("britain", "dull", "duller", "dullest", "hoopy", "hoopier", "hoopiest"), 1))
	assert.True(t, user2.CanSeeChannel("britain"))
	assert.True(t, user2.CanSeeChannel("duller"))
	assert.True(t, user2.CanSeeChannel("hoopy"))
	assert.Equals(t, user2.AuthorizeAllChannels(ch.SetOf("britain", "dull", "hoopiest")), nil)
}
Beispiel #8
0
func (user *userImpl) UnmarshalJSON(data []byte) error {
	if err := json.Unmarshal(data, &user.userImplBody); err != nil {
		return err
	} else if err := json.Unmarshal(data, &user.roleImpl); err != nil {
		return err
	}

	// Migrate "admin_roles" field:
	if user.OldExplicitRoles_ != nil {
		user.ExplicitRoles_ = ch.AtSequence(base.SetFromArray(user.OldExplicitRoles_), 1)
		user.OldExplicitRoles_ = nil
	}

	return nil
}
Beispiel #9
0
func TestAccessFunction(t *testing.T) {
	//base.LogKeys["CRUD"] = true
	//base.LogKeys["Access"] = true

	db := setupTestDB(t)
	defer tearDownTestDB(t, db)

	authenticator := auth.NewAuthenticator(db.Bucket, db)

	var err error
	db.ChannelMapper = channels.NewChannelMapper(`function(doc){access(doc.users,doc.userChannels);}`)

	user, _ := authenticator.NewUser("naomi", "letmein", channels.SetOf("Netflix"))
	user.SetExplicitRoleNames([]string{"animefan", "tumblr"})
	assertNoError(t, authenticator.Save(user), "Save")

	body := Body{"users": []string{"naomi"}, "userChannels": []string{"Hulu"}}
	_, err = db.Put("doc1", body)
	assertNoError(t, err, "")

	body = Body{"users": []string{"role:animefan"}, "userChannels": []string{"CrunchyRoll"}}
	_, err = db.Put("doc2", body)
	assertNoError(t, err, "")

	// Create the role _after_ creating the documents, to make sure the previously-indexed access
	// privileges are applied.
	role, _ := authenticator.NewRole("animefan", nil)
	authenticator.Save(role)

	user, err = authenticator.GetUser("naomi")
	assertNoError(t, err, "GetUser")
	expected := channels.AtSequence(channels.SetOf("Hulu", "Netflix"), 1)
	assert.DeepEquals(t, user.Channels(), expected)

	expected.AddChannel("CrunchyRoll", 2)
	assert.DeepEquals(t, user.InheritedChannels(), expected)
}
Beispiel #10
0
// Returns the (ordered) union of all of the changes made to multiple channels.
func (db *Database) MultiChangesFeed(chans base.Set, options ChangesOptions) (<-chan *ChangeEntry, error) {
	if len(chans) == 0 {
		return nil, nil
	}
	base.LogTo("Changes", "MultiChangesFeed(%s, %+v) ...", chans, options)

	var changeWaiter *changeWaiter
	if options.Wait {
		options.Wait = false
		changeWaiter = db.tapListener.NewWaiterWithChannels(chans, db.user)
	}
	if options.Since == nil {
		options.Since = channels.TimedSet{}
	}

	output := make(chan *ChangeEntry, kChangesViewPageSize)
	go func() {
		defer close(output)

		// This loop is used to re-run the fetch after every database change, in Wait mode
	outer:
		for {
			// Restrict to available channels, expand wild-card, and find since when these channels
			// have been available to the user:
			var channelsSince channels.TimedSet
			if db.user != nil {
				channelsSince = db.user.FilterToAvailableChannels(chans)
			} else {
				channelsSince = channels.AtSequence(chans, 1)
			}
			base.LogTo("Changes", "MultiChangesFeed: channels expand to %s ...", channelsSince)

			// Populate the parallel arrays of channels and names:
			latestSequence, err := db.LastSequence()
			if err != nil {
				base.Warn("MultiChangesFeed got error from LastSequence: %v", err)
				return
			}
			feeds := make([]<-chan *ChangeEntry, 0, len(channelsSince))
			names := make([]string, 0, len(channelsSince))
			for name, _ := range channelsSince {
				var feed <-chan *ChangeEntry
				if latestSequence > options.Since[name] {
					var err error
					feed, err = db.changesFeed(name, options)
					if err != nil {
						base.Warn("MultiChangesFeed got error reading changes feed %q: %v", name, err)
						return
					}
				}
				feeds = append(feeds, feed)
				names = append(names, name)
			}
			current := make([]*ChangeEntry, len(feeds))

			// This loop reads the available entries from all the feeds in parallel, merges them,
			// and writes them to the output channel:
			var sentSomething bool
			for {
				//FIX: This assumes Reverse or Limit aren't set in the options
				// Read more entries to fill up the current[] array:
				for i, cur := range current {
					if cur == nil && feeds[i] != nil {
						var ok bool
						current[i], ok = <-feeds[i]
						if !ok {
							feeds[i] = nil
						}
					}
				}

				// Find the current entry with the minimum sequence:
				var minSeq uint64 = math.MaxUint64
				var minEntry *ChangeEntry
				for _, cur := range current {
					if cur != nil && cur.seqNo < minSeq {
						minSeq = cur.seqNo
						minEntry = cur
					}
				}
				if minEntry == nil {
					break // Exit the loop when there are no more entries
				}

				// Clear the current entries for the sequence just sent:
				for i, cur := range current {
					if cur != nil && cur.seqNo == minSeq {
						current[i] = nil
						// Update the public sequence ID and encode it into the entry:
						options.Since[names[i]] = minSeq
						cur.Seq = options.Since.String()
						cur.seqNo = 0
						// Also concatenate the matching entries' Removed arrays:
						if cur != minEntry && cur.Removed != nil {
							if minEntry.Removed == nil {
								minEntry.Removed = cur.Removed
							} else {
								minEntry.Removed = minEntry.Removed.Union(cur.Removed)
							}
						}
					}
				}

				// Send the entry, and repeat the loop:
				select {
				case <-options.Terminator:
					base.LogTo("Changes+", "Aborting MultiChangesFeed")
					return
				case output <- minEntry:
				}
				sentSomething = true

				// Stop when we hit the limit (if any):
				if options.Limit > 0 {
					options.Limit--
					if options.Limit == 0 {
						break outer
					}
				}
			}

			if sentSomething || changeWaiter == nil {
				break
			}

			// If nothing found, and in wait mode: wait for the db to change, then run again.
			// First notify the reader that we're waiting by sending a nil.
			output <- nil
			if !changeWaiter.Wait() {
				break
			}

			// Before checking again, update the User object in case its channel access has
			// changed while waiting:
			if err := db.ReloadUser(); err != nil {
				base.Warn("Error reloading user %q: %v", db.user.Name(), err)
				return
			}
		}
		base.LogTo("Changes", "MultiChangesFeed done")
	}()

	return output, nil
}
Beispiel #11
0
// Returns the (ordered) union of all of the changes made to multiple channels.
func (db *Database) MultiChangesFeed(chans base.Set, options ChangesOptions) (<-chan *ChangeEntry, error) {
	if len(chans) == 0 {
		return nil, nil
	}
	base.LogTo("Changes", "MultiChangesFeed(%s, %+v) ...", chans, options)

	if (options.Continuous || options.Wait) && options.Terminator == nil {
		base.Warn("MultiChangesFeed: Terminator missing for Continuous/Wait mode")
	}

	output := make(chan *ChangeEntry, 50)
	go func() {
		defer func() {
			base.LogTo("Changes", "MultiChangesFeed done")
			close(output)
		}()

		var changeWaiter *changeWaiter
		var userChangeCount uint64
		if options.Wait {
			options.Wait = false
			changeWaiter = db.tapListener.NewWaiterWithChannels(chans, db.user)
			userChangeCount = changeWaiter.CurrentUserCount()
		}

		// This loop is used to re-run the fetch after every database change, in Wait mode
	outer:
		for {
			// Restrict to available channels, expand wild-card, and find since when these channels
			// have been available to the user:
			var channelsSince channels.TimedSet
			if db.user != nil {
				channelsSince = db.user.FilterToAvailableChannels(chans)
			} else {
				channelsSince = channels.AtSequence(chans, 0)
			}
			base.LogTo("Changes+", "MultiChangesFeed: channels expand to %#v ...", channelsSince)

			// Populate the parallel arrays of channels and names:
			feeds := make([]<-chan *ChangeEntry, 0, len(channelsSince))
			names := make([]string, 0, len(channelsSince))
			for name, seqAddedAt := range channelsSince {
				chanOpts := options
				if seqAddedAt > 1 && options.Since.Before(SequenceID{Seq: seqAddedAt}) {
					// Newly added channel so send all of it to user:
					chanOpts.Since = SequenceID{Seq: 0, TriggeredBy: seqAddedAt}
				}
				feed, err := db.changesFeed(name, chanOpts)
				if err != nil {
					base.Warn("MultiChangesFeed got error reading changes feed %q: %v", name, err)
					return
				}
				feeds = append(feeds, feed)
				names = append(names, name)
			}

			// If the user object has changed, create a special pseudo-feed for it:
			if db.user != nil {
				userSeq := SequenceID{Seq: db.user.Sequence()}
				if options.Since.Before(userSeq) {
					name := db.user.Name()
					if name == "" {
						name = "GUEST"
					}
					entry := ChangeEntry{
						Seq:     userSeq,
						ID:      "_user/" + name,
						Changes: []ChangeRev{},
					}
					userFeed := make(chan *ChangeEntry, 1)
					userFeed <- &entry
					close(userFeed)
					feeds = append(feeds, userFeed)
					names = append(names, entry.ID)
				}
			}

			current := make([]*ChangeEntry, len(feeds))

			// This loop reads the available entries from all the feeds in parallel, merges them,
			// and writes them to the output channel:
			var sentSomething bool
			for {
				// Read more entries to fill up the current[] array:
				for i, cur := range current {
					if cur == nil && feeds[i] != nil {
						var ok bool
						current[i], ok = <-feeds[i]
						if !ok {
							feeds[i] = nil
						}
					}
				}

				// Find the current entry with the minimum sequence:
				minSeq := MaxSequenceID
				var minEntry *ChangeEntry
				for _, cur := range current {
					if cur != nil && cur.Seq.Before(minSeq) {
						minSeq = cur.Seq
						minEntry = cur
					}
				}
				if minEntry == nil {
					break // Exit the loop when there are no more entries
				}

				// Clear the current entries for the sequence just sent:
				for i, cur := range current {
					if cur != nil && cur.Seq == minSeq {
						current[i] = nil
						//options.Since = minSeq //TEMP ???
						// Also concatenate the matching entries' Removed arrays:
						if cur != minEntry && cur.Removed != nil {
							if minEntry.Removed == nil {
								minEntry.Removed = cur.Removed
							} else {
								minEntry.Removed = minEntry.Removed.Union(cur.Removed)
							}
						}
					}
				}

				if !options.Since.Before(minSeq) {
					continue // out of order; skip it
				}

				// Add the doc body or the conflicting rev IDs, if those options are set:
				if options.IncludeDocs || options.Conflicts {
					db.addDocToChangeEntry(minEntry, options)
				}

				// Send the entry, and repeat the loop:
				base.LogTo("Changes+", "MultiChangesFeed sending %+v", minEntry)
				select {
				case <-options.Terminator:
					return
				case output <- minEntry:
				}
				sentSomething = true

				// Stop when we hit the limit (if any):
				if options.Limit > 0 {
					options.Limit--
					if options.Limit == 0 {
						break outer
					}
				}
			}

			if !options.Continuous && (sentSomething || changeWaiter == nil) {
				break
			}

			// If nothing found, and in wait mode: wait for the db to change, then run again.
			// First notify the reader that we're waiting by sending a nil.
			base.LogTo("Changes+", "MultiChangesFeed waiting...")
			output <- nil
			if !changeWaiter.Wait() {
				break
			}

			// Check whether I was terminated while waiting for a change:
			select {
			case <-options.Terminator:
				return
			default:
			}

			// Before checking again, update the User object in case its channel access has
			// changed while waiting:
			if newCount := changeWaiter.CurrentUserCount(); newCount > userChangeCount {
				base.LogTo("Changes+", "MultiChangesFeed reloading user %q", db.user.Name())
				userChangeCount = newCount
				if err := db.ReloadUser(); err != nil {
					base.Warn("Error reloading user %q: %v", db.user.Name(), err)
					return
				}
			}
		}
	}()

	return output, nil
}
Beispiel #12
0
func TestUserAccess(t *testing.T) {
	// User with no access:
	auth := NewAuthenticator(gTestBucket, nil)
	user, _ := auth.NewUser("foo", "password", nil)
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf())
	assert.False(t, user.CanSeeChannel("x"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("*")))
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)
	assert.False(t, user.AuthorizeAnyChannel(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAnyChannel(ch.SetOf()) == nil)

	// User with access to one channel:
	user.setChannels(ch.AtSequence(ch.SetOf("x"), 1))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf("x"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)
	assert.True(t, user.AuthorizeAnyChannel(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAnyChannel(ch.SetOf("y")) == nil)
	assert.False(t, user.AuthorizeAnyChannel(ch.SetOf()) == nil)

	// User with access to one channel and one derived channel:
	user.setChannels(ch.AtSequence(ch.SetOf("x", "z"), 1))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf("x", "z"))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("x")), ch.SetOf("x"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)

	// User with access to two channels:
	user.setChannels(ch.AtSequence(ch.SetOf("x", "z"), 1))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf("x", "z"))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("x")), ch.SetOf("x"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)

	user.setChannels(ch.AtSequence(ch.SetOf("x", "y"), 1))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf("x", "y"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.False(t, canSeeAllChannels(user, ch.SetOf("x", "y", "z")))
	assert.True(t, user.AuthorizeAllChannels(ch.SetOf("x", "y")) == nil)
	assert.False(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)

	// User with wildcard access:
	user.setChannels(ch.AtSequence(ch.SetOf("*", "q"), 1))
	assert.DeepEquals(t, user.ExpandWildCardChannel(ch.SetOf("*")), ch.SetOf("*", "q"))
	assert.True(t, user.CanSeeChannel("*"))
	assert.True(t, canSeeAllChannels(user, ch.SetOf()))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x")))
	assert.True(t, canSeeAllChannels(user, ch.SetOf("x", "y")))
	assert.True(t, user.AuthorizeAllChannels(ch.SetOf("x", "y")) == nil)
	assert.True(t, user.AuthorizeAllChannels(ch.SetOf("*")) == nil)
	assert.True(t, user.AuthorizeAnyChannel(ch.SetOf("x")) == nil)
	assert.True(t, user.AuthorizeAnyChannel(ch.SetOf("*")) == nil)
	assert.True(t, user.AuthorizeAnyChannel(ch.SetOf()) == nil)
}
Beispiel #13
0
func (role *roleImpl) initRole(name string, channels base.Set) error {
	channels = ch.ExpandingStar(channels)
	role.Name_ = name
	role.ExplicitChannels_ = ch.AtSequence(channels, 1)
	return role.validate()
}