mirror of
https://github.com/paralus/paralus.git
synced 2026-08-24 15:47:19 +00:00
Merge pull request #134 from RafayLabs/idp-groups-and-updating-same
Add IdP groups in Identities table
This commit is contained in:
@@ -40,6 +40,13 @@
|
||||
"via": "email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"idp_groups": {
|
||||
"title": "IDP groups",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -202,6 +202,17 @@
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpGroups",
|
||||
"description": "Idp Group. Idp Groups the user belongs to",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.emailVerified",
|
||||
"description": "EmailVerified. Flag to show if the email of the user was verified",
|
||||
@@ -412,6 +423,17 @@
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpGroups",
|
||||
"description": "Idp Group. Idp Groups the user belongs to",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.emailVerified",
|
||||
"description": "EmailVerified. Flag to show if the email of the user was verified",
|
||||
@@ -762,6 +784,17 @@
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpGroups",
|
||||
"description": "Idp Group. Idp Groups the user belongs to",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
},
|
||||
{
|
||||
"name": "spec.emailVerified",
|
||||
"description": "EmailVerified. Flag to show if the email of the user was verified",
|
||||
@@ -1478,6 +1511,15 @@
|
||||
"title": "Group",
|
||||
"readOnly": true
|
||||
},
|
||||
"idpGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Idp Groups the user belongs to",
|
||||
"title": "Idp Group",
|
||||
"readOnly": true
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1571,6 +1613,15 @@
|
||||
"title": "Group",
|
||||
"readOnly": true
|
||||
},
|
||||
"idpGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Idp Groups the user belongs to",
|
||||
"title": "Idp Group",
|
||||
"readOnly": true
|
||||
},
|
||||
"projectNamespaceRoles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -292,6 +292,19 @@ func GetByTraits(ctx context.Context, db bun.IDB, name string, entity interface{
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
func GetByTraitsFull(ctx context.Context, db bun.IDB, name string, entity interface{}) (interface{}, error) {
|
||||
err := db.NewSelect().Model(entity).
|
||||
Where("traits ->> 'email' = ?", name).
|
||||
Relation("IdentityCredential").
|
||||
Relation("IdentityCredential.IdentityCredentialType").
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
func GetIdByTraits(ctx context.Context, db bun.IDB, name string, entity interface{}) (interface{}, error) {
|
||||
// TODO: better name and possibly pass in trait name
|
||||
err := db.NewSelect().Column("id").Model(entity).
|
||||
|
||||
@@ -9,6 +9,19 @@ import (
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func GetUserType(ctx context.Context, db bun.IDB, id uuid.UUID) (string, error) {
|
||||
var user = models.KratosIdentities{}
|
||||
q := db.NewSelect().Model(&user)
|
||||
q.Relation("IdentityCredential").
|
||||
Relation("IdentityCredential.IdentityCredentialType")
|
||||
q.Where("id = ?", id)
|
||||
err := q.Scan(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return user.IdentityCredential.IdentityCredentialType.Name, nil
|
||||
}
|
||||
|
||||
func GetGroups(ctx context.Context, db bun.IDB, id uuid.UUID) ([]models.Group, error) {
|
||||
var entities = []models.Group{}
|
||||
err := db.NewSelect().Model(&entities).
|
||||
|
||||
@@ -431,11 +431,11 @@ func run() {
|
||||
go runRelayPeerRPC(&wg, ctx)
|
||||
go runDebug(&wg, ctx)
|
||||
go runEventHandlers(&wg, ctx)
|
||||
go runIdpGroupSync(&wg, ctx)
|
||||
|
||||
<-ctx.Done()
|
||||
_log.Infow("shutting down, waiting for children to die")
|
||||
wg.Wait()
|
||||
|
||||
}
|
||||
|
||||
func runAPI(wg *sync.WaitGroup, ctx context.Context) {
|
||||
@@ -675,6 +675,34 @@ func runDebug(wg *sync.WaitGroup, ctx context.Context) {
|
||||
s.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func runIdpGroupSync(wg *sync.WaitGroup, ctx context.Context) {
|
||||
defer wg.Done()
|
||||
channel := "identities:changed"
|
||||
ln := pgdriver.NewListener(db)
|
||||
listen:
|
||||
if err := ln.Listen(ctx, channel); err != nil {
|
||||
_log.Errorf("error listening for notification on channel %q: %s", channel, err)
|
||||
time.Sleep(2 * time.Second)
|
||||
goto listen
|
||||
}
|
||||
|
||||
_log.Infof("Listening for notifications on channel %q", channel)
|
||||
for n := range ln.Channel() {
|
||||
_log.Info("A identities table notification received")
|
||||
splitPl := strings.SplitN(n.Payload, ",", 3)
|
||||
op := splitPl[0]
|
||||
id := splitPl[1]
|
||||
traits := splitPl[2]
|
||||
err := us.UpdateIdpUserGroupPolicy(ctx, op, id, traits)
|
||||
if err != nil {
|
||||
_log.Warnf("Failed updating policy for IDP user with id %s: %s", id, err)
|
||||
} else {
|
||||
_log.Infof("Policies are updated successfully for IDP user with id %s", id)
|
||||
}
|
||||
}
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func main() {
|
||||
setup()
|
||||
run()
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
DROP FUNCTION IF EXISTS identities_after_change() CASCADE;
|
||||
DROP TRIGGER IF EXISTS trigger_identities_update ON identities;
|
||||
@@ -0,0 +1,23 @@
|
||||
CREATE OR REPLACE FUNCTION identities_after_change() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
row RECORD;
|
||||
output TEXT;
|
||||
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
row = OLD;
|
||||
ELSE
|
||||
row = NEW;
|
||||
END IF;
|
||||
|
||||
output = TG_OP || ',' || row.id || ',' || row.traits;
|
||||
PERFORM pg_notify('identities:changed',output);
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_identities_update
|
||||
AFTER INSERT OR UPDATE OR DELETE
|
||||
ON identities
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE identities_after_change();
|
||||
@@ -145,6 +145,13 @@ func addUserFetchExpectation(mock sqlmock.Sqlmock) string {
|
||||
return uid
|
||||
}
|
||||
|
||||
func addUserFullFetchExpectation(mock sqlmock.Sqlmock) string {
|
||||
uid := uuid.New().String()
|
||||
mock.ExpectQuery(`SELECT "identities"."id", "identities"."schema_id", "identities"."traits", "identities"."created_at", "identities"."updated_at", "identities"."state", "identities"."state_changed_at", "identities"."nid", "identity_credential"."id" AS "identity_credential__id", "identity_credential"."identity_id" AS "identity_credential__identity_id", "identity_credential"."identity_credential_type_id" AS "identity_credential__identity_credential_type_id", "identity_credential__identity_credential_type"."id" AS "identity_credential__identity_credential_type__id", "identity_credential__identity_credential_type"."name" AS "identity_credential__identity_credential_type__name" FROM "identities" LEFT JOIN "identity_credentials" AS "identity_credential" ON ."identity_credential"."identity_id" = "identities"."id". LEFT JOIN "identity_credential_types" AS "identity_credential__identity_credential_type" ON ."identity_credential__identity_credential_type"."id" = "identity_credential"."identity_credential_type_id". WHERE .traits ->> 'email' = 'user-` + uid + `'.`).
|
||||
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id", "traits", "identity_credential__identity_credential_type__name"}).AddRow(uid, []byte(`{"email":"user-`+uid+`", "first_name": "John", "last_name": "Doe", "description": "The OG user."}`), "password"))
|
||||
return uid
|
||||
}
|
||||
|
||||
func addUsersGroupFetchExpectation(mock sqlmock.Sqlmock, user string) string {
|
||||
uid := uuid.New().String()
|
||||
mock.ExpectQuery(`SELECT "group"."id".* FROM "authsrv_group" AS "group" JOIN authsrv_groupaccount ON authsrv_groupaccount.group_id="group".id WHERE .authsrv_groupaccount.account_id = '` + user + `'`).
|
||||
|
||||
+143
-15
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -20,7 +21,6 @@ import (
|
||||
"github.com/RafayLabs/rcloud-base/pkg/utils"
|
||||
userrpcv3 "github.com/RafayLabs/rcloud-base/proto/rpc/user"
|
||||
authzv1 "github.com/RafayLabs/rcloud-base/proto/types/authz"
|
||||
commonv3 "github.com/RafayLabs/rcloud-base/proto/types/commonpb/v3"
|
||||
v3 "github.com/RafayLabs/rcloud-base/proto/types/commonpb/v3"
|
||||
userv3 "github.com/RafayLabs/rcloud-base/proto/types/userpb/v3"
|
||||
)
|
||||
@@ -48,6 +48,8 @@ type UserService interface {
|
||||
List(context.Context, ...query.Option) (*userv3.UserList, error)
|
||||
// retrieve the cli config for the logged in user
|
||||
RetrieveCliConfig(ctx context.Context, req *userrpcv3.ApiKeyRequest) (*common.CliConfigDownloadData, error)
|
||||
// Update UserGroup casbin for OIdC/Idp users
|
||||
UpdateIdpUserGroupPolicy(context.Context, string, string, string) error
|
||||
}
|
||||
|
||||
type userService struct {
|
||||
@@ -65,6 +67,7 @@ type userTraits struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
Description string
|
||||
IdpGroups []string `json:"idp_groups"`
|
||||
}
|
||||
|
||||
// FIXME: find a better way to do this
|
||||
@@ -97,11 +100,23 @@ func getUserTraits(traits map[string]interface{}) userTraits {
|
||||
if !ok {
|
||||
desc = ""
|
||||
}
|
||||
|
||||
igStr := []string{}
|
||||
ig, ok := traits["idp_groups"]
|
||||
if ok {
|
||||
igList := ig.([]interface{})
|
||||
igStr = make([]string, len(igList))
|
||||
for i, g := range igList {
|
||||
igStr[i] = g.(string)
|
||||
}
|
||||
}
|
||||
|
||||
return userTraits{
|
||||
Email: email.(string),
|
||||
FirstName: fname.(string),
|
||||
LastName: lname.(string),
|
||||
Description: desc.(string),
|
||||
IdpGroups: igStr,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +266,8 @@ func (s *userService) createGroupAccountRelations(ctx context.Context, db bun.ID
|
||||
var grpaccs []models.GroupAccount
|
||||
var ugs []*authzv1.UserGroup
|
||||
var ids []uuid.UUID
|
||||
|
||||
// Add managed groups
|
||||
for _, group := range utils.Unique(usr.GetSpec().GetGroups()) {
|
||||
// FIXME: do combined lookup
|
||||
entity, err := dao.GetByName(ctx, s.db, group, &models.Group{})
|
||||
@@ -274,6 +291,35 @@ func (s *userService) createGroupAccountRelations(ctx context.Context, db bun.ID
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Add idp groups
|
||||
for _, group := range utils.Unique(usr.GetSpec().GetIdpGroups()) {
|
||||
entity, err := dao.GetByName(ctx, s.db, group, &models.Group{})
|
||||
if err != nil {
|
||||
// It is possible that a group that has been mapped via
|
||||
// Idp is not available in our system. As of now, we
|
||||
// ignore such cases, later when the group becomes
|
||||
// available we will associate them to the group.
|
||||
continue
|
||||
}
|
||||
if grp, ok := entity.(*models.Group); ok {
|
||||
grp := models.GroupAccount{
|
||||
CreatedAt: time.Now(),
|
||||
ModifiedAt: time.Now(),
|
||||
Trash: false,
|
||||
AccountId: userId,
|
||||
GroupId: grp.ID,
|
||||
Active: true,
|
||||
}
|
||||
ids = append(ids, grp.ID)
|
||||
grpaccs = append(grpaccs, grp)
|
||||
ugs = append(ugs, &authzv1.UserGroup{
|
||||
Grp: "g:" + group,
|
||||
User: "u:" + usr.Metadata.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(grpaccs) == 0 {
|
||||
return usr, []uuid.UUID{}, nil
|
||||
}
|
||||
@@ -298,7 +344,7 @@ func (s *userService) deleteGroupAccountRelations(ctx context.Context, db bun.ID
|
||||
return &userv3.User{}, ids, fmt.Errorf("unable to delete user; %v", err)
|
||||
}
|
||||
|
||||
_, err = s.azc.DeleteUserGroups(ctx, &authzv1.UserGroup{Grp: "u:" + usr.GetMetadata().GetName()})
|
||||
_, err = s.azc.DeleteUserGroups(ctx, &authzv1.UserGroup{User: "u:" + usr.GetMetadata().GetName()})
|
||||
if err != nil {
|
||||
return &userv3.User{}, ids, fmt.Errorf("unable to delete group-user relations from authz; %v", err)
|
||||
}
|
||||
@@ -331,6 +377,9 @@ func (s *userService) Create(ctx context.Context, user *userv3.User) (*userv3.Us
|
||||
return nil, fmt.Errorf("unable to get partner and org id")
|
||||
}
|
||||
|
||||
// we should not be taking idp groups as input on local user creation
|
||||
user.Spec.IdpGroups = []string{}
|
||||
|
||||
// Kratos checks if the user is already available
|
||||
id, err := s.ap.Create(ctx, map[string]interface{}{
|
||||
"email": user.GetMetadata().GetName(), // can be just username for API access
|
||||
@@ -380,6 +429,7 @@ func (s *userService) Create(ctx context.Context, user *userv3.User) (*userv3.Us
|
||||
|
||||
func (s *userService) identitiesModelToUser(ctx context.Context, db bun.IDB, user *userv3.User, usr *models.KratosIdentities) (*userv3.User, error) {
|
||||
traits := getUserTraits(usr.Traits)
|
||||
idpGroups := traits.IdpGroups
|
||||
groups, err := dao.GetGroups(ctx, db, usr.ID)
|
||||
if err != nil {
|
||||
return &userv3.User{}, err
|
||||
@@ -387,14 +437,18 @@ func (s *userService) identitiesModelToUser(ctx context.Context, db bun.IDB, use
|
||||
groupNames := []string{}
|
||||
allAssociatedRoles := []*userv3.ProjectNamespaceRole{}
|
||||
for _, g := range groups {
|
||||
groupNames = append(groupNames, g.Name)
|
||||
|
||||
//group roles
|
||||
// group roles (both idp and non idp)
|
||||
groupRoles, err := dao.GetGroupRoles(ctx, db, g.ID)
|
||||
if err != nil {
|
||||
return &userv3.User{}, err
|
||||
}
|
||||
allAssociatedRoles = append(allAssociatedRoles, groupRoles...)
|
||||
|
||||
// idp groups will be available in both traits and groups and
|
||||
// needs to be filetered out
|
||||
if !utils.Contains(idpGroups, g.Name) {
|
||||
groupNames = append(groupNames, g.Name)
|
||||
}
|
||||
}
|
||||
|
||||
labels := make(map[string]string)
|
||||
@@ -417,6 +471,7 @@ func (s *userService) identitiesModelToUser(ctx context.Context, db bun.IDB, use
|
||||
FirstName: traits.FirstName,
|
||||
LastName: traits.LastName,
|
||||
Groups: groupNames,
|
||||
IdpGroups: idpGroups,
|
||||
ProjectNamespaceRoles: roles,
|
||||
}
|
||||
|
||||
@@ -579,7 +634,7 @@ func (s *userService) deleteUserRoleRelations(ctx context.Context, db bun.IDB, u
|
||||
|
||||
func (s *userService) Update(ctx context.Context, user *userv3.User) (*userv3.User, error) {
|
||||
name := user.GetMetadata().GetName()
|
||||
entity, err := dao.GetIdByTraits(ctx, s.db, name, &models.KratosIdentities{})
|
||||
entity, err := dao.GetByTraitsFull(ctx, s.db, name, &models.KratosIdentities{})
|
||||
if err != nil {
|
||||
return &userv3.User{}, fmt.Errorf("no user found with name '%v'", name)
|
||||
}
|
||||
@@ -589,14 +644,18 @@ func (s *userService) Update(ctx context.Context, user *userv3.User) (*userv3.Us
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get partner and org id")
|
||||
}
|
||||
err = s.ap.Update(ctx, usr.ID.String(), map[string]interface{}{
|
||||
"email": user.GetMetadata().GetName(),
|
||||
"first_name": user.GetSpec().GetFirstName(),
|
||||
"last_name": user.GetSpec().GetLastName(),
|
||||
"description": user.GetMetadata().GetDescription(),
|
||||
})
|
||||
if err != nil {
|
||||
return &userv3.User{}, err
|
||||
|
||||
if usr.IdentityCredential.IdentityCredentialType.Name == "password" {
|
||||
// Don't update details for non local(IDP) users
|
||||
err = s.ap.Update(ctx, usr.ID.String(), map[string]interface{}{
|
||||
"email": user.GetMetadata().GetName(),
|
||||
"first_name": user.GetSpec().GetFirstName(),
|
||||
"last_name": user.GetSpec().GetLastName(),
|
||||
"description": user.GetMetadata().GetDescription(),
|
||||
})
|
||||
if err != nil {
|
||||
return &userv3.User{}, err
|
||||
}
|
||||
}
|
||||
|
||||
tx, err := s.db.BeginTx(ctx, &sql.TxOptions{})
|
||||
@@ -622,6 +681,8 @@ func (s *userService) Update(ctx context.Context, user *userv3.User) (*userv3.Us
|
||||
return &userv3.User{}, err
|
||||
}
|
||||
|
||||
// Add idp groups to user so that it gets added on update
|
||||
user.Spec.IdpGroups = getUserTraits(usr.Traits).IdpGroups
|
||||
user, groupsAfter, err := s.createGroupAccountRelations(ctx, tx, usr.ID, user)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
@@ -698,7 +759,7 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U
|
||||
},
|
||||
}
|
||||
|
||||
queryOptions := commonv3.QueryOptions{}
|
||||
queryOptions := v3.QueryOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(&queryOptions)
|
||||
}
|
||||
@@ -850,3 +911,70 @@ func (s *userService) RetrieveCliConfig(ctx context.Context, req *userrpcv3.ApiK
|
||||
return cliConfig, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *userService) UpdateIdpUserGroupPolicy(ctx context.Context, op, id, traits string) error {
|
||||
var (
|
||||
userInfo userTraits
|
||||
user *userv3.User
|
||||
userUUID uuid.UUID
|
||||
)
|
||||
userUUID, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing id %s: %s", id, err)
|
||||
}
|
||||
err = json.Unmarshal([]byte(traits), &userInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encountered error unmarshing payload to userInfo: %s", err)
|
||||
}
|
||||
// TODO: Revisit to only run by IDP users and not by any other
|
||||
// user
|
||||
if len(userInfo.IdpGroups) == 0 {
|
||||
return fmt.Errorf("Empty idp groups for user with id %s", id)
|
||||
}
|
||||
|
||||
// Get existing user group so that the update does not wipe them out
|
||||
userGroups, err := dao.GetGroups(ctx, s.db, userUUID)
|
||||
ugn := []string{}
|
||||
for _, g := range userGroups {
|
||||
if !utils.Contains(userInfo.IdpGroups, g.Name) {
|
||||
ugn = append(ugn, g.Name)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Empty to find existing groups for user with id %s", id)
|
||||
}
|
||||
user = &userv3.User{
|
||||
Metadata: &v3.Metadata{
|
||||
Name: userInfo.Email,
|
||||
},
|
||||
Spec: &userv3.UserSpec{
|
||||
FirstName: userInfo.FirstName,
|
||||
LastName: userInfo.LastName,
|
||||
Groups: ugn,
|
||||
IdpGroups: userInfo.IdpGroups,
|
||||
},
|
||||
}
|
||||
switch op {
|
||||
case "DELETE":
|
||||
_, _, err = s.deleteGroupAccountRelations(ctx, s.db, userUUID, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "UPDATE":
|
||||
// delete old policies
|
||||
_, _, err = s.deleteGroupAccountRelations(ctx, s.db, userUUID, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create new policies
|
||||
fallthrough
|
||||
case "INSERT":
|
||||
_, _, err = s.createGroupAccountRelations(ctx, s.db, userUUID, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Unsupported %s operation in payload", op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
us := NewUserService(ap, db, &mazc, nil, common.CliConfigDownloadData{}, getLogger(), true)
|
||||
|
||||
// performing update
|
||||
uuuid := addUserIdFetchExpectation(mock)
|
||||
uuuid := addUserFullFetchExpectation(mock)
|
||||
puuid, ouuid := addParterOrgFetchExpectation(mock)
|
||||
mock.ExpectBegin()
|
||||
_ = addUserRoleMappingsUpdateExpectation(mock, uuuid)
|
||||
@@ -197,6 +197,90 @@ func TestUpdateUser(t *testing.T) {
|
||||
performBasicAuthProviderChecks(t, *ap, 0, 1, 0, 0)
|
||||
}
|
||||
|
||||
func TestUpdateUserWithGroup(t *testing.T) {
|
||||
db, mock := getDB(t)
|
||||
defer db.Close()
|
||||
|
||||
ap := &mockAuthProvider{}
|
||||
mazc := mockAuthzClient{}
|
||||
us := NewUserService(ap, db, &mazc, nil, common.CliConfigDownloadData{}, getLogger(), true)
|
||||
|
||||
// performing update
|
||||
uuuid := addUserFullFetchExpectation(mock)
|
||||
puuid, ouuid := addParterOrgFetchExpectation(mock)
|
||||
mock.ExpectBegin()
|
||||
_ = addUserRoleMappingsUpdateExpectation(mock, uuuid)
|
||||
addUserGroupMappingsUpdateExpectation(mock, uuuid)
|
||||
ruuid := addResourceRoleFetchExpectation(mock, "project")
|
||||
pruuid := addFetchExpectation(mock, "project")
|
||||
mock.ExpectQuery(`INSERT INTO "authsrv_projectaccountresourcerole"`).
|
||||
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(uuid.New().String()))
|
||||
addFetchExpectation(mock, "group")
|
||||
mock.ExpectQuery(`INSERT INTO "authsrv_groupaccount"`).
|
||||
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(uuid.New().String()))
|
||||
mock.ExpectCommit()
|
||||
|
||||
var ns int64 = 7
|
||||
user := &userv3.User{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "user-" + uuuid},
|
||||
Spec: &userv3.UserSpec{
|
||||
Groups: []string{"group"},
|
||||
ProjectNamespaceRoles: []*userv3.ProjectNamespaceRole{{Project: idnamea(pruuid, "project"), Namespace: &ns, Role: idname(ruuid, "role")}},
|
||||
},
|
||||
}
|
||||
user, err := us.Update(context.Background(), user)
|
||||
if err != nil {
|
||||
t.Fatal("could not create user:", err)
|
||||
}
|
||||
performUserBasicChecks(t, user, uuuid)
|
||||
if user.GetMetadata().GetName() != "user-"+uuuid {
|
||||
t.Errorf("expected name 'user-%v'; got '%v'", uuuid, user.GetMetadata().GetName())
|
||||
}
|
||||
performBasicAuthProviderChecks(t, *ap, 0, 1, 0, 0)
|
||||
}
|
||||
|
||||
func TestUpdateUserInvalid(t *testing.T) {
|
||||
db, mock := getDB(t)
|
||||
defer db.Close()
|
||||
|
||||
ap := &mockAuthProvider{}
|
||||
mazc := mockAuthzClient{}
|
||||
us := NewUserService(ap, db, &mazc, nil, common.CliConfigDownloadData{}, getLogger(), true)
|
||||
|
||||
// performing update
|
||||
uuuid := addUserFullFetchExpectation(mock)
|
||||
puuid, ouuid := addParterOrgFetchExpectation(mock)
|
||||
mock.ExpectBegin()
|
||||
_ = addUserRoleMappingsUpdateExpectation(mock, uuuid)
|
||||
addUserGroupMappingsUpdateExpectation(mock, uuuid)
|
||||
ruuid := addResourceRoleFetchExpectation(mock, "project")
|
||||
pruuid := addFetchExpectation(mock, "project")
|
||||
mock.ExpectQuery(`INSERT INTO "authsrv_projectaccountresourcerole"`).
|
||||
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(uuid.New().String()))
|
||||
mock.ExpectCommit()
|
||||
|
||||
var ns int64 = 7
|
||||
user := &userv3.User{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "user-" + uuuid},
|
||||
Spec: &userv3.UserSpec{
|
||||
IdpGroups: []string{"unnecessary"},
|
||||
ProjectNamespaceRoles: []*userv3.ProjectNamespaceRole{{Project: idnamea(pruuid, "project"), Namespace: &ns, Role: idname(ruuid, "role")}},
|
||||
},
|
||||
}
|
||||
user, err := us.Update(context.Background(), user)
|
||||
if err != nil {
|
||||
t.Fatal("could not create user:", err)
|
||||
}
|
||||
performUserBasicChecks(t, user, uuuid)
|
||||
if len(user.Spec.IdpGroups) != 0 {
|
||||
t.Errorf("Idp groups added to local user")
|
||||
}
|
||||
if user.GetMetadata().GetName() != "user-"+uuuid {
|
||||
t.Errorf("expected name 'user-%v'; got '%v'", uuuid, user.GetMetadata().GetName())
|
||||
}
|
||||
performBasicAuthProviderChecks(t, *ap, 0, 1, 0, 0)
|
||||
}
|
||||
|
||||
func TestUserGetByName(t *testing.T) {
|
||||
db, mock := getDB(t)
|
||||
defer db.Close()
|
||||
|
||||
@@ -111,9 +111,10 @@ type UserInfoSpec struct {
|
||||
LastName string `protobuf:"bytes,2,opt,name=lastName,proto3" json:"lastName,omitempty"`
|
||||
Phone string `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"`
|
||||
Groups []string `protobuf:"bytes,6,rep,name=groups,proto3" json:"groups,omitempty"`
|
||||
Permissions []*Permission `protobuf:"bytes,7,rep,name=permissions,proto3" json:"permissions,omitempty"`
|
||||
EmailVerified bool `protobuf:"varint,8,opt,name=emailVerified,proto3" json:"emailVerified,omitempty"`
|
||||
PhoneVerified bool `protobuf:"varint,9,opt,name=phoneVerified,proto3" json:"phoneVerified,omitempty"`
|
||||
IdpGroups []string `protobuf:"bytes,7,rep,name=idpGroups,proto3" json:"idpGroups,omitempty"`
|
||||
Permissions []*Permission `protobuf:"bytes,8,rep,name=permissions,proto3" json:"permissions,omitempty"`
|
||||
EmailVerified bool `protobuf:"varint,9,opt,name=emailVerified,proto3" json:"emailVerified,omitempty"`
|
||||
PhoneVerified bool `protobuf:"varint,10,opt,name=phoneVerified,proto3" json:"phoneVerified,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UserInfoSpec) Reset() {
|
||||
@@ -176,6 +177,13 @@ func (x *UserInfoSpec) GetGroups() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserInfoSpec) GetIdpGroups() []string {
|
||||
if x != nil {
|
||||
return x.IdpGroups
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserInfoSpec) GetPermissions() []*Permission {
|
||||
if x != nil {
|
||||
return x.Permissions
|
||||
@@ -286,10 +294,11 @@ type UserSpec struct {
|
||||
Phone string `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"`
|
||||
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Groups []string `protobuf:"bytes,6,rep,name=groups,proto3" json:"groups,omitempty"`
|
||||
ProjectNamespaceRoles []*ProjectNamespaceRole `protobuf:"bytes,7,rep,name=projectNamespaceRoles,proto3" json:"projectNamespaceRoles,omitempty"`
|
||||
EmailVerified bool `protobuf:"varint,8,opt,name=emailVerified,proto3" json:"emailVerified,omitempty"`
|
||||
PhoneVerified bool `protobuf:"varint,9,opt,name=phoneVerified,proto3" json:"phoneVerified,omitempty"`
|
||||
RecoveryUrl *string `protobuf:"bytes,10,opt,name=recoveryUrl,proto3,oneof" json:"recoveryUrl,omitempty"`
|
||||
IdpGroups []string `protobuf:"bytes,7,rep,name=idpGroups,proto3" json:"idpGroups,omitempty"`
|
||||
ProjectNamespaceRoles []*ProjectNamespaceRole `protobuf:"bytes,8,rep,name=projectNamespaceRoles,proto3" json:"projectNamespaceRoles,omitempty"`
|
||||
EmailVerified bool `protobuf:"varint,9,opt,name=emailVerified,proto3" json:"emailVerified,omitempty"`
|
||||
PhoneVerified bool `protobuf:"varint,10,opt,name=phoneVerified,proto3" json:"phoneVerified,omitempty"`
|
||||
RecoveryUrl *string `protobuf:"bytes,11,opt,name=recoveryUrl,proto3,oneof" json:"recoveryUrl,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UserSpec) Reset() {
|
||||
@@ -359,6 +368,13 @@ func (x *UserSpec) GetGroups() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserSpec) GetIdpGroups() []string {
|
||||
if x != nil {
|
||||
return x.IdpGroups
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserSpec) GetProjectNamespaceRoles() []*ProjectNamespaceRole {
|
||||
if x != nil {
|
||||
return x.ProjectNamespaceRoles
|
||||
@@ -566,7 +582,7 @@ var file_proto_types_userpb_v3_user_proto_rawDesc = []byte{
|
||||
0x0a, 0x3b, 0x2a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x32, 0x09, 0x55, 0x73,
|
||||
0x65, 0x72, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0xd2, 0x01, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0xd2, 0x01, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0xd2, 0x01, 0x08, 0x6d, 0x65,
|
||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xd2, 0x01, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xa2, 0x05,
|
||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xd2, 0x01, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xf2, 0x05,
|
||||
0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x70, 0x65, 0x63, 0x12, 0x44,
|
||||
0x0a, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x42, 0x26, 0x92, 0x41, 0x23, 0x2a, 0x09, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d,
|
||||
@@ -584,22 +600,27 @@ var file_proto_types_userpb_v3_user_proto_rawDesc = []byte{
|
||||
0x28, 0x09, 0x42, 0x28, 0x92, 0x41, 0x25, 0x2a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x32, 0x1a,
|
||||
0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20,
|
||||
0x62, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x40, 0x01, 0x52, 0x06, 0x67, 0x72,
|
||||
0x6f, 0x75, 0x70, 0x73, 0x12, 0x4e, 0x0a, 0x09, 0x69, 0x64, 0x70, 0x47, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x2a, 0x09, 0x49, 0x64,
|
||||
0x70, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x32, 0x1e, 0x49, 0x64, 0x70, 0x20, 0x47, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x62, 0x65, 0x6c,
|
||||
0x6f, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x40, 0x01, 0x52, 0x09, 0x69, 0x64, 0x70, 0x47, 0x72,
|
||||
0x6f, 0x75, 0x70, 0x73, 0x12, 0x71, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x61, 0x66, 0x61,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x61, 0x66, 0x61,
|
||||
0x79, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x33, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x2a,
|
||||
0x92, 0x41, 0x27, 0x2a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x32, 0x18, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x66, 0x6f,
|
||||
0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d,
|
||||
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x6e, 0x0a, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c,
|
||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x42, 0x48,
|
||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x48,
|
||||
0x92, 0x41, 0x45, 0x2a, 0x0d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x32, 0x32, 0x46, 0x6c, 0x61, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x68, 0x6f, 0x77,
|
||||
0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x6f, 0x66,
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65,
|
||||
0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x40, 0x01, 0x52, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x56,
|
||||
0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x71, 0x0a, 0x0d, 0x70, 0x68, 0x6f, 0x6e, 0x65,
|
||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x4b,
|
||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x4b,
|
||||
0x92, 0x41, 0x48, 0x2a, 0x0d, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x32, 0x35, 0x46, 0x6c, 0x61, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x68, 0x6f, 0x77,
|
||||
0x20, 0x69, 0x66, 0x20, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
|
||||
@@ -642,7 +663,7 @@ var file_proto_types_userpb_v3_user_proto_rawDesc = []byte{
|
||||
0x74, 0x75, 0x73, 0x3a, 0x37, 0x92, 0x41, 0x34, 0x0a, 0x32, 0x2a, 0x04, 0x55, 0x73, 0x65, 0x72,
|
||||
0x32, 0x04, 0x55, 0x73, 0x65, 0x72, 0xd2, 0x01, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0xd2, 0x01, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0xd2, 0x01, 0x08, 0x6d, 0x65, 0x74,
|
||||
0x61, 0x64, 0x61, 0x74, 0x61, 0xd2, 0x01, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x92, 0x07, 0x0a,
|
||||
0x61, 0x64, 0x61, 0x74, 0x61, 0xd2, 0x01, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xe2, 0x07, 0x0a,
|
||||
0x08, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x44, 0x0a, 0x09, 0x66, 0x69, 0x72,
|
||||
0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0x92, 0x41,
|
||||
0x23, 0x2a, 0x09, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x32, 0x16, 0x46, 0x69,
|
||||
@@ -664,8 +685,13 @@ var file_proto_types_userpb_v3_user_proto_rawDesc = []byte{
|
||||
0x92, 0x41, 0x25, 0x2a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x32, 0x1a, 0x47, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x62, 0x65, 0x6c, 0x6f,
|
||||
0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x40, 0x01, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73,
|
||||
0x12, 0x4e, 0x0a, 0x09, 0x69, 0x64, 0x70, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x07, 0x20,
|
||||
0x03, 0x28, 0x09, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x2a, 0x09, 0x49, 0x64, 0x70, 0x20, 0x47, 0x72,
|
||||
0x6f, 0x75, 0x70, 0x32, 0x1e, 0x49, 0x64, 0x70, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x62, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73,
|
||||
0x20, 0x74, 0x6f, 0x40, 0x01, 0x52, 0x09, 0x69, 0x64, 0x70, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73,
|
||||
0x12, 0xaf, 0x01, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x2d, 0x2e, 0x72, 0x61, 0x66, 0x61, 0x79, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x74, 0x79, 0x70,
|
||||
0x65, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x42,
|
||||
@@ -676,21 +702,21 @@ var file_proto_types_userpb_v3_user_proto_rawDesc = []byte{
|
||||
0x6e, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, 0x73, 0x65, 0x72, 0x52, 0x15, 0x70, 0x72, 0x6f,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x6f, 0x6c,
|
||||
0x65, 0x73, 0x12, 0x6e, 0x0a, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x42, 0x48, 0x92, 0x41, 0x45, 0x2a, 0x0d,
|
||||
0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x48, 0x92, 0x41, 0x45, 0x2a, 0x0d,
|
||||
0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x32, 0x32, 0x46,
|
||||
0x6c, 0x61, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x69, 0x66, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x75, 0x73, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65,
|
||||
0x64, 0x40, 0x01, 0x52, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x12, 0x71, 0x0a, 0x0d, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x2a, 0x0d,
|
||||
0x69, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x2a, 0x0d,
|
||||
0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x32, 0x35, 0x46,
|
||||
0x6c, 0x61, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x69, 0x66, 0x20, 0x70,
|
||||
0x68, 0x6f, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x69,
|
||||
0x66, 0x69, 0x65, 0x64, 0x40, 0x01, 0x52, 0x0d, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72,
|
||||
0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x6b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72,
|
||||
0x79, 0x55, 0x72, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x44, 0x92, 0x41, 0x41, 0x2a,
|
||||
0x79, 0x55, 0x72, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x44, 0x92, 0x41, 0x41, 0x2a,
|
||||
0x0c, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x20, 0x55, 0x72, 0x6c, 0x32, 0x2f, 0x49,
|
||||
0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x20, 0x55, 0x52,
|
||||
0x4c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72,
|
||||
|
||||
@@ -75,18 +75,24 @@ message UserInfoSpec {
|
||||
description : "Groups the user belongs to"
|
||||
read_only : true,
|
||||
} ];
|
||||
repeated rafay.dev.types.user.v3.Permission permissions = 7
|
||||
repeated string idpGroups = 7
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Idp Group"
|
||||
description : "Idp Groups the user belongs to"
|
||||
read_only : true,
|
||||
} ];
|
||||
repeated rafay.dev.types.user.v3.Permission permissions = 8
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Permissions"
|
||||
description : "Permissions for the user"
|
||||
} ];
|
||||
bool emailVerified = 8
|
||||
bool emailVerified = 9
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "EmailVerified"
|
||||
description : "Flag to show if the email of the user was verified"
|
||||
read_only : true
|
||||
} ];
|
||||
bool phoneVerified = 9
|
||||
bool phoneVerified = 10
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "PhoneVerified"
|
||||
description : "Flag to show if phone number of the user was verified"
|
||||
@@ -167,24 +173,30 @@ message UserSpec {
|
||||
description : "Groups the user belongs to"
|
||||
read_only : true,
|
||||
} ];
|
||||
repeated rafay.dev.types.user.v3.ProjectNamespaceRole projectNamespaceRoles = 7
|
||||
repeated string idpGroups = 7
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Idp Group"
|
||||
description : "Idp Groups the user belongs to"
|
||||
read_only : true,
|
||||
} ];
|
||||
repeated rafay.dev.types.user.v3.ProjectNamespaceRole projectNamespaceRoles = 8
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "ProjectNamespaceRoles"
|
||||
description : "Project, namespace, role associations for user"
|
||||
} ];
|
||||
bool emailVerified = 8
|
||||
bool emailVerified = 9
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "EmailVerified"
|
||||
description : "Flag to show if the email of the user was verified"
|
||||
read_only : true
|
||||
} ];
|
||||
bool phoneVerified = 9
|
||||
bool phoneVerified = 10
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "PhoneVerified"
|
||||
description : "Flag to show if phone number of the user was verified"
|
||||
read_only : true
|
||||
} ];
|
||||
optional string recoveryUrl = 10
|
||||
optional string recoveryUrl = 11
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Recovery Url",
|
||||
description : "Initial signup URL returned after user creation"
|
||||
|
||||
Reference in New Issue
Block a user