Newer
Older
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package server
import (
"context"
"fmt"
"time"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/metrics"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/store"
"github.com/google/uuid"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// User holds a JWTManager and represents a UserServiceServer.
type User struct {
apb.UnimplementedUserServiceServer
jwtManager *rbac.JWTManager
}
// NewUserServer receives a JWTManager and returns a new UserServer.
func NewUserServer(jwtManager *rbac.JWTManager) *User {
return &User{
jwtManager: jwtManager,
}
}
// CreateUsers creates new users, can be 1 or more
func (u User) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: implement check if user is allowed to create users with this role
// e.g. non-admin shouldn't be allowed to create admin users
for _, u := range request.User {
roles := map[string]string{}
for key, elem := range u.Roles {
fmt.Printf("k: %v v: %v\n", key, elem)
_, err := uuid.Parse(key)
if err != nil {
return nil, handleRPCError(labels, err)
}
roles[key] = elem
}
user := rbac.NewUser(uuid.New(), u.Name, roles, u.Password, u.Token)
err := userc.Add(user)
if err != nil {
log.Error(err)
return nil, status.Errorf(codes.Aborted, "%v", err)
}
}
return &apb.CreateUsersResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
// GetUser returns one user by name.
func (u User) GetUser(ctx context.Context, request *apb.GetUserRequest) (*apb.GetUserResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "get"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: implement check if user is allowed to get this user data; only their own if not admin
userData, err := userc.Get(store.Query{Name: request.Name})
if err != nil {
return nil, err
}
user := &apb.User{
Id: userData.ID().String(),
Name: userData.Name(),
Roles: userData.GetRoles(),
}
return &apb.GetUserResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
User: user,
}, nil
}
// GetUsers returns all availbale users
func (u User) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.GetUsersResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "get"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
userList, err := userc.GetAll()
if err != nil {
return nil, err
}
users := []*apb.User{}
for _, u := range userList {
users = append(users, &apb.User{
Id: u.ID().String(),
Name: u.Name(),
Roles: u.GetRoles(),
})
}
return &apb.GetUsersResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
User: users,
}, nil
}
// UpdateUsers updates the user data of one or more users provided in the request
func (u User) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) (*apb.UpdateUsersResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: check if current user is allowed to update the user they try to update; only their own if not admin
for _, u := range request.User {
uid, err := uuid.Parse(u.Id)
if err != nil {
return nil, handleRPCError(labels, err)
}
_, err = userc.Get(store.Query{ID: uid})
if err != nil {
return nil, status.Errorf(codes.Canceled, "user not found %v", err)
}
userToUpdate := rbac.NewUser(uid, u.Name, u.Roles, u.Password, u.Token)
err = userc.Update(userToUpdate)
if err != nil {
return nil, status.Errorf(codes.Aborted, "could not update user %v", err)
}
}
return &apb.UpdateUsersResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
// DeleteUsers deletes one or more users provided in the request
func (u User) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) (*apb.DeleteUsersResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
for _, u := range request.Username {
userToDelete, err := userc.Get(store.Query{Name: u})
if err != nil {
return nil, status.Errorf(codes.Canceled, "user not found %v", err)
}
err = userc.Delete(userToDelete)
if err != nil {
return nil, status.Errorf(codes.Aborted, "error deleting user %v", err)
}
}
return &apb.DeleteUsersResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
func (u User) isValidUser(user rbac.User) (bool, error) {
storedUser, err := userc.Get(store.Query{Name: user.Name()})
if err != nil {
return false, err
} else if storedUser == nil {
return false, status.Errorf(codes.Aborted, "no user object")
}
if storedUser.Name() == user.Name() {
if storedUser.GetPassword() == user.GetPassword() {
return true, nil
}
}
return false, status.Errorf(codes.Unauthenticated, "incorrect user name or password")
}