-
Notifications
You must be signed in to change notification settings - Fork 170
/
users.go
156 lines (132 loc) · 4.9 KB
/
users.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package svc
import (
"context"
"net/http"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/pkg/user"
"github.com/go-chi/chi"
"github.com/go-chi/render"
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
//msgraph "github.com/owncloud/open-graph-api-go" // FIXME needs OnPremisesSamAccountName, OnPremisesDomainName and AdditionalData
msgraph "github.com/yaegashi/msgraph.go/v1.0"
)
// UserCtx middleware is used to load an User object from
// the URL parameters passed through as the request. In case
// the User could not be found, we stop here and return a 404.
// TODO use cs3 api to look up user
func (g Graph) UserCtx(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
if userID == "" {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing user id")
return
}
client, err := g.GetClient()
if err != nil {
g.logger.Error().Err(err).Msg("could not get client")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
res, err := client.GetUserByClaim(r.Context(), &cs3.GetUserByClaimRequest{
Claim: "userid", // FIXME add consts to reva
Value: userID,
})
switch {
case err != nil:
g.logger.Error().Err(err).Str("userid", userID).Msg("error sending get user by claim id grpc request")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
return
case res.Status.Code != cs3rpc.Code_CODE_OK:
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, res.Status.Message)
return
}
g.logger.Error().Err(err).Str("userid", userID).Msg("error sending get user by claim id grpc request")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
return
}
ctx := context.WithValue(r.Context(), userKey, res.User)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// GetMe implements the Service interface.
func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
u, ok := user.ContextGetUser(r.Context())
if !ok {
g.logger.Error().Msg("user not in context")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, "user not in context")
return
}
g.logger.Info().Interface("user", u).Msg("User in /me")
me := createUserModelFromCS3(u)
render.Status(r, http.StatusOK)
render.JSON(w, r, me)
}
// GetUsers implements the Service interface.
// TODO use cs3 api to look up user
func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
client, err := g.GetClient()
if err != nil {
g.logger.Error().Err(err).Msg("could not get client")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
search := r.URL.Query().Get("search")
if search == "" {
search = r.URL.Query().Get("$search")
}
res, err := client.FindUsers(r.Context(), &cs3.FindUsersRequest{
// FIXME presence match is currently not implemented, an empty search currently leads to
// Unwilling To Perform": Search Error: error parsing filter: (&(objectclass=posixAccount)(|(cn=*)(displayname=*)(mail=*))), error: Present filter match for cn not implemented
Filter: search,
})
switch {
case err != nil:
g.logger.Error().Err(err).Str("search", search).Msg("error sending find users grpc request")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
return
case res.Status.Code != cs3rpc.Code_CODE_OK:
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, res.Status.Message)
return
}
g.logger.Error().Err(err).Str("search", search).Msg("error sending find users grpc request")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
return
}
users := make([]*msgraph.User, 0, len(res.Users))
for _, user := range res.Users {
users = append(users, createUserModelFromCS3(user))
}
render.Status(r, http.StatusOK)
render.JSON(w, r, &listResponse{Value: users})
}
// GetUser implements the Service interface.
func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value(userKey).(*cs3.User)
render.Status(r, http.StatusOK)
render.JSON(w, r, createUserModelFromCS3(user))
}
func createUserModelFromCS3(u *cs3.User) *msgraph.User {
if u.Id == nil {
u.Id = &cs3.UserId{}
}
return &msgraph.User{
DisplayName: &u.DisplayName,
Mail: &u.Mail,
// TODO u.Groups are those ids or group names?
OnPremisesSamAccountName: &u.Username,
DirectoryObject: msgraph.DirectoryObject{
Entity: msgraph.Entity{
ID: &u.Id.OpaqueId,
Object: msgraph.Object{
AdditionalData: map[string]interface{}{
"uidnumber": u.UidNumber,
"gidnumber": u.GidNumber,
},
},
},
},
}
}