-
Notifications
You must be signed in to change notification settings - Fork 59
feat(RHOAIENG-50753): add LDAP user and group autocomplete for workspace sharing #805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
77bf358
513b5ae
ebc132a
caf55f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| package handlers | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "log" | ||
| "net/http" | ||
|
|
||
| "ambient-code-backend/ldap" | ||
|
|
||
| "github.com/gin-gonic/gin" | ||
| ) | ||
|
|
||
| // LDAPClient is the shared LDAP client instance, initialized in main.go when LDAP_URL is set. | ||
| // Access is gated in the frontend by the "ldap.autocomplete.enabled" workspace feature flag. | ||
| var LDAPClient *ldap.Client | ||
|
|
||
| // SearchLDAPUsers handles GET /api/ldap/users?q={query} | ||
| func SearchLDAPUsers(c *gin.Context) { | ||
| reqK8s, _ := GetK8sClientsForRequest(c) | ||
| if reqK8s == nil { | ||
| c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"}) | ||
| c.Abort() | ||
| return | ||
| } | ||
|
Comment on lines
+18
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider logging the discarded error from The error returned by ♻️ Proposed fix to log auth errors func SearchLDAPUsers(c *gin.Context) {
- reqK8s, _ := GetK8sClientsForRequest(c)
+ reqK8s, err := GetK8sClientsForRequest(c)
if reqK8s == nil {
+ if err != nil {
+ log.Printf("LDAP auth error: %v", err)
+ }
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"})
c.Abort()
return
}Apply the same pattern to Also applies to: 48-54, 78-84 🤖 Prompt for AI Agents |
||
|
|
||
| query := c.Query("q") | ||
| if len(query) < ldap.MinQueryLength { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("query must be at least %d characters", ldap.MinQueryLength)}) | ||
| return | ||
| } | ||
|
|
||
| if LDAPClient == nil { | ||
| c.JSON(http.StatusOK, gin.H{"users": []ldap.LDAPUser{}}) | ||
| return | ||
| } | ||
|
|
||
| users, err := LDAPClient.SearchUsers(query) | ||
| if err != nil { | ||
| log.Printf("LDAP user search error for query %q: %v", query, err) | ||
| c.JSON(http.StatusServiceUnavailable, gin.H{"error": "LDAP search unavailable"}) | ||
| return | ||
| } | ||
|
|
||
| c.JSON(http.StatusOK, gin.H{"users": users}) | ||
|
Comment on lines
+37
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Inconsistent HTTP status codes for LDAP errors.
♻️ Proposed fix for consistency user, err := LDAPClient.GetUser(uid)
if err != nil {
log.Printf("LDAP user get error for uid %q: %v", uid, err)
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to look up user"})
+ c.JSON(http.StatusServiceUnavailable, gin.H{"error": "LDAP lookup unavailable"})
return
}Also applies to: 67-74, 97-102 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| // SearchLDAPGroups handles GET /api/ldap/groups?q={query} | ||
| func SearchLDAPGroups(c *gin.Context) { | ||
| reqK8s, _ := GetK8sClientsForRequest(c) | ||
| if reqK8s == nil { | ||
| c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"}) | ||
| c.Abort() | ||
| return | ||
| } | ||
|
|
||
| query := c.Query("q") | ||
| if len(query) < ldap.MinQueryLength { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("query must be at least %d characters", ldap.MinQueryLength)}) | ||
| return | ||
| } | ||
|
|
||
| if LDAPClient == nil { | ||
| c.JSON(http.StatusOK, gin.H{"groups": []ldap.LDAPGroup{}}) | ||
| return | ||
| } | ||
|
|
||
| groups, err := LDAPClient.SearchGroups(query) | ||
| if err != nil { | ||
| log.Printf("LDAP group search error for query %q: %v", query, err) | ||
| c.JSON(http.StatusServiceUnavailable, gin.H{"error": "LDAP search unavailable"}) | ||
| return | ||
| } | ||
|
|
||
| c.JSON(http.StatusOK, gin.H{"groups": groups}) | ||
| } | ||
|
|
||
| // GetLDAPUser handles GET /api/ldap/users/:uid | ||
| func GetLDAPUser(c *gin.Context) { | ||
| reqK8s, _ := GetK8sClientsForRequest(c) | ||
| if reqK8s == nil { | ||
| c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"}) | ||
| c.Abort() | ||
| return | ||
| } | ||
|
|
||
| uid := c.Param("uid") | ||
| if uid == "" { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": "uid is required"}) | ||
| return | ||
| } | ||
|
|
||
| if LDAPClient == nil { | ||
| c.JSON(http.StatusNotFound, gin.H{"error": "LDAP not configured"}) | ||
| return | ||
| } | ||
|
|
||
| user, err := LDAPClient.GetUser(uid) | ||
| if err != nil { | ||
| log.Printf("LDAP user get error for uid %q: %v", uid, err) | ||
| c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to look up user"}) | ||
| return | ||
| } | ||
|
|
||
| if user == nil { | ||
| c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) | ||
| return | ||
| } | ||
|
|
||
| c.JSON(http.StatusOK, user) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Promote
github.com/go-ldap/ldap/v3to a direct requirement if the new LDAP client imports it.If any backend file imports this module directly, keeping Line 39 as
// indirectjust creates churn the next timego mod tidyruns. If it is only transitive, ignore this.Verify whether the dependency is directly imported
Minimal fix if the import is direct
📝 Committable suggestion
🤖 Prompt for AI Agents