github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/api4/ldap.go (about) 1 // Copyright (c) 2017-present Xenia, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api4 5 6 import ( 7 "database/sql" 8 "encoding/json" 9 "net/http" 10 11 "github.com/xzl8028/xenia-server/model" 12 ) 13 14 type mixedUnlinkedGroup struct { 15 Id *string `json:"xenia_group_id"` 16 DisplayName string `json:"name"` 17 RemoteId string `json:"primary_key"` 18 HasSyncables *bool `json:"has_syncables"` 19 } 20 21 func (api *API) InitLdap() { 22 api.BaseRoutes.LDAP.Handle("/sync", api.ApiSessionRequired(syncLdap)).Methods("POST") 23 api.BaseRoutes.LDAP.Handle("/test", api.ApiSessionRequired(testLdap)).Methods("POST") 24 25 // GET /api/v4/ldap/groups?page=0&per_page=1000 26 api.BaseRoutes.LDAP.Handle("/groups", api.ApiSessionRequired(getLdapGroups)).Methods("GET") 27 28 // POST /api/v4/ldap/groups/:remote_id/link 29 api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(linkLdapGroup)).Methods("POST") 30 31 // DELETE /api/v4/ldap/groups/:remote_id/link 32 api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(unlinkLdapGroup)).Methods("DELETE") 33 } 34 35 func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) { 36 if c.App.License() == nil || !*c.App.License().Features.LDAP { 37 c.Err = model.NewAppError("Api4.syncLdap", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented) 38 return 39 } 40 41 if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { 42 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 43 return 44 } 45 46 c.App.SyncLdap() 47 48 ReturnStatusOK(w) 49 } 50 51 func testLdap(c *Context, w http.ResponseWriter, r *http.Request) { 52 if c.App.License() == nil || !*c.App.License().Features.LDAP { 53 c.Err = model.NewAppError("Api4.testLdap", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented) 54 return 55 } 56 57 if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { 58 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 59 return 60 } 61 62 if err := c.App.TestLdap(); err != nil { 63 c.Err = err 64 return 65 } 66 67 ReturnStatusOK(w) 68 } 69 70 func getLdapGroups(c *Context, w http.ResponseWriter, r *http.Request) { 71 if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { 72 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 73 return 74 } 75 76 if c.App.License() == nil || !*c.App.License().Features.LDAPGroups { 77 c.Err = model.NewAppError("Api4.getLdapGroups", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented) 78 return 79 } 80 81 opts := model.LdapGroupSearchOpts{ 82 Q: c.Params.Q, 83 } 84 if c.Params.IsLinked != nil { 85 opts.IsLinked = c.Params.IsLinked 86 } 87 if c.Params.IsConfigured != nil { 88 opts.IsConfigured = c.Params.IsConfigured 89 } 90 91 groups, total, err := c.App.GetAllLdapGroupsPage(c.Params.Page, c.Params.PerPage, opts) 92 if err != nil { 93 c.Err = err 94 return 95 } 96 97 mugs := []*mixedUnlinkedGroup{} 98 for _, group := range groups { 99 mug := &mixedUnlinkedGroup{ 100 DisplayName: group.DisplayName, 101 RemoteId: group.RemoteId, 102 } 103 if len(group.Id) == 26 { 104 mug.Id = &group.Id 105 mug.HasSyncables = &group.HasSyncables 106 } 107 mugs = append(mugs, mug) 108 } 109 110 b, marshalErr := json.Marshal(struct { 111 Count int `json:"count"` 112 Groups []*mixedUnlinkedGroup `json:"groups"` 113 }{Count: total, Groups: mugs}) 114 if marshalErr != nil { 115 c.Err = model.NewAppError("Api4.getLdapGroups", "api.marshal_error", nil, marshalErr.Error(), http.StatusInternalServerError) 116 return 117 } 118 119 w.Write(b) 120 } 121 122 func linkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) { 123 c.RequireRemoteId() 124 if c.Err != nil { 125 return 126 } 127 128 if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { 129 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 130 return 131 } 132 133 if c.App.License() == nil || !*c.App.License().Features.LDAPGroups { 134 c.Err = model.NewAppError("Api4.linkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented) 135 return 136 } 137 138 ldapGroup, err := c.App.GetLdapGroup(c.Params.RemoteId) 139 if err != nil { 140 c.Err = err 141 return 142 } 143 144 if ldapGroup == nil { 145 c.Err = model.NewAppError("Api4.linkLdapGroup", "api.ldap_group.not_found", nil, "", http.StatusNotFound) 146 return 147 } 148 149 group, err := c.App.GetGroupByRemoteID(ldapGroup.RemoteId, model.GroupSourceLdap) 150 if err != nil && err.DetailedError != sql.ErrNoRows.Error() { 151 c.Err = err 152 return 153 } 154 155 var status int 156 var newOrUpdatedGroup *model.Group 157 158 // Group has been previously linked 159 if group != nil { 160 if group.DeleteAt == 0 { 161 newOrUpdatedGroup = group 162 } else { 163 group.DeleteAt = 0 164 group.DisplayName = ldapGroup.DisplayName 165 group.RemoteId = ldapGroup.RemoteId 166 newOrUpdatedGroup, err = c.App.UpdateGroup(group) 167 if err != nil { 168 c.Err = err 169 return 170 } 171 } 172 status = http.StatusOK 173 } else { 174 // Group has never been linked 175 // 176 // TODO: In a future phase of LDAP groups sync `Name` will be used for at-mentions and will be editable on 177 // the front-end so it will not have an initial value of `model.NewId()` but rather a slugified version of 178 // the LDAP group name with an appended duplicate-breaker. 179 newGroup := &model.Group{ 180 Name: model.NewId(), 181 DisplayName: ldapGroup.DisplayName, 182 RemoteId: ldapGroup.RemoteId, 183 Source: model.GroupSourceLdap, 184 } 185 newOrUpdatedGroup, err = c.App.CreateGroup(newGroup) 186 if err != nil { 187 c.Err = err 188 return 189 } 190 status = http.StatusCreated 191 } 192 193 b, marshalErr := json.Marshal(newOrUpdatedGroup) 194 if marshalErr != nil { 195 c.Err = model.NewAppError("Api4.linkLdapGroup", "api.marshal_error", nil, marshalErr.Error(), http.StatusInternalServerError) 196 return 197 } 198 199 w.WriteHeader(status) 200 w.Write(b) 201 } 202 203 func unlinkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) { 204 c.RequireRemoteId() 205 if c.Err != nil { 206 return 207 } 208 209 if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { 210 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 211 return 212 } 213 214 if c.App.License() == nil || !*c.App.License().Features.LDAPGroups { 215 c.Err = model.NewAppError("Api4.unlinkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented) 216 return 217 } 218 219 group, err := c.App.GetGroupByRemoteID(c.Params.RemoteId, model.GroupSourceLdap) 220 if err != nil { 221 c.Err = err 222 return 223 } 224 225 if group.DeleteAt == 0 { 226 _, err = c.App.DeleteGroup(group.Id) 227 if err != nil { 228 c.Err = err 229 return 230 } 231 } 232 233 ReturnStatusOK(w) 234 }