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 }
// 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 }
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 }