Ejemplo n.º 1
0
func (user *userImpl) FilterToAvailableChannels(channels base.Set) ch.TimedSet {
	output := ch.TimedSet{}
	for channel, _ := range channels {
		if channel == "*" {
			return user.InheritedChannels().Copy()
		}
		output.AddChannel(channel, user.CanSeeChannelSince(channel))
	}
	return output
}
Ejemplo n.º 2
0
// Recomputes the set of roles a User has been granted access to by sync() functions.
// This is part of the ChannelComputer interface defined by the Authenticator.
func (context *DatabaseContext) ComputeRolesForUser(user auth.User) (channels.TimedSet, error) {
	var vres struct {
		Rows []struct {
			Value channels.TimedSet
		}
	}

	opts := map[string]interface{}{"stale": false, "key": user.Name()}
	if verr := context.Bucket.ViewCustom("sync_gateway", "role_access", opts, &vres); verr != nil {
		return nil, verr
	}
	// Merge the TimedSets from the view result:
	var result channels.TimedSet
	for _, row := range vres.Rows {
		if result == nil {
			result = row.Value
		} else {
			result.Add(row.Value)
		}
	}
	return result, nil
}
Ejemplo n.º 3
0
func (auth *Authenticator) rebuildRoles(user User) error {
	var roles ch.TimedSet
	if auth.channelComputer != nil {
		var err error
		roles, err = auth.channelComputer.ComputeRolesForUser(user)
		if err != nil {
			base.Warn("channelComputer.ComputeRolesForUser failed on user %s: %v", user.Name(), err)
			return err
		}
	}
	if roles == nil {
		roles = ch.TimedSet{} // it mustn't be nil; nil means it's unknown
	}

	if explicit := user.ExplicitRoles(); explicit != nil {
		roles.Add(explicit)
	}

	base.LogTo("Access", "Computed roles for %q: %s", user.Name(), roles)
	user.setRolesSince(roles)
	return nil
}
Ejemplo n.º 4
0
// Recomputes the set of channels a User/Role has been granted access to by sync() functions.
// This is part of the ChannelComputer interface defined by the Authenticator.
func (context *DatabaseContext) ComputeChannelsForPrincipal(princ auth.Principal) (channels.TimedSet, error) {
	key := princ.Name()
	if _, ok := princ.(auth.User); !ok {
		key = "role:" + key // Roles are identified in access view by a "role:" prefix
	}

	var vres struct {
		Rows []struct {
			Value channels.TimedSet
		}
	}

	opts := map[string]interface{}{"stale": false, "key": key}
	if verr := context.Bucket.ViewCustom("sync_gateway", "access", opts, &vres); verr != nil {
		return nil, verr
	}
	channelSet := channels.TimedSet{}
	for _, row := range vres.Rows {
		channelSet.Add(row.Value)
	}
	return channelSet, nil
}
Ejemplo n.º 5
0
// HTTP handler for _all_docs
func (h *handler) handleAllDocs() error {
	// http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API
	includeDocs := h.getBoolQuery("include_docs")
	includeChannels := h.getBoolQuery("channels")
	includeAccess := h.getBoolQuery("access") && h.user == nil
	includeRevs := h.getBoolQuery("revs")
	includeSeqs := h.getBoolQuery("update_seq")

	// Get the doc IDs if this is a POST request:
	var explicitDocIDs []string
	if h.rq.Method == "POST" {
		input, err := h.readJSON()
		if err == nil {
			keys, ok := input["keys"].([]interface{})
			explicitDocIDs = make([]string, len(keys))
			for i := 0; i < len(keys); i++ {
				if explicitDocIDs[i], ok = keys[i].(string); !ok {
					break
				}
			}
			if !ok {
				err = base.HTTPErrorf(http.StatusBadRequest, "Bad/missing keys")
			}
		}
	}

	// Get the set of channels the user has access to; nil if user is admin or has access to "*"
	var availableChannels channels.TimedSet
	if h.user != nil {
		availableChannels = h.user.InheritedChannels()
		if availableChannels == nil {
			panic("no channels for user?")
		}
		if availableChannels.Contains("*") {
			availableChannels = nil
		}
	}

	// Subroutines that filter a channel list down to the ones that the user has access to:
	filterChannels := func(channels []string) []string {
		if availableChannels == nil {
			return channels
		}
		dst := 0
		for _, ch := range channels {
			if availableChannels.Contains(ch) {
				channels[dst] = ch
				dst++
			}
		}
		if dst == 0 {
			return nil
		}
		return channels[0:dst]
	}
	filterChannelSet := func(channelMap channels.ChannelMap) []string {
		var result []string
		for ch, _ := range channelMap {
			if availableChannels == nil || availableChannels.Contains(ch) {
				result = append(result, ch)
			}
		}
		return result
	}

	// Subroutine that writes a response entry for a document:
	totalRows := 0
	writeDoc := func(doc db.IDAndRev, channels []string) error {
		type allDocsRowValue struct {
			Rev      string              `json:"rev"`
			Channels []string            `json:"channels,omitempty"`
			Access   map[string]base.Set `json:"access,omitempty"` // for admins only
		}
		type allDocsRow struct {
			ID        string          `json:"id"`
			Key       string          `json:"key"`
			Value     allDocsRowValue `json:"value"`
			Doc       db.Body         `json:"doc,omitempty"`
			UpdateSeq uint64          `json:"update_seq,omitempty"`
		}

		row := allDocsRow{ID: doc.DocID, Key: doc.DocID}

		// Filter channels to ones available to user, and bail out if inaccessible:
		if explicitDocIDs == nil {
			if channels = filterChannels(channels); channels == nil {
				return nil
			}
		}

		if explicitDocIDs != nil || includeDocs || includeAccess {
			// Fetch the document body and other metadata that lives with it:
			body, channelSet, access, roleAccess, err := h.db.GetRevAndChannels(doc.DocID, doc.RevID, includeRevs)
			if err != nil || body["_removed"] != nil {
				return nil
			}
			if explicitDocIDs != nil {
				if channels = filterChannelSet(channelSet); channels == nil {
					return nil
				}
				doc.RevID = body["_rev"].(string)
			}
			if includeDocs {
				row.Doc = body
			}
			if includeAccess && (access != nil || roleAccess != nil) {
				row.Value.Access = map[string]base.Set{}
				for userName, channels := range access {
					row.Value.Access[userName] = channels.AsSet()
				}
				for roleName, channels := range roleAccess {
					row.Value.Access["role:"+roleName] = channels.AsSet()
				}
			}
		}

		row.Value.Rev = doc.RevID
		if includeSeqs {
			row.UpdateSeq = doc.Sequence
		}
		if includeChannels {
			row.Value.Channels = channels
		}

		if totalRows > 0 {
			h.response.Write([]byte(",\n"))
		}
		totalRows++
		h.addJSON(row)
		return nil
	}

	// Now it's time to actually write the response!
	lastSeq, _ := h.db.LastSequence()
	h.setHeader("Content-Type", "application/json")
	h.response.Write([]byte(`{"rows":[` + "\n"))

	if explicitDocIDs != nil {
		for _, docID := range explicitDocIDs {
			writeDoc(db.IDAndRev{DocID: docID, RevID: "", Sequence: 0}, nil)
		}
	} else {
		if err := h.db.ForEachDocID(writeDoc); err != nil {
			return err
		}
	}

	h.response.Write([]byte(fmt.Sprintf("],\n"+`"total_rows":%d,"update_seq":%d}`,
		totalRows, lastSeq)))
	return nil
}