Rename user into identity

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-12-20 14:14:31 +01:00
parent fa0295f481
commit 0f7c755d53
35 changed files with 606 additions and 664 deletions

View File

@@ -26,9 +26,9 @@ import (
)
type (
UserAPIKeyMembership struct {
PersonalAPIKeyMembership struct {
ID gid.GID `db:"id"`
UserAPIKeyID gid.GID `db:"auth_user_api_key_id"`
PersonalAPIKeyID gid.GID `db:"auth_personal_api_key_id"`
MembershipID gid.GID `db:"membership_id"`
Role APIRole `db:"role"`
OrganizationID gid.GID `db:"organization_id"`
@@ -37,21 +37,21 @@ type (
UpdatedAt time.Time `db:"updated_at"`
}
UserAPIKeyMemberships []*UserAPIKeyMembership
PersonalAPIKeyMemberships []*PersonalAPIKeyMembership
)
func (a *UserAPIKeyMembership) Insert(
func (a *PersonalAPIKeyMembership) Insert(
ctx context.Context,
conn pg.Conn,
scope Scoper,
) error {
q := `
INSERT INTO
authz_api_keys_memberships (id, tenant_id, auth_user_api_key_id, membership_id, role, organization_id, created_at, updated_at)
authz_api_keys_memberships (id, tenant_id, auth_personal_api_key_id, membership_id, role, organization_id, created_at, updated_at)
VALUES (
@id,
@tenant_id,
@auth_user_api_key_id,
@auth_personal_api_key_id,
@membership_id,
@role,
@organization_id,
@@ -61,34 +61,34 @@ VALUES (
`
args := pgx.StrictNamedArgs{
"id": a.ID,
"tenant_id": scope.GetTenantID(),
"auth_user_api_key_id": a.UserAPIKeyID,
"membership_id": a.MembershipID,
"role": a.Role,
"organization_id": a.OrganizationID,
"created_at": a.CreatedAt,
"updated_at": a.UpdatedAt,
"id": a.ID,
"tenant_id": scope.GetTenantID(),
"auth_personal_api_key_id": a.PersonalAPIKeyID,
"membership_id": a.MembershipID,
"role": a.Role,
"organization_id": a.OrganizationID,
"created_at": a.CreatedAt,
"updated_at": a.UpdatedAt,
}
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot insert user api key membership: %w", err)
return fmt.Errorf("cannot insert personal api key membership: %w", err)
}
return nil
}
func (a *UserAPIKeyMemberships) LoadByUserAPIKeyID(
func (a *PersonalAPIKeyMemberships) LoadByPersonalAPIKeyID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
userAPIKeyID gid.GID,
personalAPIKeyID gid.GID,
) error {
q := `
SELECT
akm.id,
akm.auth_user_api_key_id,
akm.auth_personal_api_key_id,
akm.membership_id,
akm.role,
akm.created_at,
@@ -102,7 +102,7 @@ JOIN
JOIN
organizations o ON m.organization_id = o.id
WHERE
akm.auth_user_api_key_id = @auth_user_api_key_id
akm.auth_personal_api_key_id = @auth_personal_api_key_id
AND m.%s
ORDER BY akm.created_at DESC
`
@@ -110,18 +110,18 @@ ORDER BY akm.created_at DESC
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"auth_user_api_key_id": userAPIKeyID,
"auth_personal_api_key_id": personalAPIKeyID,
}
maps.Copy(args, scope.SQLArguments())
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user api key memberships: %w", err)
return fmt.Errorf("cannot query personal api key memberships: %w", err)
}
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[UserAPIKeyMembership])
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[PersonalAPIKeyMembership])
if err != nil {
return fmt.Errorf("cannot collect user api key memberships: %w", err)
return fmt.Errorf("cannot collect personal api key memberships: %w", err)
}
*a = memberships
@@ -130,7 +130,7 @@ ORDER BY akm.created_at DESC
}
// LoadRoleByAPIKeyAndEntityID loads an API key's role by querying any entity to extract its organization_id
func (a *UserAPIKeyMembership) LoadRoleByAPIKeyAndEntityID(
func (a *PersonalAPIKeyMembership) LoadRoleByAPIKeyAndEntityID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -152,7 +152,7 @@ func (a *UserAPIKeyMembership) LoadRoleByAPIKeyAndEntityID(
query := fmt.Sprintf(`
SELECT
akm.id,
akm.auth_user_api_key_id,
akm.auth_personal_api_key_id,
akm.membership_id,
akm.role,
akm.created_at,
@@ -163,7 +163,7 @@ FROM
INNER JOIN %s e ON e.id = @entity_id
WHERE
%s
AND akm.auth_user_api_key_id = @api_key_id
AND akm.auth_personal_api_key_id = @api_key_id
AND m.organization_id = e.organization_id
LIMIT 1;
`, tableName, scope.SQLFragment())
@@ -184,10 +184,10 @@ LIMIT 1;
return fmt.Errorf("API key membership not found for key %s and entity %s", apiKeyID, entityID)
}
var membership UserAPIKeyMembership
var membership PersonalAPIKeyMembership
err = rows.Scan(
&membership.ID,
&membership.UserAPIKeyID,
&membership.PersonalAPIKeyID,
&membership.MembershipID,
&membership.Role,
&membership.CreatedAt,
@@ -202,7 +202,7 @@ LIMIT 1;
return nil
}
func (a *UserAPIKeyMembership) LoadByAPIKeyIDAndOrganizationID(
func (a *PersonalAPIKeyMembership) LoadByAPIKeyIDAndOrganizationID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -212,7 +212,7 @@ func (a *UserAPIKeyMembership) LoadByAPIKeyIDAndOrganizationID(
q := `
SELECT
akm.id,
akm.auth_user_api_key_id,
akm.auth_personal_api_key_id,
akm.membership_id,
akm.role,
akm.created_at,
@@ -226,7 +226,7 @@ JOIN
JOIN
organizations o ON m.organization_id = o.id
WHERE
akm.auth_user_api_key_id = @api_key_id
akm.auth_personal_api_key_id = @api_key_id
AND m.organization_id = @organization_id
AND m.%s
`
@@ -241,22 +241,22 @@ WHERE
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user api key membership: %w", err)
return fmt.Errorf("cannot query personal api key membership: %w", err)
}
membership, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[UserAPIKeyMembership])
membership, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[PersonalAPIKeyMembership])
if err != nil {
if err == pgx.ErrNoRows {
return fmt.Errorf("API key does not have access to organization")
}
return fmt.Errorf("cannot collect user api key membership: %w", err)
return fmt.Errorf("cannot collect personal api key membership: %w", err)
}
*a = membership
return nil
}
func (a *UserAPIKeyMembership) Delete(
func (a *PersonalAPIKeyMembership) Delete(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -278,13 +278,13 @@ WHERE
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot delete user api key membership: %w", err)
return fmt.Errorf("cannot delete personal api key membership: %w", err)
}
return nil
}
func (a *UserAPIKeyMemberships) LoadByMembershipID(
func (a *PersonalAPIKeyMemberships) LoadByMembershipID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -293,7 +293,7 @@ func (a *UserAPIKeyMemberships) LoadByMembershipID(
q := `
SELECT
akm.id,
akm.auth_user_api_key_id,
akm.auth_personal_api_key_id,
akm.membership_id,
akm.role,
akm.created_at,
@@ -321,12 +321,12 @@ ORDER BY akm.created_at DESC
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user api key memberships by membership id: %w", err)
return fmt.Errorf("cannot query personal api key memberships by membership id: %w", err)
}
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[UserAPIKeyMembership])
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[PersonalAPIKeyMembership])
if err != nil {
return fmt.Errorf("cannot collect user api key memberships: %w", err)
return fmt.Errorf("cannot collect personal api key memberships: %w", err)
}
*a = memberships
@@ -334,25 +334,25 @@ ORDER BY akm.created_at DESC
return nil
}
func DeleteAllUserAPIKeyMembershipsByUserAPIKeyID(
func DeleteAllPersonalAPIKeyMembershipsByPersonalAPIKeyID(
ctx context.Context,
conn pg.Conn,
userAPIKeyID gid.GID,
personalAPIKeyID gid.GID,
) error {
q := `
DELETE FROM
authz_api_keys_memberships
WHERE
auth_user_api_key_id = @auth_user_api_key_id
auth_personal_api_key_id = @auth_personal_api_key_id
`
args := pgx.StrictNamedArgs{
"auth_user_api_key_id": userAPIKeyID,
"auth_personal_api_key_id": personalAPIKeyID,
}
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot delete user api key memberships: %w", err)
return fmt.Errorf("cannot delete personal api key memberships: %w", err)
}
return nil

View File

@@ -32,7 +32,7 @@ const (
PeopleEntityType uint16 = 8
VendorComplianceReportEntityType uint16 = 9
DocumentEntityType uint16 = 10
UserEntityType uint16 = 11
IdentityEntityType uint16 = 11
SessionEntityType uint16 = 12
EmailEntityType uint16 = 13
ControlEntityType uint16 = 14
@@ -64,8 +64,8 @@ const (
SlackMessageEntityType uint16 = 40
TrustCenterFileEntityType uint16 = 41
SAMLConfigurationEntityType uint16 = 42
UserAPIKeyEntityType uint16 = 43
UserAPIKeyMembershipEntityType uint16 = 44
PersonalAPIKeyEntityType uint16 = 43
PersonalAPIKeyMembershipEntityType uint16 = 44
MeetingEntityType uint16 = 45
DataProtectionImpactAssessmentEntityType uint16 = 46
TransferImpactAssessmentEntityType uint16 = 47
@@ -124,9 +124,9 @@ var entityRegistry = map[uint16]EntityInfo{
Model: "Document",
Table: "documents",
},
UserEntityType: {
Model: "User",
Table: "auth_users",
IdentityEntityType: {
Model: "Identity",
Table: "identities",
},
SessionEntityType: {
Model: "Session",
@@ -252,12 +252,12 @@ var entityRegistry = map[uint16]EntityInfo{
Model: "SAMLConfiguration",
Table: "auth_saml_configurations",
},
UserAPIKeyEntityType: {
Model: "UserAPIKey",
Table: "auth_user_api_keys",
PersonalAPIKeyEntityType: {
Model: "PersonalAPIKey",
Table: "auth_personal_api_keys",
},
UserAPIKeyMembershipEntityType: {
Model: "UserAPIKeyMembership",
PersonalAPIKeyMembershipEntityType: {
Model: "PersonalAPIKeyMembership",
Table: "authz_api_keys_memberships",
},
MeetingEntityType: {

View File

@@ -31,34 +31,34 @@ import (
)
type (
User struct {
Identity struct {
ID gid.GID `db:"id"`
EmailAddress mail.Addr `db:"email_address"`
HashedPassword []byte `db:"hashed_password"`
FullName string `db:"fullname"`
EmailAddressVerified bool `db:"email_address_verified"`
SAMLSubject *string `db:"saml_subject"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
HashedPassword []byte `db:"hashed_password"`
FullName string `db:"fullname"`
EmailAddressVerified bool `db:"email_address_verified"`
SAMLSubject *string `db:"saml_subject"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
Users []*User
Identities []*Identity
)
func (u User) CursorKey(orderBy UserOrderField) page.CursorKey {
func (i Identity) CursorKey(orderBy IdentityOrderField) page.CursorKey {
switch orderBy {
case UserOrderFieldCreatedAt:
return page.NewCursorKey(u.ID, u.CreatedAt)
case IdentityOrderFieldCreatedAt:
return page.NewCursorKey(i.ID, i.CreatedAt)
}
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
}
func (u *Users) LoadByOrganizationID(
func (i *Identities) LoadByOrganizationID(
ctx context.Context,
conn pg.Conn,
organizationID gid.GID,
cursor *page.Cursor[UserOrderField],
cursor *page.Cursor[IdentityOrderField],
) error {
q := `
SELECT
@@ -70,10 +70,10 @@ SELECT
created_at,
updated_at
FROM
users
identities
WHERE
id IN (
SELECT user_id FROM authz_memberships WHERE organization_id = @organization_id
SELECT identity_id FROM authz_memberships WHERE organization_id = @organization_id
)
AND %s
`
@@ -85,20 +85,20 @@ WHERE
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query users: %w", err)
return fmt.Errorf("cannot query identities: %w", err)
}
users, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[User])
identities, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Identity])
if err != nil {
return fmt.Errorf("cannot collect users: %w", err)
return fmt.Errorf("cannot collect identities: %w", err)
}
*u = users
*i = identities
return nil
}
func (u *Users) CountByOrganizationID(
func (i *Identities) CountByOrganizationID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -108,10 +108,10 @@ func (u *Users) CountByOrganizationID(
SELECT
COUNT(*)
FROM
users
identities
WHERE
id IN (
SELECT user_id FROM authz_memberships WHERE organization_id = @organization_id AND %s
SELECT identity_id FROM authz_memberships WHERE organization_id = @organization_id AND %s
)
`
@@ -125,14 +125,14 @@ WHERE
var count int
err := row.Scan(&count)
if err != nil {
return 0, fmt.Errorf("cannot count users: %w", err)
return 0, fmt.Errorf("cannot count identities: %w", err)
}
return count, nil
}
// Tenant id scope is not applied because we want to access users across all tenants for authentication purposes.
func (u *User) LoadByEmail(
// Tenant id scope is not applied because we want to access identities across all tenants for authentication purposes.
func (i *Identity) LoadByEmail(
ctx context.Context,
conn pg.Conn,
email mail.Addr,
@@ -148,38 +148,38 @@ SELECT
created_at,
updated_at
FROM
users
identities
WHERE
email_address = @user_email
email_address = @identity_email
LIMIT 1;
`
args := pgx.StrictNamedArgs{"user_email": email}
args := pgx.StrictNamedArgs{"identity_email": email}
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user: %w", err)
return fmt.Errorf("cannot query identity: %w", err)
}
user, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[User])
identity, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Identity])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect user: %w", err)
return fmt.Errorf("cannot collect identity: %w", err)
}
*u = user
*i = identity
return nil
}
// Tenant id scope is not applied because we want to access users across all tenants for authentication purposes.
func (u *User) LoadByID(
// Tenant id scope is not applied because we want to access identities across all tenants for authentication purposes.
func (i *Identity) LoadByID(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
identityID gid.GID,
) error {
q := `
SELECT
@@ -192,42 +192,42 @@ SELECT
created_at,
updated_at
FROM
users
identities
WHERE
id = @user_id
id = @identity_id
LIMIT 1;
`
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user: %w", err)
return fmt.Errorf("cannot query identity: %w", err)
}
user, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[User])
identity, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Identity])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect user: %w", err)
return fmt.Errorf("cannot collect identity: %w", err)
}
*u = user
*i = identity
return nil
}
func (u *User) Insert(
func (i *Identity) Insert(
ctx context.Context,
conn pg.Conn,
) error {
q := `
INSERT INTO
users (id, email_address, hashed_password, email_address_verified, fullname, saml_subject, created_at, updated_at)
identities (id, email_address, hashed_password, email_address_verified, fullname, saml_subject, created_at, updated_at)
VALUES (
@user_id,
@identity_id,
@email_address,
@hashed_password,
@email_address_verified,
@@ -239,14 +239,14 @@ VALUES (
`
args := pgx.StrictNamedArgs{
"user_id": u.ID,
"email_address": u.EmailAddress,
"hashed_password": u.HashedPassword,
"fullname": u.FullName,
"saml_subject": u.SAMLSubject,
"created_at": u.CreatedAt,
"updated_at": u.UpdatedAt,
"email_address_verified": u.EmailAddressVerified,
"identity_id": i.ID,
"email_address": i.EmailAddress,
"hashed_password": i.HashedPassword,
"fullname": i.FullName,
"saml_subject": i.SAMLSubject,
"created_at": i.CreatedAt,
"updated_at": i.UpdatedAt,
"email_address_verified": i.EmailAddressVerified,
}
_, err := conn.Exec(ctx, q, args)
@@ -265,10 +265,10 @@ VALUES (
return nil
}
func (u *User) Update(ctx context.Context, conn pg.Conn) error {
func (i *Identity) Update(ctx context.Context, conn pg.Conn) error {
q := `
UPDATE
users
identities
SET
email_address = @email_address,
email_address_verified = @email_address_verified,
@@ -277,22 +277,22 @@ SET
hashed_password = @hashed_password,
updated_at = @updated_at
WHERE
id = @user_id
id = @identity_id
`
args := pgx.StrictNamedArgs{
"user_id": u.ID,
"email_address": u.EmailAddress,
"email_address_verified": u.EmailAddressVerified,
"saml_subject": u.SAMLSubject,
"updated_at": u.UpdatedAt,
"fullname": u.FullName,
"hashed_password": u.HashedPassword,
"identity_id": i.ID,
"email_address": i.EmailAddress,
"email_address_verified": i.EmailAddressVerified,
"saml_subject": i.SAMLSubject,
"updated_at": i.UpdatedAt,
"fullname": i.FullName,
"hashed_password": i.HashedPassword,
}
result, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
if result.RowsAffected() == 0 {
@@ -302,8 +302,8 @@ WHERE
return nil
}
// LoadBySAMLSubject loads a user by their SAML subject (NameID)
func (u *User) LoadBySAMLSubject(
// LoadBySAMLSubject loads an identity by their SAML subject (NameID)
func (i *Identity) LoadBySAMLSubject(
ctx context.Context,
conn pg.Conn,
samlSubject string,
@@ -319,7 +319,7 @@ SELECT
created_at,
updated_at
FROM
users
identities
WHERE
saml_subject = @saml_subject
LIMIT 1;
@@ -329,24 +329,24 @@ LIMIT 1;
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user by SAML subject: %w", err)
return fmt.Errorf("cannot query identity by SAML subject: %w", err)
}
user, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[User])
identity, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Identity])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect user: %w", err)
return fmt.Errorf("cannot collect identity: %w", err)
}
*u = user
*i = identity
return nil
}
func (u *User) CountMemberships(
func (i *Identity) CountMemberships(
ctx context.Context,
conn pg.Conn,
) (int, error) {
@@ -356,19 +356,16 @@ SELECT
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
`
args := pgx.StrictNamedArgs{"user_id": u.ID}
args := pgx.StrictNamedArgs{"identity_id": i.ID}
var count int
err := conn.QueryRow(ctx, q, args).Scan(&count)
if err != nil {
return 0, fmt.Errorf("cannot count user memberships: %w", err)
return 0, fmt.Errorf("cannot count identity memberships: %w", err)
}
return count, nil
}
// ConvertToTenantUser method removed
// All users are now global (no tenant conversion needed)

View File

@@ -15,26 +15,26 @@
package coredata
type (
UserOrderField string
IdentityOrderField string
)
const (
UserOrderFieldCreatedAt UserOrderField = "CREATED_AT"
IdentityOrderFieldCreatedAt IdentityOrderField = "CREATED_AT"
)
func (p UserOrderField) Column() string {
func (p IdentityOrderField) Column() string {
return string(p)
}
func (p UserOrderField) String() string {
func (p IdentityOrderField) String() string {
return string(p)
}
func (p UserOrderField) MarshalText() ([]byte, error) {
func (p IdentityOrderField) MarshalText() ([]byte, error) {
return []byte(p.String()), nil
}
func (p *UserOrderField) UnmarshalText(text []byte) error {
*p = UserOrderField(text)
func (p *IdentityOrderField) UnmarshalText(text []byte) error {
*p = IdentityOrderField(text)
return nil
}

View File

@@ -33,7 +33,7 @@ import (
type (
Membership struct {
ID gid.GID `db:"id"`
UserID gid.GID `db:"user_id"`
IdentityID gid.GID `db:"identity_id"`
OrganizationID gid.GID `db:"organization_id"`
Role MembershipRole `db:"role"`
FullName string `db:"full_name"`
@@ -60,11 +60,11 @@ func (m Membership) CursorKey(orderBy MembershipOrderField) page.CursorKey {
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
}
func (m *Membership) LoadByUserInOrganization(ctx context.Context, conn pg.Conn, userID gid.GID, organizationID gid.GID) error {
func (m *Membership) LoadByIdentityInOrganization(ctx context.Context, conn pg.Conn, identityID gid.GID, organizationID gid.GID) error {
q := `
SELECT
id,
user_id,
identity_id,
organization_id,
role,
created_at,
@@ -72,12 +72,12 @@ SELECT
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
AND organization_id = @organization_id
`
args := pgx.StrictNamedArgs{
"user_id": userID,
"identity_id": identityID,
"organization_id": organizationID,
}
@@ -105,7 +105,7 @@ INSERT INTO
authz_memberships (
tenant_id,
id,
user_id,
identity_id,
organization_id,
role,
created_at,
@@ -114,7 +114,7 @@ INSERT INTO
VALUES (
@tenant_id,
@id,
@user_id,
@identity_id,
@organization_id,
@role,
@created_at,
@@ -125,7 +125,7 @@ VALUES (
args := pgx.StrictNamedArgs{
"tenant_id": scope.GetTenantID(),
"id": m.ID,
"user_id": m.UserID,
"identity_id": m.IdentityID,
"organization_id": m.OrganizationID,
"role": m.Role,
"created_at": m.CreatedAt,
@@ -159,7 +159,7 @@ func (m *Membership) LoadByID(
WITH mbr AS (
SELECT
id,
user_id,
identity_id,
organization_id,
role,
created_at,
@@ -172,17 +172,17 @@ WITH mbr AS (
)
SELECT
mbr.id,
mbr.user_id,
mbr.identity_id,
mbr.organization_id,
mbr.role,
u.fullname as full_name,
u.email_address,
i.fullname as full_name,
i.email_address,
mbr.created_at,
mbr.updated_at
FROM
mbr
JOIN
users u ON mbr.user_id = u.id
identities i ON mbr.identity_id = i.id
`
query = fmt.Sprintf(query, scope.SQLFragment())
@@ -210,19 +210,19 @@ JOIN
return nil
}
// LoadRoleByUserAndEntityID loads a user's role by querying any entity to extract its organization_id
func (m *Membership) LoadRoleByUserAndEntityID(
// LoadRoleByIdentityAndEntityID loads an identity's role by querying any entity to extract its organization_id
func (m *Membership) LoadRoleByIdentityAndEntityID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
userID gid.GID,
identityID gid.GID,
entityID gid.GID,
) error {
entityType := entityID.EntityType()
// For organization, the entity ID is the organization ID
if entityType == OrganizationEntityType {
return m.LoadByUserAndOrg(ctx, conn, scope, userID, entityID)
return m.LoadByIdentityAndOrg(ctx, conn, scope, identityID, entityID)
}
tableName, ok := EntityTable(entityType)
@@ -238,7 +238,7 @@ func (m *Membership) LoadRoleByUserAndEntityID(
query := fmt.Sprintf(`
SELECT
m.id,
m.user_id,
m.identity_id,
m.organization_id,
m.role,
m.created_at,
@@ -248,14 +248,14 @@ FROM
INNER JOIN %s e ON e.id = @entity_id
WHERE
%s
AND m.user_id = @user_id
AND m.identity_id = @identity_id
AND m.organization_id = e.organization_id
LIMIT 1;
`, tableName, scopeFragment)
args := pgx.NamedArgs{
"user_id": userID,
"entity_id": entityID,
"identity_id": identityID,
"entity_id": entityID,
}
maps.Copy(args, scope.SQLArguments())
@@ -272,7 +272,7 @@ LIMIT 1;
var membership Membership
err = rows.Scan(
&membership.ID,
&membership.UserID,
&membership.IdentityID,
&membership.OrganizationID,
&membership.Role,
&membership.CreatedAt,
@@ -287,18 +287,18 @@ LIMIT 1;
return nil
}
func (m *Membership) LoadByUserAndOrg(
func (m *Membership) LoadByIdentityAndOrg(
ctx context.Context,
conn pg.Conn,
scope Scoper,
userID gid.GID,
identityID gid.GID,
organizationID gid.GID,
) error {
q := `
WITH mbr AS (
SELECT
am.id,
am.user_id,
am.identity_id,
am.organization_id,
am.role,
am.created_at,
@@ -306,29 +306,29 @@ WITH mbr AS (
FROM
authz_memberships am
WHERE
am.user_id = @user_id
am.identity_id = @identity_id
AND am.organization_id = @organization_id
AND %s
)
SELECT
mbr.id,
mbr.user_id,
mbr.identity_id,
mbr.organization_id,
mbr.role,
u.fullname as full_name,
u.email_address,
i.fullname as full_name,
i.email_address,
mbr.created_at,
mbr.updated_at
FROM
mbr
JOIN
users u ON mbr.user_id = u.id
identities i ON mbr.identity_id = i.id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"user_id": userID,
"identity_id": identityID,
"organization_id": organizationID,
}
maps.Copy(args, scope.SQLArguments())
@@ -412,18 +412,18 @@ WHERE
return nil
}
func (m *Memberships) LoadByUserID(
func (m *Memberships) LoadByIdentityID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
userID gid.GID,
identityID gid.GID,
cursor *page.Cursor[MembershipOrderField],
) error {
query := `
WITH mbr AS (
SELECT
id,
user_id,
identity_id,
organization_id,
role,
created_at,
@@ -431,24 +431,24 @@ WITH mbr AS (
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
AND %s
ORDER BY
created_at DESC
)
SELECT
mbr.id,
mbr.user_id,
mbr.identity_id,
mbr.organization_id,
mbr.role,
u.fullname as full_name,
u.email_address,
i.fullname as full_name,
i.email_address,
mbr.created_at,
mbr.updated_at
FROM
mbr
JOIN
users u ON mbr.user_id = u.id
identities i ON mbr.identity_id = i.id
ORDER BY
mbr.created_at DESC
`
@@ -456,7 +456,7 @@ ORDER BY
query = fmt.Sprintf(query, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"user_id": userID,
"identity_id": identityID,
}
maps.Copy(args, scope.SQLArguments())
@@ -485,7 +485,7 @@ func (m *Memberships) LoadByOrganizationID(
WITH mbr AS (
SELECT
id,
user_id,
identity_id,
organization_id,
role,
created_at,
@@ -498,7 +498,7 @@ WITH mbr AS (
)
SELECT
id,
user_id,
identity_id,
organization_id,
role,
full_name,
@@ -508,18 +508,18 @@ SELECT
FROM (
SELECT
mbr.id,
mbr.user_id,
mbr.identity_id,
mbr.organization_id,
mbr.role,
u.fullname as full_name,
u.email_address,
i.fullname as full_name,
i.email_address,
mbr.created_at,
mbr.updated_at
FROM
mbr
JOIN
users u ON mbr.user_id = u.id
) AS membership_with_user
identities i ON mbr.identity_id = i.id
) AS membership_with_identity
WHERE %s
`
@@ -573,10 +573,10 @@ WHERE
return count, nil
}
func (m *Memberships) CountByUserID(
func (m *Memberships) CountByIdentityID(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
identityID gid.GID,
) (int, error) {
query := `
SELECT
@@ -584,10 +584,10 @@ SELECT
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
`
args := pgx.StrictNamedArgs{
"user_id": userID,
"identity_id": identityID,
}
row := conn.QueryRow(ctx, query, args)

View File

@@ -0,0 +1,8 @@
ALTER TABLE users RENAME TO identities;
ALTER TABLE sessions RENAME COLUMN user_id TO identity_id;
ALTER TABLE authz_memberships RENAME COLUMN user_id TO identity_id;
ALTER TABLE peoples RENAME COLUMN user_id TO identity_id;
ALTER TABLE auth_user_api_keys RENAME TO auth_personal_api_keys;
ALTER TABLE auth_personal_api_keys RENAME COLUMN user_id TO identity_id;
ALTER TABLE authz_api_keys_memberships RENAME COLUMN auth_user_api_key_id TO auth_personal_api_key_id;

View File

@@ -111,21 +111,21 @@ LIMIT 1;
return nil
}
func (o *Organizations) LoadByUserID(
func (o *Organizations) LoadByIdentityID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
userID gid.GID,
identityID gid.GID,
cursor *page.Cursor[OrganizationOrderField],
) error {
q := `
WITH user_org AS (
WITH identity_org AS (
SELECT
organization_id
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
)
SELECT
tenant_id,
@@ -143,7 +143,7 @@ SELECT
FROM
organizations
INNER JOIN
user_org ON organizations.id = user_org.organization_id
identity_org ON organizations.id = identity_org.organization_id
WHERE
%s
AND %s
@@ -151,7 +151,7 @@ WHERE
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
maps.Copy(args, cursor.SQLArguments())
rows, err := conn.Query(ctx, q, args)
@@ -169,19 +169,19 @@ WHERE
return nil
}
func (o *Organizations) LoadAllByUserID(
func (o *Organizations) LoadAllByIdentityID(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
identityID gid.GID,
) error {
q := `
WITH user_org AS (
WITH identity_org AS (
SELECT
organization_id
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
)
SELECT
tenant_id,
@@ -199,12 +199,12 @@ SELECT
FROM
organizations
INNER JOIN
user_org ON organizations.id = user_org.organization_id
identity_org ON organizations.id = identity_org.organization_id
ORDER BY
name ASC
`
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
rows, err := conn.Query(ctx, q, args)
if err != nil {
@@ -221,20 +221,20 @@ ORDER BY
return nil
}
func (o *Organizations) LoadAllByUserIDWithRole(
func (o *Organizations) LoadAllByIdentityIDWithRole(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
identityID gid.GID,
role MembershipRole,
) error {
q := `
WITH user_org AS (
WITH identity_org AS (
SELECT
organization_id
FROM
authz_memberships
WHERE
user_id = @user_id
identity_id = @identity_id
AND role = @role
)
SELECT
@@ -253,14 +253,14 @@ SELECT
FROM
organizations
INNER JOIN
user_org ON organizations.id = user_org.organization_id
identity_org ON organizations.id = identity_org.organization_id
ORDER BY
name ASC
`
args := pgx.StrictNamedArgs{
"user_id": userID,
"role": role,
"identity_id": identityID,
"role": role,
}
rows, err := conn.Query(ctx, q, args)
@@ -278,13 +278,13 @@ ORDER BY
return nil
}
func (o *Organizations) LoadAllByUserAPIKeyID(
func (o *Organizations) LoadAllByPersonalAPIKeyID(
ctx context.Context,
conn pg.Conn,
userAPIKeyID gid.GID,
personalAPIKeyID gid.GID,
) error {
q := `
WITH user_api_key_org AS (
WITH personal_api_key_org AS (
SELECT
am.organization_id
FROM
@@ -292,7 +292,7 @@ WITH user_api_key_org AS (
INNER JOIN
authz_memberships am ON akm.membership_id = am.id
WHERE
akm.auth_user_api_key_id = @auth_user_api_key_id
akm.auth_personal_api_key_id = @auth_personal_api_key_id
)
SELECT
tenant_id,
@@ -310,12 +310,12 @@ SELECT
FROM
organizations
INNER JOIN
user_api_key_org ON organizations.id = user_api_key_org.organization_id
personal_api_key_org ON organizations.id = personal_api_key_org.organization_id
ORDER BY
name ASC
`
args := pgx.StrictNamedArgs{"auth_user_api_key_id": userAPIKeyID}
args := pgx.StrictNamedArgs{"auth_personal_api_key_id": personalAPIKeyID}
rows, err := conn.Query(ctx, q, args)
if err != nil {

View File

@@ -27,9 +27,9 @@ import (
)
type (
UserAPIKey struct {
PersonalAPIKey struct {
ID gid.GID `db:"id"`
UserID gid.GID `db:"user_id"`
IdentityID gid.GID `db:"identity_id"`
Name string `db:"name"`
ExpiresAt time.Time `db:"expires_at"`
ExpireReason *ExpireReason `db:"expire_reason"`
@@ -37,19 +37,19 @@ type (
UpdatedAt time.Time `db:"updated_at"`
}
UserAPIKeys []*UserAPIKey
PersonalAPIKeys []*PersonalAPIKey
)
func (a *UserAPIKey) CursorKey(orderBy UserAPIKeyOrderField) page.CursorKey {
func (a *PersonalAPIKey) CursorKey(orderBy PersonalAPIKeyOrderField) page.CursorKey {
switch orderBy {
case UserAPIKeyOrderFieldCreatedAt:
case PersonalAPIKeyOrderFieldCreatedAt:
return page.NewCursorKey(a.ID, a.CreatedAt)
}
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
}
func (a *UserAPIKey) LoadByID(
func (a *PersonalAPIKey) LoadByID(
ctx context.Context,
conn pg.Conn,
apiKeyID gid.GID,
@@ -57,14 +57,14 @@ func (a *UserAPIKey) LoadByID(
q := `
SELECT
id,
user_id,
identity_id,
name,
expires_at,
expire_reason,
created_at,
updated_at
FROM
auth_user_api_keys
auth_personal_api_keys
WHERE
id = @api_key_id
LIMIT 1;
@@ -74,16 +74,16 @@ LIMIT 1;
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user api key: %w", err)
return fmt.Errorf("cannot query personal api key: %w", err)
}
apiKey, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[UserAPIKey])
apiKey, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[PersonalAPIKey])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect user api key: %w", err)
return fmt.Errorf("cannot collect personal api key: %w", err)
}
*a = apiKey
@@ -91,37 +91,37 @@ LIMIT 1;
return nil
}
func (a *UserAPIKeys) LoadByUserID(
func (a *PersonalAPIKeys) LoadByIdentityID(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
identityID gid.GID,
) error {
q := `
SELECT
id,
user_id,
identity_id,
name,
expires_at,
expire_reason,
created_at,
updated_at
FROM
auth_user_api_keys
auth_personal_api_keys
WHERE
user_id = @user_id
identity_id = @identity_id
ORDER BY created_at DESC;
`
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query user api keys: %w", err)
return fmt.Errorf("cannot query personal api keys: %w", err)
}
apiKeys, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[UserAPIKey])
apiKeys, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[PersonalAPIKey])
if err != nil {
return fmt.Errorf("cannot collect user api keys: %w", err)
return fmt.Errorf("cannot collect personal api keys: %w", err)
}
*a = apiKeys
@@ -129,18 +129,18 @@ ORDER BY created_at DESC;
return nil
}
func (a *UserAPIKeys) CountByUserID(ctx context.Context, conn pg.Conn, userID gid.GID) (int, error) {
func (a *PersonalAPIKeys) CountByIdentityID(ctx context.Context, conn pg.Conn, identityID gid.GID) (int, error) {
q := `
SELECT
COUNT(*)
FROM
auth_user_api_keys
auth_personal_api_keys
WHERE
user_id = @user_id
identity_id = @identity_id
ORDER BY created_at DESC;
`
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
row := conn.QueryRow(ctx, q, args)
var count int
if err := row.Scan(&count); err != nil {
@@ -150,16 +150,16 @@ ORDER BY created_at DESC;
return count, nil
}
func (a *UserAPIKey) Insert(
func (a *PersonalAPIKey) Insert(
ctx context.Context,
conn pg.Conn,
) error {
q := `
INSERT INTO
auth_user_api_keys (id, user_id, name, expires_at, expire_reason, created_at, updated_at)
auth_personal_api_keys (id, identity_id, name, expires_at, expire_reason, created_at, updated_at)
VALUES (
@api_key_id,
@user_id,
@identity_id,
@name,
@expires_at,
@expire_reason,
@@ -170,7 +170,7 @@ VALUES (
args := pgx.StrictNamedArgs{
"api_key_id": a.ID,
"user_id": a.UserID,
"identity_id": a.IdentityID,
"name": a.Name,
"expires_at": a.ExpiresAt,
"expire_reason": a.ExpireReason,
@@ -180,19 +180,19 @@ VALUES (
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot insert user api key: %w", err)
return fmt.Errorf("cannot insert personal api key: %w", err)
}
return nil
}
func (a *UserAPIKey) Update(
func (a *PersonalAPIKey) Update(
ctx context.Context,
conn pg.Conn,
) error {
q := `
UPDATE
auth_user_api_keys
auth_personal_api_keys
SET
name = @name,
expires_at = @expires_at,
@@ -212,19 +212,19 @@ WHERE
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot update user api key: %w", err)
return fmt.Errorf("cannot update personal api key: %w", err)
}
return nil
}
func (a *UserAPIKey) Delete(
func (a *PersonalAPIKey) Delete(
ctx context.Context,
conn pg.Conn,
) error {
q := `
DELETE FROM
auth_user_api_keys
auth_personal_api_keys
WHERE
id = @api_key_id
`
@@ -233,7 +233,7 @@ WHERE
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot delete user api key: %w", err)
return fmt.Errorf("cannot delete personal api key: %w", err)
}
return nil

View File

@@ -15,26 +15,26 @@
package coredata
type (
UserAPIKeyOrderField string
PersonalAPIKeyOrderField string
)
const (
UserAPIKeyOrderFieldCreatedAt UserAPIKeyOrderField = "CREATED_AT"
PersonalAPIKeyOrderFieldCreatedAt PersonalAPIKeyOrderField = "CREATED_AT"
)
func (p UserAPIKeyOrderField) Column() string {
func (p PersonalAPIKeyOrderField) Column() string {
return string(p)
}
func (p UserAPIKeyOrderField) String() string {
func (p PersonalAPIKeyOrderField) String() string {
return string(p)
}
func (p UserAPIKeyOrderField) MarshalText() ([]byte, error) {
func (p PersonalAPIKeyOrderField) MarshalText() ([]byte, error) {
return []byte(p.String()), nil
}
func (p *UserAPIKeyOrderField) UnmarshalText(text []byte) error {
*p = UserAPIKeyOrderField(text)
func (p *PersonalAPIKeyOrderField) UnmarshalText(text []byte) error {
*p = PersonalAPIKeyOrderField(text)
return nil
}

View File

@@ -31,7 +31,7 @@ import (
type (
Session struct {
ID gid.GID `db:"id"`
UserID gid.GID `db:"user_id"`
IdentityID gid.GID `db:"identity_id"`
TenantID *gid.TenantID `db:"tenant_id"`
MembershipID *gid.GID `db:"membership_id"`
ParentSessionID *gid.GID `db:"parent_session_id"`
@@ -58,11 +58,11 @@ const (
AuthMethodSAML AuthMethod = "SAML"
)
func NewRootSession(userID gid.GID, method AuthMethod, duration time.Duration) *Session {
func NewRootSession(identityID gid.GID, method AuthMethod, duration time.Duration) *Session {
now := time.Now()
return &Session{
ID: gid.New(gid.NilTenant, SessionEntityType),
UserID: userID,
IdentityID: identityID,
ExpiredAt: now.Add(duration),
AuthMethod: method,
AuthenticatedAt: now,
@@ -100,7 +100,7 @@ func (s *Session) LoadByID(
q := `
SELECT
id,
user_id,
identity_id,
tenant_id,
membership_id,
data,
@@ -146,10 +146,10 @@ func (s *Session) Insert(
) error {
q := `
INSERT INTO
sessions (id, user_id, tenant_id, membership_id, data, parent_session_id, auth_method, authenticated_at, expire_reason, user_agent, ip_address, expired_at, created_at, updated_at)
sessions (id, identity_id, tenant_id, membership_id, data, parent_session_id, auth_method, authenticated_at, expire_reason, user_agent, ip_address, expired_at, created_at, updated_at)
VALUES (
@session_id,
@user_id,
@identity_id,
@tenant_id,
@membership_id,
@data,
@@ -167,7 +167,7 @@ VALUES (
args := pgx.StrictNamedArgs{
"session_id": s.ID,
"user_id": s.UserID,
"identity_id": s.IdentityID,
"tenant_id": s.TenantID,
"membership_id": s.MembershipID,
"data": s.Data,
@@ -225,11 +225,11 @@ WHERE
return nil
}
func (s *Sessions) LoadByUserID(ctx context.Context, conn pg.Conn, userID gid.GID, cursor *page.Cursor[SessionOrderField]) error {
func (s *Sessions) LoadByIdentityID(ctx context.Context, conn pg.Conn, identityID gid.GID, cursor *page.Cursor[SessionOrderField]) error {
q := `
SELECT
id,
user_id,
identity_id,
tenant_id,
membership_id,
data,
@@ -245,13 +245,13 @@ SELECT
FROM
sessions
WHERE
user_id = @user_id
identity_id = @identity_id
AND %s
`
q = fmt.Sprintf(q, cursor.SQLFragment())
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
maps.Copy(args, cursor.SQLArguments())
rows, err := conn.Query(ctx, q, args)
@@ -269,17 +269,17 @@ WHERE
return nil
}
func (s *Sessions) CountByUserID(ctx context.Context, conn pg.Conn, userID gid.GID) (int, error) {
func (s *Sessions) CountByIdentityID(ctx context.Context, conn pg.Conn, identityID gid.GID) (int, error) {
q := `
SELECT
COUNT(*)
FROM
sessions
WHERE
user_id = @user_id
identity_id = @identity_id
`
args := pgx.StrictNamedArgs{"user_id": userID}
args := pgx.StrictNamedArgs{"identity_id": identityID}
row := conn.QueryRow(ctx, q, args)
@@ -291,7 +291,7 @@ WHERE
return count, nil
}
func (s *Sessions) ExpireAllForUserExceptOneSession(ctx context.Context, conn pg.Conn, userID gid.GID, sessionID gid.GID) (int64, error) {
func (s *Sessions) ExpireAllForIdentityExceptOneSession(ctx context.Context, conn pg.Conn, identityID gid.GID, sessionID gid.GID) (int64, error) {
q := `
UPDATE sessions
SET
@@ -300,13 +300,13 @@ SET
expire_reason = 'revoked'
WHERE
id != @session_id
AND user_id = @user_id
AND identity_id = @identity_id
AND expire_reason IS NULL
`
args := pgx.StrictNamedArgs{
"session_id": sessionID,
"user_id": userID,
"session_id": sessionID,
"identity_id": identityID,
}
result, err := conn.Exec(ctx, q, args)
@@ -321,7 +321,7 @@ func (s *Session) LoadByRootSessionIDAndMembershipID(ctx context.Context, conn p
q := `
SELECT
id,
user_id,
identity_id,
tenant_id,
membership_id,
data,

View File

@@ -38,12 +38,12 @@ func NewAccessManagementService(svc *Service) *AccessManagementService {
}
// Authorize implements Model 2 authorization:
// - principalID is the actor (User now; later service accounts)
// - credentialID is an optional credential (UserAPIKey now)
// - principalID is the actor (Identity now; later service accounts)
// - credentialID is an optional credential (PersonalAPIKey now)
// - intersection semantics: actor must be allowed AND credential (if present) must be allowed.
//
// Entity scope:
// - Global/self-owned entities (User/Session/UserAPIKey) are authorized via ownership checks only (no global admin).
// - Global/self-owned entities (Identity/Session/PersonalAPIKey) are authorized via ownership checks only (no global admin).
// - Organization-scoped entities are authorized via membership lookups that derive organization_id from entityID.
func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid.GID, credentialID *gid.GID, entityID gid.GID, action Action) error {
requiredRoles := GetPermissionsForAction(entityID.EntityType(), action)
@@ -53,7 +53,7 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
}
switch principalID.EntityType() {
case coredata.UserEntityType:
case coredata.IdentityEntityType:
// ok
default:
return NewUnsupportedPrincipalTypeError(principalID.EntityType())
@@ -62,7 +62,7 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
return s.pg.WithConn(ctx, func(conn pg.Conn) error {
// Global/self-owned path
switch entityID.EntityType() {
case coredata.UserEntityType:
case coredata.IdentityEntityType:
if entityID != principalID {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
@@ -73,17 +73,17 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
if err := sess.LoadByID(ctx, conn, entityID); err != nil {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
if sess.UserID != principalID {
if sess.IdentityID != principalID {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
return nil
case coredata.UserAPIKeyEntityType:
key := &coredata.UserAPIKey{}
case coredata.PersonalAPIKeyEntityType:
key := &coredata.PersonalAPIKey{}
if err := key.LoadByID(ctx, conn, entityID); err != nil {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
if key.UserID != principalID {
if key.IdentityID != principalID {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
return nil
@@ -92,7 +92,7 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
// Organization-scoped path (derive org via joins)
scope := coredata.NewScope(entityID.TenantID())
actorRoleName, err := s.loadUserRoleForEntity(ctx, conn, scope, principalID, entityID)
actorRoleName, err := s.loadIdentityRoleForEntity(ctx, conn, scope, principalID, entityID)
if err != nil || !requiredRoleNamesContain(actorRoleName, requiredRoles) {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
@@ -100,13 +100,13 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
// Optional credential restriction (intersection)
if credentialID != nil {
switch credentialID.EntityType() {
case coredata.UserAPIKeyEntityType:
case coredata.PersonalAPIKeyEntityType:
// Defensive check: credential must belong to actor
apiKey := &coredata.UserAPIKey{}
apiKey := &coredata.PersonalAPIKey{}
if err := apiKey.LoadByID(ctx, conn, *credentialID); err != nil {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
if apiKey.UserID != principalID {
if apiKey.IdentityID != principalID {
return NewInsufficientPermissionsError(principalID, entityID, action)
}
@@ -123,15 +123,15 @@ func (s *AccessManagementService) Authorize(ctx context.Context, principalID gid
})
}
func (s *AccessManagementService) loadUserRoleForEntity(
func (s *AccessManagementService) loadIdentityRoleForEntity(
ctx context.Context,
conn pg.Conn,
scope coredata.Scoper,
userID gid.GID,
identityID gid.GID,
entityID gid.GID,
) (Role, error) {
var m coredata.Membership
if err := m.LoadRoleByUserAndEntityID(ctx, conn, scope, userID, entityID); err != nil {
if err := m.LoadRoleByIdentityAndEntityID(ctx, conn, scope, identityID, entityID); err != nil {
// Do not leak existence details
if errors.Is(err, coredata.ErrResourceNotFound) {
return "", err
@@ -148,7 +148,7 @@ func (s *AccessManagementService) loadAPIKeyRoleForEntity(
apiKeyID gid.GID,
entityID gid.GID,
) (Role, error) {
var akm coredata.UserAPIKeyMembership
var akm coredata.PersonalAPIKeyMembership
if err := akm.LoadRoleByAPIKeyAndEntityID(ctx, conn, scope, apiKeyID, entityID); err != nil {
return "", err
}
@@ -173,35 +173,3 @@ func requiredRoleNamesContain(roleName Role, required []Role) bool {
}
return false
}
// func (s AccountService) AllAccessibleTenants(ctx context.Context, identityID gid.GID) ([]gid.TenantID, error) {
// var tenants []gid.TenantID
// err := s.pg.WithConn(
// ctx,
// func(conn pg.Conn) error {
// memberships := coredata.Memberships{}
// orderBy := page.OrderBy[coredata.MembershipOrderField]{
// Field: coredata.MembershipOrderFieldCreatedAt,
// Direction: page.OrderDirectionDesc,
// }
// cursor := page.NewCursor(1000, nil, page.Head, orderBy)
// err := memberships.LoadByUserID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
// if err != nil {
// return fmt.Errorf("cannot load memberships: %w", err)
// }
// for _, membership := range memberships {
// tenants = append(tenants, membership.ID.TenantID())
// }
// return nil
// },
// )
// if err != nil {
// return nil, err
// }
// return tenants, nil
// }

View File

@@ -35,7 +35,7 @@ type (
*Service
}
UserAPIKeyTokenData struct {
PersonalAPIKeyTokenData struct {
Version int `json:"v"`
KeyID gid.GID `json:"kid"`
PrincipalID gid.GID `json:"pid"`
@@ -43,8 +43,8 @@ type (
}
EmailConfirmationData struct {
UserID gid.GID `json:"uid"`
Email mail.Addr `json:"email"`
IdentityID gid.GID `json:"uid"`
Email mail.Addr `json:"email"`
}
)
@@ -78,7 +78,7 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req
s.tokenSecret,
TokenTypeEmailConfirmation,
24*time.Hour,
EmailConfirmationData{UserID: identityID, Email: req.NewEmail},
EmailConfirmationData{IdentityID: identityID, Email: req.NewEmail},
)
if err != nil {
return fmt.Errorf("cannot generate confirmation token: %w", err)
@@ -97,17 +97,17 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
err := user.LoadByID(ctx, tx, identityID)
identity := &coredata.Identity{}
err := identity.LoadByID(ctx, tx, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
isPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(req.Password), user.HashedPassword)
isPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(req.Password), identity.HashedPassword)
if err != nil {
return fmt.Errorf("cannot compare password: %w", err)
}
@@ -116,18 +116,18 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req
return NewInvalidPasswordError("invalid password")
}
user.EmailAddress = req.NewEmail
user.EmailAddressVerified = false
user.UpdatedAt = time.Now()
identity.EmailAddress = req.NewEmail
identity.EmailAddressVerified = false
identity.UpdatedAt = time.Now()
err = user.Update(ctx, tx)
err = identity.Update(ctx, tx)
if err != nil {
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
subject, textBody, htmlBody, err := emails.RenderConfirmEmail(
s.baseURL,
user.FullName,
identity.FullName,
confirmationUrl,
)
if err != nil {
@@ -135,8 +135,8 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req
}
confirmationEmail := coredata.NewEmail(
user.FullName,
user.EmailAddress,
identity.FullName,
identity.EmailAddress,
subject,
textBody,
htmlBody,
@@ -161,30 +161,30 @@ func (s AccountService) VerifyEmail(ctx context.Context, token string) error {
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
err := user.LoadByID(ctx, tx, payload.Data.UserID)
identity := &coredata.Identity{}
err := identity.LoadByID(ctx, tx, payload.Data.IdentityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(payload.Data.UserID)
return NewIdentityNotFoundError(payload.Data.IdentityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
if user.EmailAddress != payload.Data.Email {
if identity.EmailAddress != payload.Data.Email {
return NewEmailVerificationMismatchError()
}
if user.EmailAddressVerified {
if identity.EmailAddressVerified {
return NewEmailAlreadyVerifiedError()
}
user.EmailAddressVerified = true
user.UpdatedAt = time.Now()
identity.EmailAddressVerified = true
identity.UpdatedAt = time.Now()
err = user.Update(ctx, tx)
err = identity.Update(ctx, tx)
if err != nil {
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
return nil
@@ -205,16 +205,16 @@ func (s *AccountService) AcceptInvitation(
err := s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := coredata.User{}
identity := coredata.Identity{}
invitation := coredata.Invitation{}
err := user.LoadByID(ctx, tx, identityID)
err := identity.LoadByID(ctx, tx, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
err = invitation.LoadByID(ctx, tx, coredata.NewNoScope(), invitationID)
@@ -226,7 +226,7 @@ func (s *AccountService) AcceptInvitation(
return fmt.Errorf("cannot load invitation: %w", err)
}
if invitation.Email != user.EmailAddress {
if invitation.Email != identity.EmailAddress {
return NewInvitationNotFoundError(invitationID)
}
@@ -243,7 +243,7 @@ func (s *AccountService) AcceptInvitation(
membership = &coredata.Membership{
ID: gid.New(tenantID, coredata.MembershipEntityType),
UserID: identityID,
IdentityID: identityID,
OrganizationID: invitation.OrganizationID,
Role: invitation.Role,
CreatedAt: now,
@@ -286,11 +286,11 @@ func (s *AccountService) ListPendingInvitations(
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
identity := coredata.User{}
identity := coredata.Identity{}
err := identity.LoadByID(ctx, conn, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load identity: %w", err)
@@ -323,7 +323,7 @@ func (s *AccountService) CountPendingInvitations(
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
identity := coredata.User{}
identity := coredata.Identity{}
err := identity.LoadByID(ctx, conn, identityID)
if err != nil {
return fmt.Errorf("cannot load identity: %w", err)
@@ -357,7 +357,7 @@ func (s *AccountService) ListMemberships(
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := memberships.LoadByUserID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
err := memberships.LoadByIdentityID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
if err != nil {
return fmt.Errorf("cannot load memberships: %w", err)
}
@@ -383,7 +383,7 @@ func (s *AccountService) CountMemberships(
ctx,
func(conn pg.Conn) (err error) {
memberships := coredata.Memberships{}
count, err = memberships.CountByUserID(ctx, conn, identityID)
count, err = memberships.CountByIdentityID(ctx, conn, identityID)
if err != nil {
return fmt.Errorf("cannot count memberships: %w", err)
}
@@ -407,17 +407,17 @@ func (s AccountService) ChangePassword(ctx context.Context, identityID gid.GID,
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
err := user.LoadByID(ctx, tx, identityID)
identity := &coredata.Identity{}
err := identity.LoadByID(ctx, tx, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
isLegacyPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(req.CurrentPassword), user.HashedPassword)
isLegacyPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(req.CurrentPassword), identity.HashedPassword)
if err != nil {
return fmt.Errorf("cannot compare legacy password: %w", err)
}
@@ -431,15 +431,15 @@ func (s AccountService) ChangePassword(ctx context.Context, identityID gid.GID,
return fmt.Errorf("cannot hash new password: %w", err)
}
user.HashedPassword = newPasswordHash
user.UpdatedAt = time.Now()
identity.HashedPassword = newPasswordHash
identity.UpdatedAt = time.Now()
err = user.Update(ctx, tx)
err = identity.Update(ctx, tx)
if err != nil {
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
// TODO: email to notify user that their password has been changed
// TODO: email to notify identity that their password has been changed
return nil
},
@@ -453,7 +453,7 @@ func (s AccountService) CountSessions(ctx context.Context, identityID gid.GID) (
ctx,
func(conn pg.Conn) (err error) {
sessions := coredata.Sessions{}
count, err = sessions.CountByUserID(ctx, conn, identityID)
count, err = sessions.CountByIdentityID(ctx, conn, identityID)
if err != nil {
return fmt.Errorf("cannot count sessions: %w", err)
}
@@ -475,7 +475,7 @@ func (s AccountService) ListSessions(
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := sessions.LoadByUserID(ctx, conn, identityID, cursor)
err := sessions.LoadByIdentityID(ctx, conn, identityID, cursor)
if err != nil {
return fmt.Errorf("cannot load sessions: %w", err)
}
@@ -491,19 +491,19 @@ func (s AccountService) ListSessions(
return page.NewPage(sessions, cursor), nil
}
func (s AccountService) GetIdentity(ctx context.Context, identityID gid.GID) (*coredata.User, error) {
user := &coredata.User{}
func (s AccountService) GetIdentity(ctx context.Context, identityID gid.GID) (*coredata.Identity, error) {
identity := &coredata.Identity{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := user.LoadByID(ctx, conn, identityID)
err := identity.LoadByID(ctx, conn, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
return nil
@@ -513,20 +513,20 @@ func (s AccountService) GetIdentity(ctx context.Context, identityID gid.GID) (*c
return nil, err
}
return user, nil
return identity, nil
}
func (s AccountService) ListPersonalAPIKeys(
ctx context.Context,
identityID gid.GID,
cursor *page.Cursor[coredata.UserAPIKeyOrderField],
) (*page.Page[*coredata.UserAPIKey, coredata.UserAPIKeyOrderField], error) {
var personalAccessTokens coredata.UserAPIKeys
cursor *page.Cursor[coredata.PersonalAPIKeyOrderField],
) (*page.Page[*coredata.PersonalAPIKey, coredata.PersonalAPIKeyOrderField], error) {
var personalAccessTokens coredata.PersonalAPIKeys
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := personalAccessTokens.LoadByUserID(ctx, conn, identityID)
err := personalAccessTokens.LoadByIdentityID(ctx, conn, identityID)
if err != nil {
return fmt.Errorf("cannot load personal access tokens: %w", err)
}
@@ -548,8 +548,8 @@ func (s AccountService) CountPersonalAPIKeys(ctx context.Context, identityID gid
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) (err error) {
personalAccessTokens := coredata.UserAPIKeys{}
count, err = personalAccessTokens.CountByUserID(ctx, conn, identityID)
personalAccessTokens := coredata.PersonalAPIKeys{}
count, err = personalAccessTokens.CountByIdentityID(ctx, conn, identityID)
if err != nil {
return fmt.Errorf("cannot count personal access tokens: %w", err)
}
@@ -561,10 +561,10 @@ func (s AccountService) CountPersonalAPIKeys(ctx context.Context, identityID gid
return count, err
}
func (s AccountService) GetIdentityForMembership(ctx context.Context, membershipID gid.GID) (*coredata.User, error) {
func (s AccountService) GetIdentityForMembership(ctx context.Context, membershipID gid.GID) (*coredata.Identity, error) {
var (
scope = coredata.NewScopeFromObjectID(membershipID)
identity = &coredata.User{}
identity = &coredata.Identity{}
)
err := s.pg.WithConn(
@@ -580,10 +580,10 @@ func (s AccountService) GetIdentityForMembership(ctx context.Context, membership
return fmt.Errorf("cannot load membership: %w", err)
}
err = identity.LoadByID(ctx, conn, membership.UserID)
err = identity.LoadByID(ctx, conn, membership.IdentityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(membership.UserID)
return NewIdentityNotFoundError(membership.IdentityID)
}
return fmt.Errorf("cannot load identity: %w", err)
@@ -605,10 +605,10 @@ func (s *AccountService) CreatePersonalAPIKey(
identityID gid.GID,
name string,
expiresAt time.Time,
) (*coredata.UserAPIKey, string, error) {
) (*coredata.PersonalAPIKey, string, error) {
var (
userAPIKey *coredata.UserAPIKey
token string
personalAPIKey *coredata.PersonalAPIKey
token string
)
err := s.pg.WithTx(
@@ -616,33 +616,33 @@ func (s *AccountService) CreatePersonalAPIKey(
func(tx pg.Conn) (err error) {
now := time.Now()
userAPIKey = &coredata.UserAPIKey{
ID: gid.New(gid.NilTenant, coredata.UserAPIKeyEntityType),
UserID: identityID,
Name: name,
ExpiresAt: expiresAt,
CreatedAt: now,
UpdatedAt: now,
personalAPIKey = &coredata.PersonalAPIKey{
ID: gid.New(gid.NilTenant, coredata.PersonalAPIKeyEntityType),
IdentityID: identityID,
Name: name,
ExpiresAt: expiresAt,
CreatedAt: now,
UpdatedAt: now,
}
if err := userAPIKey.Insert(ctx, tx); err != nil {
return fmt.Errorf("cannot insert user api key: %w", err)
if err := personalAPIKey.Insert(ctx, tx); err != nil {
return fmt.Errorf("cannot insert personal api key: %w", err)
}
token, err = statelesstoken.NewDeterministicToken(
s.tokenSecret,
TokenTypeAPIKey,
userAPIKey.ExpiresAt,
userAPIKey.CreatedAt,
UserAPIKeyTokenData{
personalAPIKey.ExpiresAt,
personalAPIKey.CreatedAt,
PersonalAPIKeyTokenData{
Version: 2,
KeyID: userAPIKey.ID,
KeyID: personalAPIKey.ID,
PrincipalID: identityID,
IssuedAt: userAPIKey.CreatedAt,
IssuedAt: personalAPIKey.CreatedAt,
},
)
if err != nil {
return fmt.Errorf("cannot generate user api key token: %w", err)
return fmt.Errorf("cannot generate personal api key token: %w", err)
}
return nil
@@ -653,34 +653,34 @@ func (s *AccountService) CreatePersonalAPIKey(
return nil, "", err
}
return userAPIKey, token, nil
return personalAPIKey, token, nil
}
func (s *AccountService) DeletePersonalAPIKey(
ctx context.Context,
identityID gid.GID,
userAPIKeyID gid.GID,
personalAPIKeyID gid.GID,
) error {
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
userAPIKey := &coredata.UserAPIKey{}
err := userAPIKey.LoadByID(ctx, tx, userAPIKeyID)
personalAPIKey := &coredata.PersonalAPIKey{}
err := personalAPIKey.LoadByID(ctx, tx, personalAPIKeyID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserAPIKeyNotFoundError(userAPIKeyID)
return NewPersonalAPIKeyNotFoundError(personalAPIKeyID)
}
return fmt.Errorf("cannot load user api key: %w", err)
return fmt.Errorf("cannot load personal api key: %w", err)
}
if userAPIKey.UserID != identityID {
return NewUserAPIKeyNotFoundError(userAPIKeyID)
if personalAPIKey.IdentityID != identityID {
return NewPersonalAPIKeyNotFoundError(personalAPIKeyID)
}
err = userAPIKey.Delete(ctx, tx)
err = personalAPIKey.Delete(ctx, tx)
if err != nil {
return fmt.Errorf("cannot delete user api key: %w", err)
return fmt.Errorf("cannot delete personal api key: %w", err)
}
return nil
@@ -699,7 +699,7 @@ func (s AccountService) ListOrganizations(ctx context.Context, identityID gid.GI
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := organizations.LoadByUserID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
err := organizations.LoadByIdentityID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
if err != nil {
return fmt.Errorf("cannot load organizations: %w", err)
}
@@ -714,35 +714,3 @@ func (s AccountService) ListOrganizations(ctx context.Context, identityID gid.GI
return organizations, nil
}
// func (s AccountService) AllAccessibleTenants(ctx context.Context, identityID gid.GID) ([]gid.TenantID, error) {
// var tenants []gid.TenantID
// err := s.pg.WithConn(
// ctx,
// func(conn pg.Conn) error {
// memberships := coredata.Memberships{}
// orderBy := page.OrderBy[coredata.MembershipOrderField]{
// Field: coredata.MembershipOrderFieldCreatedAt,
// Direction: page.OrderDirectionDesc,
// }
// cursor := page.NewCursor(1000, nil, page.Head, orderBy)
// err := memberships.LoadByUserID(ctx, conn, coredata.NewNoScope(), identityID, cursor)
// if err != nil {
// return fmt.Errorf("cannot load memberships: %w", err)
// }
// for _, membership := range memberships {
// tenants = append(tenants, membership.ID.TenantID())
// }
// return nil
// },
// )
// if err != nil {
// return nil, err
// }
// return tenants, nil
// }

View File

@@ -35,9 +35,9 @@ func NewAPIKeyService(svc *Service) *APIKeyService {
return &APIKeyService{Service: svc}
}
func (s *APIKeyService) GetAPIKey(ctx context.Context, keyID gid.GID) (*coredata.UserAPIKey, error) {
func (s *APIKeyService) GetAPIKey(ctx context.Context, keyID gid.GID) (*coredata.PersonalAPIKey, error) {
var (
apiKey = &coredata.UserAPIKey{}
apiKey = &coredata.PersonalAPIKey{}
now = time.Now()
)
@@ -46,12 +46,12 @@ func (s *APIKeyService) GetAPIKey(ctx context.Context, keyID gid.GID) (*coredata
func(tx pg.Conn) error {
if err := apiKey.LoadByID(ctx, tx, keyID); err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserAPIKeyNotFoundError(keyID)
return NewPersonalAPIKeyNotFoundError(keyID)
}
}
if apiKey.ExpireReason != nil {
return NewUserAPIKeyExpiredError(keyID)
return NewPersonalAPIKeyExpiredError(keyID)
}
if now.After(apiKey.ExpiresAt) {
@@ -60,10 +60,10 @@ func (s *APIKeyService) GetAPIKey(ctx context.Context, keyID gid.GID) (*coredata
apiKey.UpdatedAt = now
if err := apiKey.Update(ctx, tx); err != nil {
return fmt.Errorf("cannot update user api key: %w", err)
return fmt.Errorf("cannot update personal api key: %w", err)
}
return NewUserAPIKeyExpiredError(keyID)
return NewPersonalAPIKeyExpiredError(keyID)
}
return nil

View File

@@ -110,7 +110,7 @@ func (req CreateIdentityWithPasswordRequest) Validate() error {
func (s *AuthService) CreateIdentityFromInvitation(
ctx context.Context,
req *CreateIdentityFromInvitationRequest,
) (*coredata.User, *coredata.Session, error) {
) (*coredata.Identity, *coredata.Session, error) {
if err := req.Validate(); err != nil {
return nil, nil, fmt.Errorf("invalid request: %w", err)
}
@@ -123,7 +123,7 @@ func (s *AuthService) CreateIdentityFromInvitation(
var (
scope = coredata.NewScopeFromObjectID(payload.Data.InvitationID)
invitation = &coredata.Invitation{}
user = &coredata.User{}
identity = &coredata.Identity{}
session = &coredata.Session{}
now = time.Now()
)
@@ -153,8 +153,8 @@ func (s *AuthService) CreateIdentityFromInvitation(
return NewInvitationExpiredError(payload.Data.InvitationID)
}
user = &coredata.User{
ID: gid.New(gid.NilTenant, coredata.UserEntityType),
identity = &coredata.Identity{
ID: gid.New(gid.NilTenant, coredata.IdentityEntityType),
EmailAddress: invitation.Email,
HashedPassword: hashedPassword,
EmailAddressVerified: true,
@@ -163,16 +163,16 @@ func (s *AuthService) CreateIdentityFromInvitation(
UpdatedAt: now,
}
err = user.Insert(ctx, tx)
err = identity.Insert(ctx, tx)
if err != nil {
if err == coredata.ErrResourceAlreadyExists {
return NewUserAlreadyExistsError(invitation.Email)
return NewIdentityAlreadyExistsError(invitation.Email)
}
return fmt.Errorf("cannot insert user: %w", err)
return fmt.Errorf("cannot insert identity: %w", err)
}
session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, s.sessionDuration)
session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, s.sessionDuration)
err = session.Insert(ctx, tx)
if err != nil {
return fmt.Errorf("cannot insert session: %w", err)
@@ -186,7 +186,7 @@ func (s *AuthService) CreateIdentityFromInvitation(
return nil, nil, err
}
return user, session, nil
return identity, session, nil
}
func (s AuthService) ResetPassword(
@@ -210,26 +210,26 @@ func (s AuthService) ResetPassword(
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
err := user.LoadByEmail(ctx, tx, payload.Data.Email)
identity := &coredata.Identity{}
err := identity.LoadByEmail(ctx, tx, payload.Data.Email)
if err != nil {
if err == coredata.ErrResourceNotFound {
return nil // Don't leak information about non-existent users
return nil // Don't leak information about non-existent identities
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
user.HashedPassword = hashedPassword
user.UpdatedAt = time.Now()
identity.HashedPassword = hashedPassword
identity.UpdatedAt = time.Now()
err = user.Update(ctx, tx)
err = identity.Update(ctx, tx)
if err != nil {
if err == coredata.ErrResourceNotFound {
return nil // Don't leak information about non-existent users
return nil // Don't leak information about non-existent identities
}
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
return nil
@@ -264,18 +264,18 @@ func (s AuthService) SendPasswordResetInstructionByEmail(
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
if err := user.LoadByEmail(ctx, tx, email); err != nil {
identity := &coredata.Identity{}
if err := identity.LoadByEmail(ctx, tx, email); err != nil {
if err == coredata.ErrResourceNotFound {
return nil // Don't leak information about non-existent users
return nil // Don't leak information about non-existent identities
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
subject, textBody, htmlBody, err := emails.RenderPasswordReset(
s.baseURL,
user.FullName,
identity.FullName,
resetPasswordUrl,
)
if err != nil {
@@ -283,8 +283,8 @@ func (s AuthService) SendPasswordResetInstructionByEmail(
}
passwordResetEmail := coredata.NewEmail(
user.FullName,
user.EmailAddress,
identity.FullName,
identity.EmailAddress,
subject,
textBody,
htmlBody,
@@ -303,7 +303,7 @@ func (s AuthService) SendPasswordResetInstructionByEmail(
func (s AuthService) CreateIdentityWithPassword(
ctx context.Context,
req *CreateIdentityWithPasswordRequest,
) (*coredata.User, *coredata.Session, error) {
) (*coredata.Identity, *coredata.Session, error) {
if s.disableSignup { // TODO Rename this one to disableSignup
return nil, nil, NewErrSignupDisabled()
}
@@ -320,8 +320,8 @@ func (s AuthService) CreateIdentityWithPassword(
var (
now = time.Now()
user = &coredata.User{
ID: gid.New(gid.NilTenant, coredata.UserEntityType),
identity = &coredata.Identity{
ID: gid.New(gid.NilTenant, coredata.IdentityEntityType),
EmailAddress: req.Email,
HashedPassword: hashedPassword,
EmailAddressVerified: false,
@@ -330,14 +330,14 @@ func (s AuthService) CreateIdentityWithPassword(
UpdatedAt: now,
}
session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, 24*time.Hour*7)
session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, 24*time.Hour*7)
)
confirmationToken, err := statelesstoken.NewToken(
s.tokenSecret,
TokenTypeEmailConfirmation,
24*time.Hour,
EmailConfirmationData{UserID: user.ID, Email: user.EmailAddress},
EmailConfirmationData{IdentityID: identity.ID, Email: identity.EmailAddress},
)
if err != nil {
return nil, nil, fmt.Errorf("cannot generate confirmation token: %w", err)
@@ -358,7 +358,7 @@ func (s AuthService) CreateIdentityWithPassword(
subject, textBody, htmlBody, err := emails.RenderConfirmEmail(
s.baseURL,
user.FullName,
identity.FullName,
confirmationUrl,
)
if err != nil {
@@ -366,8 +366,8 @@ func (s AuthService) CreateIdentityWithPassword(
}
confirmationEmail := coredata.NewEmail(
user.FullName,
user.EmailAddress,
identity.FullName,
identity.EmailAddress,
subject,
textBody,
htmlBody,
@@ -376,13 +376,13 @@ func (s AuthService) CreateIdentityWithPassword(
err = s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
err := user.Insert(ctx, tx)
err := identity.Insert(ctx, tx)
if err != nil {
if err == coredata.ErrResourceAlreadyExists {
return NewUserAlreadyExistsError(user.EmailAddress)
return NewIdentityAlreadyExistsError(identity.EmailAddress)
}
return fmt.Errorf("cannot insert user: %w", err)
return fmt.Errorf("cannot insert identity: %w", err)
}
if err := confirmationEmail.Insert(ctx, tx); err != nil {
@@ -397,16 +397,16 @@ func (s AuthService) CreateIdentityWithPassword(
},
)
return user, session, err
return identity, session, err
}
func (s AuthService) OpenSessionWithSAML(ctx context.Context, userID gid.GID, organizationID gid.GID) (*coredata.Session, error) {
func (s AuthService) OpenSessionWithSAML(ctx context.Context, identityID gid.GID, organizationID gid.GID) (*coredata.Session, error) {
session := &coredata.Session{}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) (err error) {
session = coredata.NewRootSession(userID, coredata.AuthMethodSAML, s.sessionDuration)
session = coredata.NewRootSession(identityID, coredata.AuthMethodSAML, s.sessionDuration)
err = session.Insert(ctx, conn)
if err != nil {
return fmt.Errorf("cannot insert session: %w", err)
@@ -423,7 +423,7 @@ func (s AuthService) OpenSessionWithSAML(ctx context.Context, userID gid.GID, or
return session, nil
}
func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Addr, password string) (*coredata.User, *coredata.Session, error) {
func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Addr, password string) (*coredata.Identity, *coredata.Session, error) {
v := validator.New()
v.Check(password, "password", PasswordValidator())
@@ -433,29 +433,29 @@ func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Add
}
var (
user = &coredata.User{}
session = &coredata.Session{}
identity = &coredata.Identity{}
session = &coredata.Session{}
)
err = s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
err := user.LoadByEmail(ctx, conn, email)
err := identity.LoadByEmail(ctx, conn, email)
if err != nil {
// Do not leak information about non-existent users
// Do not leak information about non-existent identities
if err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load user by email: %w", err)
return fmt.Errorf("cannot load identity by email: %w", err)
}
}
// Perform a password comparison even when the user does not exist to mitigate timing attacks
// Perform a password comparison even when the identity does not exist to mitigate timing attacks
// and prevent revealing account existence.
if user.ID == gid.Nil {
if identity.ID == gid.Nil {
s.hp.ComparePasswordAndHash([]byte(password+"qwertyuiop1234567890"), []byte("qwertyuiop1234567890"))
return NewInvalidCredentialsError("invalid email or password")
}
isPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(password), user.HashedPassword)
isPasswordMatch, err := s.hp.ComparePasswordAndHash([]byte(password), identity.HashedPassword)
if err != nil {
return fmt.Errorf("cannot verify password: %w", err)
}
@@ -464,7 +464,7 @@ func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Add
return NewInvalidCredentialsError("invalid email or password")
}
session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, s.sessionDuration)
session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, s.sessionDuration)
err = session.Insert(ctx, conn)
if err != nil {
return fmt.Errorf("cannot insert session: %w", err)
@@ -474,5 +474,5 @@ func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Add
},
)
return user, session, err
return identity, session, err
}

View File

@@ -70,7 +70,7 @@ type AuthorizeParams struct {
// It combines self-management policies with role-based policies.
func (a *Authorizer) Authorize(ctx context.Context, params AuthorizeParams) error {
// Validate principal type
if params.Principal.EntityType() != coredata.UserEntityType {
if params.Principal.EntityType() != coredata.IdentityEntityType {
return NewUnsupportedPrincipalTypeError(params.Principal.EntityType())
}
@@ -135,7 +135,7 @@ func (a *Authorizer) loadRolePolicies(ctx context.Context, principalID gid.GID,
scope := coredata.NewScope(resourceID.TenantID())
var m coredata.Membership
if err := m.LoadRoleByUserAndEntityID(ctx, conn, scope, principalID, resourceID); err != nil {
if err := m.LoadRoleByIdentityAndEntityID(ctx, conn, scope, principalID, resourceID); err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil // No membership = no role-based policies
}

View File

@@ -61,14 +61,14 @@ func (e ErrInvitationExpired) Error() string {
return fmt.Sprintf("invitation %q expired", e.InvitationID)
}
type ErrUserAlreadyExists struct{ EmailAddress mail.Addr }
type ErrIdentityAlreadyExists struct{ EmailAddress mail.Addr }
func NewUserAlreadyExistsError(emailAddress mail.Addr) error {
return &ErrUserAlreadyExists{EmailAddress: emailAddress}
func NewIdentityAlreadyExistsError(emailAddress mail.Addr) error {
return &ErrIdentityAlreadyExists{EmailAddress: emailAddress}
}
func (e ErrUserAlreadyExists) Error() string {
return fmt.Sprintf("user %q already exists", e.EmailAddress.String())
func (e ErrIdentityAlreadyExists) Error() string {
return fmt.Sprintf("identity %q already exists", e.EmailAddress.String())
}
type ErrEmailAlreadyVerified struct{ message string }
@@ -81,14 +81,14 @@ func (e ErrEmailAlreadyVerified) Error() string {
return e.message
}
type ErrUserNotFound struct{ UserID gid.GID }
type ErrIdentityNotFound struct{ IdentityID gid.GID }
func NewUserNotFoundError(userID gid.GID) error {
return &ErrUserNotFound{userID}
func NewIdentityNotFoundError(identityID gid.GID) error {
return &ErrIdentityNotFound{identityID}
}
func (e ErrUserNotFound) Error() string {
return fmt.Sprintf("user %q not found", e.UserID)
func (e ErrIdentityNotFound) Error() string {
return fmt.Sprintf("identity %q not found", e.IdentityID)
}
type ErrInvalidPassword struct{ message string }
@@ -168,16 +168,16 @@ func (e ErrSessionExpired) Error() string {
}
type ErrMembershipAlreadyExists struct {
UserID gid.GID
IdentityID gid.GID
OrganizationID gid.GID
}
func NewMembershipAlreadyExistsError(userID gid.GID, organizationID gid.GID) error {
return &ErrMembershipAlreadyExists{UserID: userID, OrganizationID: organizationID}
func NewMembershipAlreadyExistsError(identityID gid.GID, organizationID gid.GID) error {
return &ErrMembershipAlreadyExists{IdentityID: identityID, OrganizationID: organizationID}
}
func (e ErrMembershipAlreadyExists) Error() string {
return fmt.Sprintf("membership already exists for user %q in organization %q", e.UserID, e.OrganizationID)
return fmt.Sprintf("membership already exists for identity %q in organization %q", e.IdentityID, e.OrganizationID)
}
type ErrSAMLConfigurationNotFound struct{ ConfigID gid.GID }
@@ -190,24 +190,24 @@ func (e ErrSAMLConfigurationNotFound) Error() string {
return fmt.Sprintf("SAML configuration %q not found", e.ConfigID)
}
type ErrUserAPIKeyNotFound struct{ UserAPIKeyID gid.GID }
type ErrPersonalAPIKeyNotFound struct{ PersonalAPIKeyID gid.GID }
func NewUserAPIKeyNotFoundError(userAPIKeyID gid.GID) error {
return &ErrUserAPIKeyNotFound{UserAPIKeyID: userAPIKeyID}
func NewPersonalAPIKeyNotFoundError(personalAPIKeyID gid.GID) error {
return &ErrPersonalAPIKeyNotFound{PersonalAPIKeyID: personalAPIKeyID}
}
func (e ErrUserAPIKeyNotFound) Error() string {
return fmt.Sprintf("user API key %q not found", e.UserAPIKeyID)
func (e ErrPersonalAPIKeyNotFound) Error() string {
return fmt.Sprintf("personal API key %q not found", e.PersonalAPIKeyID)
}
type ErrUserAPIKeyExpired struct{ UserAPIKeyID gid.GID }
type ErrPersonalAPIKeyExpired struct{ PersonalAPIKeyID gid.GID }
func NewUserAPIKeyExpiredError(userAPIKeyID gid.GID) error {
return &ErrUserAPIKeyExpired{UserAPIKeyID: userAPIKeyID}
func NewPersonalAPIKeyExpiredError(personalAPIKeyID gid.GID) error {
return &ErrPersonalAPIKeyExpired{PersonalAPIKeyID: personalAPIKeyID}
}
func (e ErrUserAPIKeyExpired) Error() string {
return fmt.Sprintf("user API key %q expired", e.UserAPIKeyID)
func (e ErrPersonalAPIKeyExpired) Error() string {
return fmt.Sprintf("personal API key %q expired", e.PersonalAPIKeyID)
}
type ErrSAMLConfigurationDomainNotVerified struct{ ConfigID gid.GID }

View File

@@ -307,22 +307,22 @@ func (s *OrganizationService) InviteMember(
return fmt.Errorf("cannot load organization: %w", err)
}
user := &coredata.User{}
err = user.LoadByEmail(ctx, tx, emailAddress)
identity := &coredata.Identity{}
err = identity.LoadByEmail(ctx, tx, emailAddress)
if err != nil && err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
userExists := user.ID != gid.Nil
if userExists {
identityExists := identity.ID != gid.Nil
if identityExists {
membership := &coredata.Membership{}
err = membership.LoadByUserAndOrg(ctx, tx, scope, user.ID, organizationID)
err = membership.LoadByIdentityAndOrg(ctx, tx, scope, identity.ID, organizationID)
if err != nil && err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load membership: %w", err)
}
if membership.ID != gid.Nil {
return NewMembershipAlreadyExistsError(user.ID, organizationID)
return NewMembershipAlreadyExistsError(identity.ID, organizationID)
}
}
@@ -506,7 +506,7 @@ func (s *OrganizationService) CreateOrganization(
membership := &coredata.Membership{
ID: gid.New(tenantID, coredata.MembershipEntityType),
UserID: identityID,
IdentityID: identityID,
OrganizationID: organizationID,
Role: coredata.MembershipRoleOwner,
CreatedAt: now,

View File

@@ -413,7 +413,7 @@ var Permissions = map[uint16]map[Action][]Role{
ActionGetTrustCenterFile: EditRoles,
ActionDeleteTrustCenterFile: EditRoles,
},
coredata.UserEntityType: {
coredata.IdentityEntityType: {
ActionGet: NonEmployeeRoles,
},
coredata.MembershipEntityType: {

View File

@@ -171,10 +171,10 @@ func (s *Service) HandleAssertion(
ctx context.Context,
samlResponse string,
configID gid.GID,
) (*coredata.User, *coredata.Membership, error) {
) (*coredata.Identity, *coredata.Membership, error) {
var (
now = time.Now()
user = &coredata.User{}
identity = &coredata.Identity{}
membership = &coredata.Membership{}
)
@@ -251,12 +251,12 @@ func (s *Service) HandleAssertion(
return NewEmailDomainMismatchError(email, config.EmailDomain)
}
err = user.LoadByEmail(ctx, tx, email)
err = identity.LoadByEmail(ctx, tx, email)
if err == coredata.ErrResourceNotFound && !config.AutoSignupEnabled {
return NewSAMLAutoSignupDisabledError(config.ID)
} else if err == coredata.ErrResourceNotFound && config.AutoSignupEnabled {
*user = coredata.User{
ID: gid.New(gid.NilTenant, coredata.UserEntityType),
*identity = coredata.Identity{
ID: gid.New(gid.NilTenant, coredata.IdentityEntityType),
EmailAddress: email,
HashedPassword: nil,
EmailAddressVerified: true,
@@ -265,26 +265,26 @@ func (s *Service) HandleAssertion(
UpdatedAt: now,
}
err := user.Insert(ctx, tx)
err := identity.Insert(ctx, tx)
if err != nil {
return fmt.Errorf("cannot insert user: %w", err)
return fmt.Errorf("cannot insert identity: %w", err)
}
} else if err != nil {
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
} else {
user.SAMLSubject = &assertion.Subject.NameID.Value
user.FullName = fullname
user.EmailAddress = email
user.EmailAddressVerified = true
user.UpdatedAt = now
identity.SAMLSubject = &assertion.Subject.NameID.Value
identity.FullName = fullname
identity.EmailAddress = email
identity.EmailAddressVerified = true
identity.UpdatedAt = now
err = user.Update(ctx, tx)
err = identity.Update(ctx, tx)
if err != nil {
return fmt.Errorf("cannot update user: %w", err)
return fmt.Errorf("cannot update identity: %w", err)
}
}
err = membership.LoadByUserAndOrg(ctx, tx, coredata.NewNoScope(), user.ID, config.OrganizationID)
err = membership.LoadByIdentityAndOrg(ctx, tx, coredata.NewNoScope(), identity.ID, config.OrganizationID)
if err != nil && err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load membership: %w", err)
}
@@ -293,7 +293,7 @@ func (s *Service) HandleAssertion(
if !isMember {
membership = &coredata.Membership{
ID: gid.New(config.ID.TenantID(), coredata.MembershipEntityType),
UserID: user.ID,
IdentityID: identity.ID,
OrganizationID: config.OrganizationID,
Role: coredata.MembershipRoleViewer,
CreatedAt: now,
@@ -324,7 +324,7 @@ func (s *Service) HandleAssertion(
return nil, nil, err
}
return user, membership, nil
return identity, membership, nil
}
func (s *Service) validateAssertion(assertion *saml.Assertion, config *coredata.SAMLConfiguration, now time.Time) error {

View File

@@ -129,14 +129,14 @@ func (s SessionService) RevokeSession(ctx context.Context, identityID gid.GID, s
return s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
err := user.LoadByID(ctx, tx, identityID)
identity := &coredata.Identity{}
err := identity.LoadByID(ctx, tx, identityID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewUserNotFoundError(identityID)
return NewIdentityNotFoundError(identityID)
}
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
session := &coredata.Session{}
@@ -150,7 +150,7 @@ func (s SessionService) RevokeSession(ctx context.Context, identityID gid.GID, s
}
// TODO: move to dedicated query instead of LoadByID
if session.UserID != identityID {
if session.IdentityID != identityID {
return NewSessionNotFoundError(sessionID)
}
@@ -192,7 +192,7 @@ func (s SessionService) RevokeAllSessions(ctx context.Context, currentSessionID
}
sessions := coredata.Sessions{}
count, err = sessions.ExpireAllForUserExceptOneSession(ctx, tx, session.UserID, session.ID)
count, err = sessions.ExpireAllForIdentityExceptOneSession(ctx, tx, session.IdentityID, session.ID)
if err != nil {
return fmt.Errorf("cannot expire all sessions: %w", err)
}
@@ -323,7 +323,7 @@ func (s SessionService) AssumeOrganizationSession(
var (
now = time.Now()
rootSession = &coredata.Session{}
user = &coredata.User{}
identity = &coredata.Identity{}
membership = &coredata.Membership{}
childSession = &coredata.Session{}
scope = coredata.NewScopeFromObjectID(organizationID)
@@ -348,12 +348,12 @@ func (s SessionService) AssumeOrganizationSession(
return NewSessionExpiredError(sessionID)
}
err = user.LoadByID(ctx, tx, rootSession.UserID)
err = identity.LoadByID(ctx, tx, rootSession.IdentityID)
if err != nil {
return fmt.Errorf("cannot load user: %w", err)
return fmt.Errorf("cannot load identity: %w", err)
}
err = membership.LoadByUserInOrganization(ctx, tx, rootSession.UserID, organizationID)
err = membership.LoadByIdentityInOrganization(ctx, tx, rootSession.IdentityID, organizationID)
if err != nil {
if err == coredata.ErrResourceNotFound {
return NewMembershipNotFoundError(organizationID)
@@ -367,7 +367,7 @@ func (s SessionService) AssumeOrganizationSession(
tx,
scope,
organizationID,
user.EmailAddress.Domain(),
identity.EmailAddress.Domain(),
)
if err != nil && err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load SAML configuration: %w", err)
@@ -389,7 +389,7 @@ func (s SessionService) AssumeOrganizationSession(
tenantID := scope.GetTenantID()
childSession = &coredata.Session{
ID: gid.New(tenantID, coredata.SessionEntityType),
UserID: rootSession.UserID,
IdentityID: rootSession.IdentityID,
TenantID: &tenantID,
MembershipID: &membership.ID,
ParentSessionID: &rootSession.ID,

View File

@@ -31,8 +31,8 @@ var (
apiKeyContextKey = &ctxKey{name: "api_key"}
)
func APIKeyFromContext(ctx context.Context) *coredata.UserAPIKey {
apiKey, _ := ctx.Value(apiKeyContextKey).(*coredata.UserAPIKey)
func APIKeyFromContext(ctx context.Context) *coredata.PersonalAPIKey {
apiKey, _ := ctx.Value(apiKeyContextKey).(*coredata.PersonalAPIKey)
return apiKey
}
@@ -62,30 +62,30 @@ func NewAPIKeyMiddleware(svc *iam.Service) func(next http.Handler) http.Handler
apiKey, err := svc.APIKeyService.GetAPIKey(ctx, keyID)
if err != nil {
var errUserAPIKeyNotFound *iam.ErrUserAPIKeyNotFound
var errUserAPIKeyExpired *iam.ErrUserAPIKeyExpired
var errPersonalAPIKeyNotFound *iam.ErrPersonalAPIKeyNotFound
var errPersonalAPIKeyExpired *iam.ErrPersonalAPIKeyExpired
if errors.As(err, &errUserAPIKeyNotFound) || errors.As(err, &errUserAPIKeyExpired) {
if errors.As(err, &errPersonalAPIKeyNotFound) || errors.As(err, &errPersonalAPIKeyExpired) {
next.ServeHTTP(w, r)
return
}
panic(fmt.Errorf("cannot get user API key: %w", err))
panic(fmt.Errorf("cannot get personal API key: %w", err))
}
user, err := svc.AccountService.GetIdentity(ctx, apiKey.UserID)
identity, err := svc.AccountService.GetIdentity(ctx, apiKey.IdentityID)
if err != nil {
var errUserNotFound *iam.ErrUserNotFound
if errors.As(err, &errUserNotFound) {
var errIdentityNotFound *iam.ErrIdentityNotFound
if errors.As(err, &errIdentityNotFound) {
next.ServeHTTP(w, r)
return
}
panic(fmt.Errorf("cannot get user: %w", err))
panic(fmt.Errorf("cannot get identity: %w", err))
}
ctx = context.WithValue(ctx, apiKeyContextKey, apiKey)
ctx = context.WithValue(ctx, identityContextKey, user)
ctx = context.WithValue(ctx, identityContextKey, identity)
next.ServeHTTP(w, r.WithContext(ctx))
},

View File

@@ -70,7 +70,7 @@ func SessionDirective(ctx context.Context, obj any, next graphql.Resolver, requi
}
func IsViewerDirective(ctx context.Context, obj any, next graphql.Resolver) (any, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
switch node := obj.(type) {
case *types.Identity:

View File

@@ -38,9 +38,9 @@ func SessionFromContext(ctx context.Context) *coredata.Session {
return session
}
func UserFromContext(ctx context.Context) *coredata.User {
user, _ := ctx.Value(identityContextKey).(*coredata.User)
return user
func IdentityFromContext(ctx context.Context) *coredata.Identity {
identity, _ := ctx.Value(identityContextKey).(*coredata.Identity)
return identity
}
func NewSessionMiddleware(svc *iam.Service, cookieConfig securecookie.Config) func(next http.Handler) http.Handler {
@@ -82,16 +82,16 @@ func NewSessionMiddleware(svc *iam.Service, cookieConfig securecookie.Config) fu
panic(fmt.Errorf("cannot get session: %w", err))
}
user, err := svc.AccountService.GetIdentity(ctx, session.UserID)
identity, err := svc.AccountService.GetIdentity(ctx, session.IdentityID)
if err != nil {
var errUserNotFound *iam.ErrUserNotFound
if errors.As(err, &errUserNotFound) {
var errIdentityNotFound *iam.ErrIdentityNotFound
if errors.As(err, &errIdentityNotFound) {
securecookie.Clear(w, cookieConfig)
next.ServeHTTP(w, r)
return
}
panic(fmt.Errorf("cannot get user: %w", err))
panic(fmt.Errorf("cannot get identity: %w", err))
}
userAgent := r.UserAgent()
@@ -109,7 +109,7 @@ func NewSessionMiddleware(svc *iam.Service, cookieConfig securecookie.Config) fu
}
ctx = context.WithValue(ctx, sessionContextKey, session)
ctx = context.WithValue(ctx, identityContextKey, user)
ctx = context.WithValue(ctx, identityContextKey, identity)
next.ServeHTTP(w, r.WithContext(ctx))

View File

@@ -16,7 +16,7 @@ package types
import "go.probo.inc/probo/pkg/coredata"
func NewIdentity(identity *coredata.User) *Identity {
func NewIdentity(identity *coredata.Identity) *Identity {
return &Identity{
ID: identity.ID,
Email: identity.EmailAddress,

View File

@@ -62,7 +62,7 @@ func NewMembershipEdge(membership *coredata.Membership, orderField coredata.Memb
func NewMembership(membership *coredata.Membership) *Membership {
return &Membership{
ID: membership.ID,
IdentityID: membership.UserID,
IdentityID: membership.IdentityID,
CreatedAt: membership.CreatedAt,
// Permissions: membership.Permissions,
// ProvisionedBy: membership.ProvisionedBy,

View File

@@ -21,7 +21,7 @@ import (
)
type (
PersonalAPIKeyOrderBy OrderBy[coredata.UserAPIKeyOrderField]
PersonalAPIKeyOrderBy OrderBy[coredata.PersonalAPIKeyOrderField]
PersonalAPIKeyConnection struct {
TotalCount int
@@ -34,7 +34,7 @@ type (
)
func NewPersonalAPIKeyConnection(
p *page.Page[*coredata.UserAPIKey, coredata.UserAPIKeyOrderField],
p *page.Page[*coredata.PersonalAPIKey, coredata.PersonalAPIKeyOrderField],
resolver any,
parentID gid.GID,
) *PersonalAPIKeyConnection {
@@ -52,14 +52,14 @@ func NewPersonalAPIKeyConnection(
}
}
func NewPersonalAPIKeyEdge(personalAPIKey *coredata.UserAPIKey, orderField coredata.UserAPIKeyOrderField) *PersonalAPIKeyEdge {
func NewPersonalAPIKeyEdge(personalAPIKey *coredata.PersonalAPIKey, orderField coredata.PersonalAPIKeyOrderField) *PersonalAPIKeyEdge {
return &PersonalAPIKeyEdge{
Node: NewPersonalAPIKey(personalAPIKey),
Cursor: personalAPIKey.CursorKey(orderField),
}
}
func NewPersonalAPIKey(personalAPIKey *coredata.UserAPIKey) *PersonalAPIKey {
func NewPersonalAPIKey(personalAPIKey *coredata.PersonalAPIKey) *PersonalAPIKey {
return &PersonalAPIKey{
ID: personalAPIKey.ID,
Name: personalAPIKey.Name,

View File

@@ -63,7 +63,7 @@ func NewSession(session *coredata.Session) *Session {
return &Session{
ID: session.ID,
IPAddress: session.IPAddress.String(),
IdentityID: session.UserID,
IdentityID: session.IdentityID,
UserAgent: session.UserAgent,
UpdatedAt: session.UpdatedAt,
CreatedAt: session.CreatedAt,

View File

@@ -89,8 +89,8 @@ func (r *identityResolver) Sessions(ctx context.Context, obj *types.Identity, fi
// PersonalAPIKeys is the resolver for the personalAPIKeys field.
func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error) {
pageOrderBy := page.OrderBy[coredata.UserAPIKeyOrderField]{
Field: coredata.UserAPIKeyOrderFieldCreatedAt,
pageOrderBy := page.OrderBy[coredata.PersonalAPIKeyOrderField]{
Field: coredata.PersonalAPIKeyOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
@@ -233,8 +233,8 @@ func (r *mutationResolver) SignUp(ctx context.Context, input types.SignUpInput)
},
)
if err != nil {
var errUserAlreadyExists *iam.ErrUserAlreadyExists
if errors.As(err, &errUserAlreadyExists) {
var errIdentityAlreadyExists *iam.ErrIdentityAlreadyExists
if errors.As(err, &errIdentityAlreadyExists) {
return nil, gqlutils.Invalid(err, nil)
}
@@ -287,7 +287,7 @@ func (r *mutationResolver) SignUpFromInvitation(ctx context.Context, input types
errInvitationNotFound *iam.ErrInvitationNotFound
errInvitationAlreadyAccepted *iam.ErrInvitationAlreadyAccepted
errInvitationExpired *iam.ErrInvitationExpired
errUserAlreadyExists *iam.ErrUserAlreadyExists
errIdentityAlreadyExists *iam.ErrIdentityAlreadyExists
isInvalidErr = errors.As(err, &errInvalidToken) ||
errors.As(err, &errInvitationNotFound) ||
@@ -299,7 +299,7 @@ func (r *mutationResolver) SignUpFromInvitation(ctx context.Context, input types
return nil, gqlutils.Invalid(err, nil)
}
if errors.As(err, &errUserAlreadyExists) {
if errors.As(err, &errIdentityAlreadyExists) {
return nil, gqlutils.Conflict(err)
}
@@ -371,7 +371,7 @@ func (r *mutationResolver) VerifyEmail(ctx context.Context, input types.VerifyEm
if err != nil {
var (
errInvalidToken *iam.ErrInvalidToken
errUserNotFound *iam.ErrUserNotFound
errIdentityNotFound *iam.ErrIdentityNotFound
errEmailAlreadyVerified *iam.ErrEmailAlreadyVerified
errEmailVerificationMismatch *iam.ErrEmailVerificationMismatch
@@ -387,7 +387,7 @@ func (r *mutationResolver) VerifyEmail(ctx context.Context, input types.VerifyEm
return nil, gqlutils.Conflict(err)
}
if errors.As(err, &errUserNotFound) {
if errors.As(err, &errIdentityNotFound) {
return nil, gqlutils.NotFound(err)
}
@@ -402,7 +402,7 @@ func (r *mutationResolver) VerifyEmail(ctx context.Context, input types.VerifyEm
// ChangePassword is the resolver for the changePassword field.
func (r *mutationResolver) ChangePassword(ctx context.Context, input types.ChangePasswordInput) (*types.ChangePasswordPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
err := r.iam.AccountService.ChangePassword(
ctx,
@@ -414,15 +414,15 @@ func (r *mutationResolver) ChangePassword(ctx context.Context, input types.Chang
)
if err != nil {
var (
errInvalidPassword *iam.ErrInvalidPassword
errUserNotFound *iam.ErrUserNotFound
errInvalidPassword *iam.ErrInvalidPassword
errIdentityNotFound *iam.ErrIdentityNotFound
)
if errors.As(err, &errInvalidPassword) {
return nil, gqlutils.Invalid(err, nil)
}
if errors.As(err, &errUserNotFound) {
if errors.As(err, &errIdentityNotFound) {
return nil, gqlutils.NotFound(err)
}
@@ -437,7 +437,7 @@ func (r *mutationResolver) ChangePassword(ctx context.Context, input types.Chang
// ChangeEmail is the resolver for the changeEmail field.
func (r *mutationResolver) ChangeEmail(ctx context.Context, input types.ChangeEmailInput) (*types.ChangeEmailPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
err := r.iam.AccountService.ChangeEmail(
ctx,
@@ -449,15 +449,15 @@ func (r *mutationResolver) ChangeEmail(ctx context.Context, input types.ChangeEm
)
if err != nil {
var (
errInvalidPassword *iam.ErrInvalidPassword
errUserNotFound *iam.ErrUserNotFound
errInvalidPassword *iam.ErrInvalidPassword
errIdentityNotFound *iam.ErrIdentityNotFound
)
if errors.As(err, &errInvalidPassword) {
return nil, gqlutils.Invalid(err, nil)
}
if errors.As(err, &errUserNotFound) {
if errors.As(err, &errIdentityNotFound) {
return nil, gqlutils.NotFound(err)
}
@@ -522,7 +522,7 @@ func (r *mutationResolver) UpdateIdentityProfile(ctx context.Context, input type
// RevokeSession is the resolver for the revokeSession field.
func (r *mutationResolver) RevokeSession(ctx context.Context, input types.RevokeSessionInput) (*types.RevokeSessionPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
err := r.iam.SessionService.RevokeSession(ctx, identity.ID, input.SessionID)
if err != nil {
@@ -553,7 +553,7 @@ func (r *mutationResolver) RevokeAllSessions(ctx context.Context) (*types.Revoke
// CreatePersonalAPIKey is the resolver for the createPersonalAPIKey field.
func (r *mutationResolver) CreatePersonalAPIKey(ctx context.Context, input types.CreatePersonalAPIKeyInput) (*types.CreatePersonalAPIKeyPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
userAPIKey, token, err := r.iam.AccountService.CreatePersonalAPIKey(
ctx,
@@ -567,7 +567,7 @@ func (r *mutationResolver) CreatePersonalAPIKey(ctx context.Context, input types
}
return &types.CreatePersonalAPIKeyPayload{
PersonalAPIKeyEdge: types.NewPersonalAPIKeyEdge(userAPIKey, coredata.UserAPIKeyOrderFieldCreatedAt),
PersonalAPIKeyEdge: types.NewPersonalAPIKeyEdge(userAPIKey, coredata.PersonalAPIKeyOrderFieldCreatedAt),
Token: token,
}, nil
}
@@ -579,7 +579,7 @@ func (r *mutationResolver) UpdatePersonalAPIKey(ctx context.Context, input types
// RevokePersonalAPIKey is the resolver for the revokePersonalAPIKey field.
func (r *mutationResolver) RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
err := r.iam.AccountService.DeletePersonalAPIKey(ctx, identity.ID, input.TokenID)
if err != nil {
@@ -592,7 +592,7 @@ func (r *mutationResolver) RevokePersonalAPIKey(ctx context.Context, input types
// CreateOrganization is the resolver for the createOrganization field.
func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
var (
logoFile *iam.UploadedFile
@@ -735,7 +735,7 @@ func (r *mutationResolver) RemoveMember(ctx context.Context, input types.RemoveM
// AcceptInvitation is the resolver for the acceptInvitation field.
func (r *mutationResolver) AcceptInvitation(ctx context.Context, input types.AcceptInvitationInput) (*types.AcceptInvitationPayload, error) {
identity := UserFromContext(ctx)
identity := IdentityFromContext(ctx)
membership, err := r.iam.AccountService.AcceptInvitation(ctx, identity.ID, input.InvitationID)
if err != nil {
@@ -928,7 +928,7 @@ func (r *personalAPIKeyConnectionResolver) TotalCount(ctx context.Context, obj *
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
var (
loadNode func(ctx context.Context, id gid.GID) (types.Node, error)
user = UserFromContext(ctx)
user = IdentityFromContext(ctx)
action string
)
@@ -942,7 +942,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
}
return types.NewOrganization(organization), nil
}
case coredata.UserEntityType:
case coredata.IdentityEntityType:
action = iam.ActionIAMIdentityGet
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
identity, err := r.iam.AccountService.GetIdentity(ctx, id)
@@ -1009,7 +1009,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
if err != nil {
var (
errOrganizationNotFound *iam.ErrOrganizationNotFound
errIdentityNotFound *iam.ErrUserNotFound
errIdentityNotFound *iam.ErrIdentityNotFound
errSessionNotFound *iam.ErrSessionNotFound
errMembershipNotFound *iam.ErrMembershipNotFound
errInvitationNotFound *iam.ErrInvitationNotFound
@@ -1034,7 +1034,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
// Viewer is the resolver for the viewer field.
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
user := UserFromContext(ctx)
user := IdentityFromContext(ctx)
return &types.Identity{
ID: user.ID,

View File

@@ -52,7 +52,7 @@ type (
)
func ensureAuthenticated(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
if identity == nil {
return func(ctx context.Context) *graphql.Response {
@@ -228,7 +228,7 @@ func NewMux(
panic(fmt.Errorf("cannot parse organization id: %w", err))
}
identity := connect_v1.UserFromContext(r.Context())
identity := connect_v1.IdentityFromContext(r.Context())
apiKey := connect_v1.APIKeyFromContext(r.Context())
if identity == nil {
httpserver.RenderError(w, http.StatusUnauthorized, fmt.Errorf("authentication required"))
@@ -328,7 +328,7 @@ func GetTenantService(ctx context.Context, proboSvc *probo.Service, tenantID gid
}
func (r *Resolver) MustBeAuthorized(ctx context.Context, entityID gid.GID, action iam.Action) {
user := connect_v1.UserFromContext(ctx)
user := connect_v1.IdentityFromContext(ctx)
apiKey := connect_v1.APIKeyFromContext(ctx)
var credentialID *gid.GID

View File

@@ -967,7 +967,7 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc
func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.DocumentVersion) (bool, error) {
r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetSigned)
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
if identity == nil {
panic(fmt.Errorf("user not found in context"))
}
@@ -1758,7 +1758,7 @@ func (r *mutationResolver) DeleteTrustCenterFile(ctx context.Context, input type
// CreatePeople is the resolver for the createPeople field.
func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) {
user := connect_v1.UserFromContext(ctx)
user := connect_v1.IdentityFromContext(ctx)
r.iam.Authorizer.Authorize(ctx, iam.AuthorizeParams{
Principal: user.ID,
@@ -2165,7 +2165,7 @@ func (r *mutationResolver) ExportFramework(ctx context.Context, input types.Expo
r.MustBeAuthorized(ctx, input.FrameworkID, iam.ActionExportFramework)
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
err, exportJobID := prb.Frameworks.RequestExport(
ctx,
@@ -3257,7 +3257,7 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ
prb := r.ProboService(ctx, input.DocumentID.TenantID())
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
document, documentVersion, err := prb.Documents.PublishVersion(ctx, input.DocumentID, identity.ID, input.Changelog)
if err != nil {
@@ -3287,7 +3287,7 @@ func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, inpu
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
documentVersions, documents, err := prb.Documents.BulkPublishVersions(
ctx,
@@ -3343,7 +3343,7 @@ func (r *mutationResolver) BulkExportDocuments(ctx context.Context, input types.
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
options := probo.ExportPDFOptions{
WithWatermark: input.WithWatermark,
@@ -3514,7 +3514,7 @@ func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input typ
func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDocumentInput) (*types.SignDocumentPayload, error) {
r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionSignDocument)
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
documentVersionSignature, err := prb.Documents.SignDocumentVersionByEmail(ctx, input.DocumentVersionID, identity.EmailAddress)
@@ -3564,7 +3564,7 @@ func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context,
panic(fmt.Errorf("cannot get document version: %w", err))
}
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&identity.EmailAddress)
_, err = prb.Documents.GetWithFilter(ctx, documentVersion.DocumentID, documentFilter)
@@ -5919,7 +5919,8 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
// Viewer is the resolver for the viewer field.
func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
session := connect_v1.SessionFromContext(ctx)
apiKey := connect_v1.APIKeyFromContext(ctx)

View File

@@ -41,7 +41,7 @@ func RequireAPIKeyHandler(
)
apiKey := connect_v1.APIKeyFromContext(ctx)
identity := connect_v1.UserFromContext(ctx)
identity := connect_v1.IdentityFromContext(ctx)
if identity == nil {
httpserver.RenderError(w, http.StatusUnauthorized, errors.New("authentication required"))
return

View File

@@ -19,7 +19,7 @@ type Resolver struct {
}
func (r *Resolver) MustBeAuthorized(ctx context.Context, entityID gid.GID, action iam.Action) {
user := connect_v1.UserFromContext(ctx)
user := connect_v1.IdentityFromContext(ctx)
apiKey := connect_v1.APIKeyFromContext(ctx)
if user == nil {
panic(&iam.TenantAccessError{Message: "authentication required"})

View File

@@ -21,7 +21,7 @@ import (
// ListOrganizationsTool handles the listOrganizations tool
// List all organizations the user has access to
func (r *Resolver) ListOrganizationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListOrganizationsInput) (*mcp.CallToolResult, types.ListOrganizationsOutput, error) {
user := connect_v1.UserFromContext(ctx)
user := connect_v1.IdentityFromContext(ctx)
organizations, err := r.iamSvc.AccountService.ListOrganizations(ctx, user.ID)
if err != nil {
@@ -1667,7 +1667,7 @@ func (r *Resolver) PublishDocumentVersionTool(ctx context.Context, req *mcp.Call
svc := r.ProboService(ctx, input.DocumentID)
user := connect_v1.UserFromContext(ctx)
user := connect_v1.IdentityFromContext(ctx)
document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, user.ID, input.Changelog)
if err != nil {

View File

@@ -33,7 +33,7 @@ type TokenAccessData struct {
}
type ContextAccessor interface {
UserFromContext(ctx context.Context) *coredata.User
IdentityFromContext(ctx context.Context) *coredata.Identity
TokenAccessFromContext(ctx context.Context) *TokenAccessData
}
@@ -46,8 +46,8 @@ func ValidateTenantAccess(ctx context.Context, accessor ContextAccessor, userTen
return nil
}
user := accessor.UserFromContext(ctx)
if user != nil {
identity := accessor.IdentityFromContext(ctx)
if identity != nil {
userTenants, ok := ctx.Value(userTenantContextKey).(*[]gid.TenantID)
if !ok || userTenants == nil {
return fmt.Errorf("access denied: no tenant information available")
@@ -65,10 +65,10 @@ func ValidateTenantAccess(ctx context.Context, accessor ContextAccessor, userTen
}
func GetCurrentUserRole(ctx context.Context, accessor ContextAccessor) types.Role {
user := accessor.UserFromContext(ctx)
identity := accessor.IdentityFromContext(ctx)
tokenAccess := accessor.TokenAccessFromContext(ctx)
if user != nil || tokenAccess != nil {
if identity != nil || tokenAccess != nil {
return types.RoleUser
}
return types.RoleNone

View File

@@ -74,7 +74,7 @@ func (r *documentResolver) IsUserAuthorized(ctx context.Context, obj *types.Docu
// return false, nil
// }
// userData := connect_v1.UserFromContext(ctx)
// userData := connect_v1.IdentityFromContext(ctx)
// if userData != nil {
// return true, nil
// }
@@ -99,7 +99,7 @@ func (r *documentResolver) HasUserRequestedAccess(ctx context.Context, obj *type
// return false, nil
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return false, nil
// }
@@ -137,7 +137,7 @@ func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framewor
func (r *mutationResolver) RequestAllAccesses(ctx context.Context, input types.RequestAllAccessesInput) (*types.RequestAccessesPayload, error) {
// publicTrustService := r.PublicTrustService(ctx, input.TrustCenterID.TenantID())
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return nil, fmt.Errorf("session users cannot request trust center access")
// }
@@ -239,7 +239,7 @@ func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.Ex
// }
// }
// userData := UserFromContext(ctx)
// userData := IdentityFromContext(ctx)
// var userEmail mail.Addr
// if userData != nil {
// userEmail = userData.EmailAddress
@@ -319,7 +319,7 @@ func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.Expo
// }
// }
// userData := UserFromContext(ctx)
// userData := IdentityFromContext(ctx)
// var userEmail mail.Addr
// if userData != nil {
// userEmail = userData.EmailAddress
@@ -371,7 +371,7 @@ func (r *mutationResolver) RequestDocumentAccess(ctx context.Context, input type
// fullname string
// )
// identity := connect_v1.UserFromContext(ctx)
// identity := connect_v1.IdentityFromContext(ctx)
// if identity != nil {
// email = identity.EmailAddress
// fullname = identity.FullName
@@ -422,7 +422,7 @@ func (r *mutationResolver) RequestReportAccess(ctx context.Context, input types.
// return nil, fmt.Errorf("report is publicly available and does not require access request")
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return nil, fmt.Errorf("session users cannot request trust center access")
// }
@@ -473,7 +473,7 @@ func (r *mutationResolver) RequestTrustCenterFileAccess(ctx context.Context, inp
// return nil, fmt.Errorf("trust center file is publicly available and does not require access request")
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return nil, fmt.Errorf("session users cannot request trust center access")
// }
@@ -571,7 +571,7 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
// }
// }
// userData := UserFromContext(ctx)
// userData := IdentityFromContext(ctx)
// var userEmail mail.Addr
// if userData != nil {
// userEmail = userData.EmailAddress
@@ -753,7 +753,7 @@ func (r *reportResolver) IsUserAuthorized(ctx context.Context, obj *types.Report
// return false, nil
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return true, nil
// }
@@ -780,7 +780,7 @@ func (r *reportResolver) HasUserRequestedAccess(ctx context.Context, obj *types.
// return false, nil
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return false, nil
// }
@@ -836,7 +836,7 @@ func (r *trustCenterResolver) HasAcceptedNonDisclosureAgreement(ctx context.Cont
// return false, nil
// }
// userData := UserFromContext(ctx)
// userData := IdentityFromContext(ctx)
// if userData != nil {
// return true, nil
// }
@@ -963,7 +963,7 @@ func (r *trustCenterFileResolver) IsUserAuthorized(ctx context.Context, obj *typ
// return false, nil
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return true, nil
// }
@@ -990,7 +990,7 @@ func (r *trustCenterFileResolver) HasUserRequestedAccess(ctx context.Context, ob
// return false, nil
// }
// userData := r.UserFromContext(ctx)
// userData := r.IdentityFromContext(ctx)
// if userData != nil {
// return false, nil
// }