Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions hooks/ordrd-group-x/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ var (

// baseGroup is obtained from a flag and used for the shared posixGroup.
baseGroup string

// userObjectClasses is the objectClass list written to user entries in the
// target LDAP. Configurable via --userObjectClasses so the hook can run
// against targets that don't have the helxUser schema loaded.
userObjectClassesFlag string
userObjectClasses []string
)

// HookRequest represents the input payload for the /hook endpoint.
Expand Down Expand Up @@ -180,15 +186,19 @@ func processORDRDGroup(req HookRequest) HookResponse {
// Emit one extra transformed entry per member that patches their groups attribute.
// Because groups is a merge attribute in the main service, these accumulate correctly
// (e.g. a user in both "users" and "eagle" ends up with groups: [users, eagle]).
// Only emitted when helxUser is in the objectClass list; otherwise the destination
// LDAP schema won't have the groups attribute type defined.
transformedEntries := []map[string]interface{}{transformed}
for _, uid := range memberUids {
userGroupPatch := map[string]interface{}{
"dn": fmt.Sprintf("uid=%s,ou=users,dc=example,dc=org", uid),
"content": map[string]interface{}{
"groups": []interface{}{groupname},
},
if hasHelxUser() {
for _, uid := range memberUids {
userGroupPatch := map[string]interface{}{
"dn": fmt.Sprintf("uid=%s,ou=users,dc=example,dc=org", uid),
"content": map[string]interface{}{
"groups": []interface{}{groupname},
},
}
transformedEntries = append(transformedEntries, userGroupPatch)
}
transformedEntries = append(transformedEntries, userGroupPatch)
}

return HookResponse{
Expand Down Expand Up @@ -219,14 +229,17 @@ func processUNCUser(req HookRequest) HookResponse {
"displayName": req.Content["displayName"],
"gidNumber": baseGid, // Use the global baseGid.
"givenName": req.Content["givenName"],
"groups": []interface{}{baseGroup}, // every user belongs to the base group
"homeDirectory": fmt.Sprintf("/home/%s", uid),
"objectClass": []string{"top", "inetOrgPerson", "posixAccount", "helxUser"},
"objectClass": userObjectClasses,
"ou": "users",
"sn": req.Content["sn"],
"uid": uid,
"uidNumber": req.Content["uidNumber"],
}
// Only include groups when the destination schema has helxUser loaded.
if hasHelxUser() {
newContent["groups"] = []interface{}{baseGroup}
}

transformed := map[string]interface{}{
"dn": newDN,
Expand Down Expand Up @@ -303,6 +316,18 @@ func processPosixGroup(req HookRequest) HookResponse {
}
}

// hasHelxUser reports whether "helxUser" is present in the configured
// userObjectClasses. The groups attribute is only defined in the helxUser
// schema extension, so it must not be written to destinations that lack it.
func hasHelxUser() bool {
for _, oc := range userObjectClasses {
if oc == "helxUser" {
return true
}
}
return false
}

// extractGroupName extracts the groupname from a DN expected in the form:
// "cn=unc:app:renci:{{ groupname }},ou=Groups,dc=unc,dc=edu"
func extractGroupName(dn string) string {
Expand Down Expand Up @@ -342,8 +367,17 @@ func main() {
// Accept the baseGid flag. Default value is "200" (adjust as needed).
flag.StringVar(&baseGid, "baseGid", "200", "Base gidNumber to use for UNC Users")
flag.StringVar(&baseGroup, "baseGroup", "users", "Base group name for all UNC Users")
flag.StringVar(&userObjectClassesFlag, "userObjectClasses",
"top,inetOrgPerson,posixAccount,helxUser",
"Comma-separated objectClass list to assign to synced user entries")
flag.Parse()

for _, oc := range strings.Split(userObjectClassesFlag, ",") {
if oc = strings.TrimSpace(oc); oc != "" {
userObjectClasses = append(userObjectClasses, oc)
}
}

e := echo.New()

// Register the /hook POST endpoint.
Expand Down
55 changes: 37 additions & 18 deletions hooks/unc-group-x/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,19 @@ func processORDRDGroup(req HookRequest) HookResponse {
// Emit one extra transformed entry per member that patches their groups attribute.
// Because groups is a merge attribute in the main service, these accumulate correctly
// (e.g. a user in both "users" and "eagle" ends up with groups: [users, eagle]).
// Only emitted when helxUser is in the objectClass list; otherwise the destination
// LDAP schema won't have the groups attribute type defined.
transformedEntries := []map[string]interface{}{transformed}
for _, pid := range memberPids {
userGroupPatch := map[string]interface{}{
"dn": fmt.Sprintf("uid=$pidUidMap.%s,ou=users,dc=example,dc=org", pid),
"content": map[string]interface{}{
"groups": []interface{}{groupname},
},
if hasHelxUser() {
for _, pid := range memberPids {
userGroupPatch := map[string]interface{}{
"dn": fmt.Sprintf("uid=$pidUidMap.%s,ou=users,dc=example,dc=org", pid),
"content": map[string]interface{}{
"groups": []interface{}{groupname},
},
}
transformedEntries = append(transformedEntries, userGroupPatch)
}
transformedEntries = append(transformedEntries, userGroupPatch)
}

return HookResponse{
Expand Down Expand Up @@ -254,17 +258,20 @@ func processUNCUser(req HookRequest) HookResponse {

// Build the transformed content.
newContent := map[string]interface{}{
"cn": req.Content["cn"],
"displayName": req.Content["displayName"],
"gidNumber": baseGid, // Use the global baseGid.
"givenName": req.Content["givenName"],
"groups": []interface{}{baseGroup}, // every user belongs to the base group
"homeDirectory": fmt.Sprintf("/home/%s", uid),
"objectClass": userObjectClasses,
"ou": "users",
"sn": req.Content["sn"],
"uid": uid,
"uidNumber": req.Content["uidNumber"],
"cn": req.Content["cn"],
"displayName": req.Content["displayName"],
"gidNumber": baseGid, // Use the global baseGid.
"givenName": req.Content["givenName"],
"homeDirectory": fmt.Sprintf("/home/%s", uid),
"objectClass": userObjectClasses,
"ou": "users",
"sn": req.Content["sn"],
"uid": uid,
"uidNumber": req.Content["uidNumber"],
}
// Only include groups when the destination schema has helxUser loaded.
if hasHelxUser() {
newContent["groups"] = []interface{}{baseGroup}
}

transformed := map[string]interface{}{
Expand Down Expand Up @@ -397,6 +404,18 @@ func extractCN(dn string) string {
return ""
}

// hasHelxUser reports whether "helxUser" is present in the configured
// userObjectClasses. The groups attribute is only defined in the helxUser
// schema extension, so it must not be written to destinations that lack it.
func hasHelxUser() bool {
for _, oc := range userObjectClasses {
if oc == "helxUser" {
return true
}
}
return false
}

// copyMap creates a shallow copy of a map.
func copyMap(orig map[string]interface{}) map[string]interface{} {
newMap := make(map[string]interface{})
Expand Down
Loading