Sync title in SCIM and Gbridge
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -112,6 +112,9 @@ func (s *Bridge) Run(ctx context.Context) (created, updated, deleted, deactivate
|
|||||||
if existingSCIM.DisplayName != pu.DisplayName {
|
if existingSCIM.DisplayName != pu.DisplayName {
|
||||||
needsUpdate = true
|
needsUpdate = true
|
||||||
}
|
}
|
||||||
|
if existingSCIM.Title != pu.Title {
|
||||||
|
needsUpdate = true
|
||||||
|
}
|
||||||
|
|
||||||
if needsUpdate {
|
if needsUpdate {
|
||||||
if !s.dryRun {
|
if !s.dryRun {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ type (
|
|||||||
GivenName string `json:"-"`
|
GivenName string `json:"-"`
|
||||||
FamilyName string `json:"-"`
|
FamilyName string `json:"-"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
|
Title string `json:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
Users []User
|
Users []User
|
||||||
@@ -130,6 +131,7 @@ func (c *Client) CreateUser(ctx context.Context, user *User) error {
|
|||||||
"primary": true,
|
"primary": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"title": user.Title,
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
@@ -178,6 +180,7 @@ func (c *Client) UpdateUser(ctx context.Context, userID string, user *User) erro
|
|||||||
"primary": true,
|
"primary": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"title": user.Title,
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package googleworkspace
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -82,6 +83,36 @@ func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var title string
|
||||||
|
|
||||||
|
if u.Organizations == nil {
|
||||||
|
title = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(u.Organizations)
|
||||||
|
if err != nil {
|
||||||
|
title = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var orgs []admin.UserOrganization
|
||||||
|
if err := json.Unmarshal(data, &orgs); err != nil {
|
||||||
|
title = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer the primary organization's title
|
||||||
|
for _, org := range orgs {
|
||||||
|
if org.Primary && org.Title != "" {
|
||||||
|
title = org.Title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to the first organization with a title
|
||||||
|
for _, org := range orgs {
|
||||||
|
if org.Title != "" {
|
||||||
|
title = org.Title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
allUsers = append(
|
allUsers = append(
|
||||||
allUsers,
|
allUsers,
|
||||||
scimclient.User{
|
scimclient.User{
|
||||||
@@ -90,6 +121,7 @@ func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
|||||||
GivenName: u.Name.GivenName,
|
GivenName: u.Name.GivenName,
|
||||||
FamilyName: u.Name.FamilyName,
|
FamilyName: u.Name.FamilyName,
|
||||||
Active: !u.Suspended && !u.Archived,
|
Active: !u.Suspended && !u.Archived,
|
||||||
|
Title: title,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ func UserSchema() schema.Schema {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
schema.SimpleCoreAttribute(
|
||||||
|
schema.SimpleStringParams(
|
||||||
|
schema.StringParams{
|
||||||
|
Name: "title",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func (s *Service) CreateUser(
|
|||||||
config *coredata.SCIMConfiguration,
|
config *coredata.SCIMConfiguration,
|
||||||
attributes scim.ResourceAttributes,
|
attributes scim.ResourceAttributes,
|
||||||
) (scim.Resource, error) {
|
) (scim.Resource, error) {
|
||||||
email, fullName, active := ParseUserFromAttributes(attributes)
|
email, fullName, active, title := ParseUserFromAttributes(attributes)
|
||||||
if email == "" {
|
if email == "" {
|
||||||
return scim.Resource{}, scimerrors.ScimErrorBadRequest("userName or email is required")
|
return scim.Resource{}, scimerrors.ScimErrorBadRequest("userName or email is required")
|
||||||
}
|
}
|
||||||
@@ -190,6 +190,7 @@ func (s *Service) CreateUser(
|
|||||||
Source: coredata.ProfileSourceSCIM,
|
Source: coredata.ProfileSourceSCIM,
|
||||||
State: profileState,
|
State: profileState,
|
||||||
FullName: fullName,
|
FullName: fullName,
|
||||||
|
Position: &title,
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
@@ -204,6 +205,8 @@ func (s *Service) CreateUser(
|
|||||||
} else {
|
} else {
|
||||||
profile.Source = coredata.ProfileSourceSCIM
|
profile.Source = coredata.ProfileSourceSCIM
|
||||||
profile.State = profileState
|
profile.State = profileState
|
||||||
|
profile.FullName = fullName
|
||||||
|
profile.Position = &title
|
||||||
profile.UpdatedAt = now
|
profile.UpdatedAt = now
|
||||||
if err := profile.Update(ctx, tx, scope); err != nil {
|
if err := profile.Update(ctx, tx, scope); err != nil {
|
||||||
return fmt.Errorf("cannot update profile: %w", err)
|
return fmt.Errorf("cannot update profile: %w", err)
|
||||||
@@ -379,8 +382,8 @@ func (s *Service) ReplaceUser(
|
|||||||
profileID gid.GID,
|
profileID gid.GID,
|
||||||
attributes scim.ResourceAttributes,
|
attributes scim.ResourceAttributes,
|
||||||
) (scim.Resource, error) {
|
) (scim.Resource, error) {
|
||||||
fullName, active := ParseUserFromReplaceAttributes(attributes)
|
fullName, active, title := ParseUserFromReplaceAttributes(attributes)
|
||||||
profile, err := s.updateUser(ctx, config, profileID, fullName, active)
|
profile, err := s.updateUser(ctx, config, profileID, fullName, active, title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scim.Resource{}, err
|
return scim.Resource{}, err
|
||||||
}
|
}
|
||||||
@@ -394,8 +397,8 @@ func (s *Service) PatchUser(
|
|||||||
profileID gid.GID,
|
profileID gid.GID,
|
||||||
operations []scim.PatchOperation,
|
operations []scim.PatchOperation,
|
||||||
) (scim.Resource, error) {
|
) (scim.Resource, error) {
|
||||||
fullName, active := ParseUserFromPatchOperations(operations)
|
fullName, active, title := ParseUserFromPatchOperations(operations)
|
||||||
profile, err := s.updateUser(ctx, config, profileID, fullName, active)
|
profile, err := s.updateUser(ctx, config, profileID, fullName, active, title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scim.Resource{}, err
|
return scim.Resource{}, err
|
||||||
}
|
}
|
||||||
@@ -409,6 +412,7 @@ func (s *Service) updateUser(
|
|||||||
profileID gid.GID,
|
profileID gid.GID,
|
||||||
fullName string,
|
fullName string,
|
||||||
active *bool,
|
active *bool,
|
||||||
|
title string,
|
||||||
) (*coredata.MembershipProfile, error) {
|
) (*coredata.MembershipProfile, error) {
|
||||||
scope := coredata.NewScopeFromObjectID(config.OrganizationID)
|
scope := coredata.NewScopeFromObjectID(config.OrganizationID)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -447,6 +451,12 @@ func (s *Service) updateUser(
|
|||||||
profile.UpdatedAt = now
|
profile.UpdatedAt = now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if title == "" {
|
||||||
|
profile.Position = nil
|
||||||
|
} else {
|
||||||
|
profile.Position = &title
|
||||||
|
}
|
||||||
|
|
||||||
if shouldReactivate {
|
if shouldReactivate {
|
||||||
profile.State = coredata.ProfileStateActive
|
profile.State = coredata.ProfileStateActive
|
||||||
profile.UpdatedAt = now
|
profile.UpdatedAt = now
|
||||||
@@ -598,7 +608,7 @@ func (s *Service) createEvent(
|
|||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseUserFromAttributes(attributes scim.ResourceAttributes) (email string, fullName string, active bool) {
|
func ParseUserFromAttributes(attributes scim.ResourceAttributes) (email string, fullName string, active bool, title string) {
|
||||||
userName, _ := attributes["userName"].(string)
|
userName, _ := attributes["userName"].(string)
|
||||||
displayName, _ := attributes["displayName"].(string)
|
displayName, _ := attributes["displayName"].(string)
|
||||||
|
|
||||||
@@ -646,10 +656,14 @@ func ParseUserFromAttributes(attributes scim.ResourceAttributes) (email string,
|
|||||||
fullName = userName
|
fullName = userName
|
||||||
}
|
}
|
||||||
|
|
||||||
return email, fullName, active
|
if t, ok := attributes["title"].(string); ok {
|
||||||
|
title = t
|
||||||
|
}
|
||||||
|
|
||||||
|
return email, fullName, active, title
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseUserFromReplaceAttributes(attributes scim.ResourceAttributes) (fullName string, active *bool) {
|
func ParseUserFromReplaceAttributes(attributes scim.ResourceAttributes) (fullName string, active *bool, title string) {
|
||||||
displayName, _ := attributes["displayName"].(string)
|
displayName, _ := attributes["displayName"].(string)
|
||||||
|
|
||||||
var givenName, familyName string
|
var givenName, familyName string
|
||||||
@@ -668,10 +682,14 @@ func ParseUserFromReplaceAttributes(attributes scim.ResourceAttributes) (fullNam
|
|||||||
activeVal = a
|
activeVal = a
|
||||||
}
|
}
|
||||||
|
|
||||||
return fullName, &activeVal
|
if t, ok := attributes["title"].(string); ok {
|
||||||
|
title = t
|
||||||
|
}
|
||||||
|
|
||||||
|
return fullName, &activeVal, title
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseUserFromPatchOperations(operations []scim.PatchOperation) (fullName string, active *bool) {
|
func ParseUserFromPatchOperations(operations []scim.PatchOperation) (fullName string, active *bool, title string) {
|
||||||
var givenName, familyName string
|
var givenName, familyName string
|
||||||
|
|
||||||
for _, op := range operations {
|
for _, op := range operations {
|
||||||
@@ -720,6 +738,10 @@ func ParseUserFromPatchOperations(operations []scim.PatchOperation) (fullName st
|
|||||||
if name, ok := op.Value.(string); ok {
|
if name, ok := op.Value.(string); ok {
|
||||||
familyName = name
|
familyName = name
|
||||||
}
|
}
|
||||||
|
case "title":
|
||||||
|
if t, ok := op.Value.(string); ok {
|
||||||
|
title = t
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -729,7 +751,7 @@ func ParseUserFromPatchOperations(operations []scim.PatchOperation) (fullName st
|
|||||||
fullName = strings.TrimSpace(givenName + " " + familyName)
|
fullName = strings.TrimSpace(givenName + " " + familyName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fullName, active
|
return fullName, active, title
|
||||||
}
|
}
|
||||||
|
|
||||||
func userToResource(p *coredata.MembershipProfile) scim.Resource {
|
func userToResource(p *coredata.MembershipProfile) scim.Resource {
|
||||||
@@ -750,6 +772,7 @@ func userToResource(p *coredata.MembershipProfile) scim.Resource {
|
|||||||
"primary": true,
|
"primary": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"title": p.Position,
|
||||||
},
|
},
|
||||||
Meta: scim.Meta{
|
Meta: scim.Meta{
|
||||||
Created: &p.CreatedAt,
|
Created: &p.CreatedAt,
|
||||||
|
|||||||
Reference in New Issue
Block a user