Example #1
0
func (db *mongoDatabase) Validate(f *Filter, c *Cred) (Perm, error) {
	log := db.log().New("Validate")

	if err := f.Valid(); err != nil {
		return nil, err
	}

	if f.Matches(c.Perm) {
		return c.Perm, nil
	}

	perm := extractMongoPerm(f, c)

	log.Debug("extracted perm: %#v", perm)

	if err := db.fetchModels(f, perm); err != nil {
		// Return partially constructed perm to allow SetCreds
		// do alidate-or-create operation.
		return perm, err
	}

	belongs := modelhelper.Selector{
		"targetId": perm.CredModel.Id,
		"sourceId": bson.M{
			"$in": perm.CredGroups,
		},
		"as": bson.M{"$in": perm.Roles},
	}

	log.Debug("testing relationship for %+v", belongs)

	if count, err := modelhelper.RelationshipCount(belongs); err != nil || count == 0 {
		if err == nil {
			err = fmt.Errorf("user %q has no access to %q credential", f.Username, c.Ident)
		}

		return nil, models.ResError(err, "jRelationship")
	}

	if c.Perm == nil {
		c.Perm = perm
	}

	return perm, nil
}
Example #2
0
// BuildCredentials fetches credential details for current b.Stack from MongoDB.
//
// When nil error is returned, the b.Koding and  b.Credentials fields are non-nil.
//
// TODO(rjeczalik): Replace with *credential.Client
func (b *Builder) BuildCredentials(method, username, groupname string, identifiers []string) error {
	// fetch jaccount from username
	account, err := modelhelper.GetAccount(username)
	if err != nil {
		return models.ResError(err, "jAccount")
	}

	// fetch jUser from username
	user, err := modelhelper.GetUser(username)
	if err != nil {
		return models.ResError(err, "jUser")
	}

	kodingMeta := &KodingMeta{
		Email:     user.Email,
		Username:  user.Name,
		Nickname:  account.Profile.Nickname,
		Firstname: account.Profile.FirstName,
		Lastname:  account.Profile.LastName,
		Hash:      account.Profile.Hash,
	}

	if b.StackTemplate != nil {
		kodingMeta.TemplateID = b.StackTemplate.Id.Hex()
	}

	if b.Stack != nil {
		kodingMeta.StackID = b.Stack.Stack.Id.Hex()
		kodingMeta.TemplateID = b.Stack.Stack.BaseStackId.Hex()
	}

	groupIDs := []bson.ObjectId{account.Id}

	if groupname != "" {
		// fetch jGroup from group slug name
		group, err := modelhelper.GetGroup(groupname)
		if err != nil {
			return models.ResError(err, "jGroup")
		}

		// validate if username belongs to groupnam
		selector := modelhelper.Selector{
			"targetId": account.Id,
			"sourceId": group.Id,
			"as": bson.M{
				"$in": []string{"member"},
			},
		}

		count, err := modelhelper.RelationshipCount(selector)
		if err != nil || count == 0 {
			return fmt.Errorf("username '%s' does not belong to group '%s'", username, groupname)
		}

		kodingMeta.Title = group.Title
		kodingMeta.Slug = group.Slug

		groupIDs = append(groupIDs, group.Id)
	}

	// 2- fetch credential from identifiers via args
	credentials, err := modelhelper.GetCredentialsFromIdentifiers(identifiers...)
	if err != nil {
		return models.ResError(err, "jCredential")
	}

	credentialTitles := make(map[string]string, len(credentials))
	for _, cred := range credentials {
		credentialTitles[cred.Identifier] = cred.Title
	}

	// 3- count relationship with credential id and jaccount id as user or
	// owner. Any non valid credentials will be discarded
	validKeys := make(map[string]string, len(credentials))

	permittedTargets, ok := credPermissions[method]
	if !ok {
		return fmt.Errorf("no permission data available for method '%s'", method)
	}

	for _, cred := range credentials {
		selector := modelhelper.Selector{
			"targetId": cred.Id,
			"sourceId": bson.M{
				"$in": groupIDs,
			},
			"as": bson.M{"$in": permittedTargets},
		}

		count, err := modelhelper.RelationshipCount(selector)
		if err != nil {
			return models.ResError(err, "jRelationship")
		}
		if count == 0 {
			return fmt.Errorf("credential with identifier '%s' is not validated: %v", cred.Identifier, err)
		}

		validKeys[cred.Identifier] = cred.Provider
	}

	// 5- return list of keys.
	b.Koding = &stack.Credential{
		Provider:   "koding",
		Credential: kodingMeta,
	}

	creds := make([]*stack.Credential, 0, len(validKeys))

	for ident, provider := range validKeys {
		creds = append(creds, &stack.Credential{
			Title:      credentialTitles[ident],
			Provider:   provider,
			Identifier: ident,
		})
	}

	if err := b.FetchCredentials(username, creds...); err != nil {
		// TODO(rjeczalik): add *NotFoundError support to CredStore
		return models.ResError(err, "jCredentialData")
	}

	b.Credentials = append(b.Credentials, creds...)

	for i, cred := range b.Credentials {
		b.Log.Debug("Built credential #%d: %# v (%+v, %+v)", i, cred, cred.Credential, cred.Bootstrap)
	}

	return nil
}
Example #3
0
func (db *mongoDatabase) fetchModels(f *Filter, perm *MongoPerm) (err error) {
	log := db.Log.New("fetchModels")

	if perm.AccModel == nil {
		log.Debug("fetching %q account", f.Username)

		perm.AccModel, err = modelhelper.GetAccount(f.Username)
		if err != nil {
			return models.ResError(err, "jAccount")
		}

		perm.CredGroups = append(perm.CredGroups, perm.AccModel.Id)
	}

	if perm.UserModel == nil {
		log.Debug("fetching %q user", f.Username)

		perm.UserModel, err = modelhelper.GetUser(f.Username)
		if err != nil {
			return models.ResError(err, "jUser")
		}
	}

	if f.Teamname != "" {
		if perm.TeamModel == nil {
			log.Debug("fetching %q team", f.Teamname)

			perm.TeamModel, err = modelhelper.GetGroup(f.Teamname)
			if err != nil {
				return models.ResError(err, "jGroup")
			}

			perm.CredGroups = append(perm.CredGroups, perm.TeamModel.Id)
		}

		if !perm.Member {
			belongs := modelhelper.Selector{
				"targetId": perm.AccModel.Id,
				"sourceId": perm.TeamModel.Id,
				"as":       "member",
			}

			log.Debug("testing relationship for %+v", belongs)

			if count, err := modelhelper.RelationshipCount(belongs); err != nil || count == 0 {
				if err == nil {
					err = fmt.Errorf("user %q does not belong to %q group", f.Username, f.Teamname)
				}

				return models.ResError(err, "jRelationship")
			}

			perm.Member = true
		}
	}

	if perm.CredModel == nil && f.Ident != "" {
		log.Debug("fetching %q credential", f.Ident)

		perm.CredModel, err = modelhelper.GetCredential(f.Ident)
		if err != nil {
			return models.ResError(err, "jCredential")
		}
	}

	return nil
}