Leosac  0.8.0
Open Source Access Control
UserSecurityContext.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "UserSecurityContext.hpp"
21 #include "core/auth/Group_odb.h"
22 #include "core/auth/IDoor.hpp"
23 #include "core/auth/User_odb.h"
25 #include "tools/db/DBService.hpp"
28 #include "tools/log.hpp"
29 
30 using namespace Leosac;
31 
33  : SecurityContext(dbsrv)
34  , user_id_(id)
35 {
36 }
37 
39  const ActionParam &ap) const
40 {
41  // Simply put: Administrator can do everything, without any permission check.
42  if (is_admin())
43  return true;
44 
45  switch (action)
46  {
47  case Action::IS_ADMIN:
48  return is_admin();
49  case Action::IS_MANAGER:
50  return is_manager();
51 
53  return is_manager();
55  return is_admin();
56  case Action::USER_READ:
57  return can_read_user(ap.user);
59  return can_read_user_detail(ap.user);
61  return can_update_user(ap.user);
64  return is_manager();
66  return is_manager() || is_self(ap.user.user_id);
67 
69  return true;
71  return true;
72  case Action::GROUP_READ:
73  return can_read_group(ap.group);
77  return can_administrate_group(ap.group);
80 
85 
86 
88  return can_read_credential(ap.cred);
89 
93  return is_manager();
94 
96  return can_read_schedule(ap.sched);
100  return is_manager();
102  return true;
103 
104  case Action::DOOR_READ:
105  return can_read_door(ap.door);
106  case Action::DOOR_CREATE:
107  case Action::DOOR_UPDATE:
108  case Action::DOOR_DELETE:
109  return is_manager();
110  case Action::DOOR_SEARCH:
111  return true;
112 
118  return is_manager();
119 
120  // Zone management is for manager.
121  case Action::ZONE_READ:
122  case Action::ZONE_CREATE:
123  case Action::ZONE_UPDATE:
124  case Action::ZONE_DELETE:
125  case Action::ZONE_SEARCH:
126  return is_manager();
127 
131  return is_admin();
132 
133  case Action::LOG_READ:
134  return is_manager();
135 
136  case Action::AUDIT_READ:
137  return is_manager();
139  return is_admin();
141  return is_manager();
142 
144  return is_admin();
145  default:
146  ASSERT_LOG(0, "Not handled.");
147  }
148  return false;
149 }
150 
152  const SecurityContext::GroupActionParam &gap) const
153 {
154  if (is_manager() || gap.group_id == 0) // listing group.
155  return true;
156  Auth::GroupPtr group =
157  dbsrv_->find_group_by_id(gap.group_id, DBService::THROW_IF_NOT_FOUND);
158  return group->member_has(user_id_);
159 }
160 
162  const SecurityContext::GroupActionParam &gap) const
163 {
164  if (is_manager())
165  return true;
166  Auth::GroupRank rank;
167  Auth::GroupPtr group =
168  dbsrv_->find_group_by_id(gap.group_id, DBService::THROW_IF_NOT_FOUND);
169  if (group->member_has(user_id_, &rank))
170  {
171  return rank == Auth::GroupRank::ADMIN;
172  }
173  return false;
174 }
175 
178 {
179  Auth::UserGroupMembershipPtr ugm = dbsrv_->find_membership_by_id(
181 
182  ActionParam ap;
183  ap.group.group_id = ugm->group_id();
184  return ugm->user_id() == user_id_ ||
186 }
187 
189  const SecurityContext::UserActionParam &) const
190 {
191  return true;
192 }
193 
195 {
196  return is_self(uap.user_id) || is_manager();
197 }
198 
200  const SecurityContext::UserActionParam &uap) const
201 {
202  return is_self(uap.user_id) || is_manager();
203 }
204 
207 {
208  if (is_manager())
209  return true;
210  // If we are at least Operator in the group, we can add someone.
211  Auth::GroupPtr group =
212  dbsrv_->find_group_by_id(map.group_id, DBService::THROW_IF_NOT_FOUND);
213  Auth::GroupRank rank;
214  if (group->member_has(user_id_, &rank))
215  {
216  if (rank >= Auth::GroupRank::OPERATOR && map.rank <= rank)
217  {
218  // Cannot invite to a rank superior our own rank.
219  return true;
220  }
221  }
222  return false;
223 }
224 
227 {
228  if (is_manager())
229  return true;
230  db::OptionalTransaction t(dbsrv_->db()->begin());
231  Auth::UserGroupMembershipPtr membership = dbsrv_->find_membership_by_id(
233 
234  auto group = membership->group().load();
235  auto target_user = membership->user().load();
236  t.commit();
237 
238  if (target_user->id() == user_id_)
239  return true; // Can leave any group.
240 
241  Auth::GroupRank my_rank;
242  if (group && group->member_has(user_id_, &my_rank))
243  {
244  if (my_rank >= Auth::GroupRank::OPERATOR && my_rank >= membership->rank())
245  {
246  // Cannot kick someone with a higher rank.
247  return true;
248  }
249  }
250  return false;
251 }
252 
254  const SecurityContext::ScheduleActionParam &cap) const
255 {
256  if (is_manager() || cap.schedule_id == 0)
257  return true;
258 
259  Tools::ISchedulePtr sched =
260  dbsrv_->find_schedule_by_id(cap.schedule_id, DBService::THROW_IF_NOT_FOUND);
261  // We need to find out is assigned to the schedule.
262  // If it is, we can read the schedule's data.
263  // Todo: Maybe have more fine grained permission here, like being able to read
264  // timeframes and door mapped but not everything.
265 
266  for (const auto &mapping : sched->mapping())
267  {
268  if (mapping->has_user_indirect(self()))
269  return true;
270  }
271  return false;
272 }
273 
275  const SecurityContext::DoorActionParam &dap) const
276 {
277  if (is_manager() || dap.door_id == 0)
278  return true;
279 
280  db::MultiplexedTransaction t(dbsrv_->db()->begin());
281  Auth::IDoorPtr door =
282  dbsrv_->find_door_by_id(dap.door_id, DBService::THROW_IF_NOT_FOUND);
283  for (const auto &mapping : door->lazy_mapping())
284  {
285  auto loaded_mapping = mapping.load();
286  if (loaded_mapping->has_user_indirect(self()))
287  return true;
288  }
289  return false;
290 }
291 
294 {
295  if (is_manager() || cap.credential_id == 0)
296  return true;
297 
298  auto cred = dbsrv_->find_credential_by_id(cap.credential_id,
300  return is_self(cred->owner_id());
301 }
302 
303 
305 {
306  auto user = dbsrv_->find_user_by_id(user_id_);
307  if (user)
308  return user->rank() == Auth::UserRank::ADMIN;
309  return false;
310 }
311 
313 {
314  auto user = dbsrv_->find_user_by_id(user_id_);
315  if (user)
316  return user->rank() >= Auth::UserRank::MANAGER;
317  return false;
318 }
319 
321 {
322  return user_id_ == id;
323 }
324 
326 {
327  return user_id_;
328 }
329 
331 {
332  return dbsrv_->find_user_by_id(user_id_, DBService::THROW_IF_NOT_FOUND);
333 }
334 
336  : UserSecurityContext(nullptr, 0)
337 {
338 }
339 
342 {
343  return false;
344 }
Leosac::SecurityContext::Action::ZONE_SEARCH
@ ZONE_SEARCH
Leosac::SecurityContext::ScheduleActionParam
Definition: SecurityContext.hpp:196
Leosac::db::OptionalTransaction
An optional transaction is an object that behave like an odb::transaction if there is no currently ac...
Definition: OptionalTransaction.hpp:43
Leosac::SecurityContext::Action::DOOR_READ
@ DOOR_READ
Leosac::SecurityContext::Action::GROUP_READ
@ GROUP_READ
Leosac::db::OptionalTransaction::commit
void commit()
Commit the transaction, if there was no currently active transaction at the time of this object's cre...
Definition: OptionalTransaction.cpp:38
Leosac::Tools::ISchedulePtr
std::shared_ptr< ISchedule > ISchedulePtr
Definition: ToolsFwd.hpp:37
Leosac::SecurityContext::ActionParam::sched
ScheduleActionParam sched
Definition: SecurityContext.hpp:236
Leosac::UserSecurityContext
A SecurityContext object for users.
Definition: UserSecurityContext.hpp:31
Leosac::SecurityContext::GroupActionParam
Definition: SecurityContext.hpp:165
IDoor.hpp
Leosac::UserSecurityContext::can_read_membership
bool can_read_membership(const MembershipActionParam &map) const
Definition: UserSecurityContext.cpp:176
Leosac::SecurityContext::Action::SCHEDULE_CREATE
@ SCHEDULE_CREATE
Leosac::SecurityContext::check_permission
virtual bool check_permission(Action a, const ActionParam &ap) const
Check for the permission to perform action a with parameters ap.
Definition: SecurityContext.cpp:30
Leosac::UserSecurityContext::can_administrate_group
bool can_administrate_group(const GroupActionParam &gap) const
Definition: UserSecurityContext.cpp:161
Leosac::UserSecurityContext::can_read_group
bool can_read_group(const GroupActionParam &gap) const
Definition: UserSecurityContext.cpp:151
Leosac::UserSecurityContext::UserSecurityContext
UserSecurityContext(DBServicePtr dbsrv, Auth::UserId id)
Definition: UserSecurityContext.cpp:32
Leosac::UserSecurityContext::is_manager
bool is_manager() const
Helper function that returns true if the user is at least manager.
Definition: UserSecurityContext.cpp:312
Leosac::SecurityContext::Action::ZONE_READ
@ ZONE_READ
Leosac::UserSecurityContext::user_id
Auth::UserId user_id() const
Definition: UserSecurityContext.cpp:325
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::Auth::UserPtr
std::shared_ptr< User > UserPtr
Definition: AuthFwd.hpp:31
Leosac::SecurityContext::Action::ACCESS_OVERVIEW
@ ACCESS_OVERVIEW
Overview of users/doors access permission.
Leosac::SecurityContext::Action::SCHEDULE_READ
@ SCHEDULE_READ
Leosac::UserSecurityContext::can_read_door
bool can_read_door(const DoorActionParam &dap) const
Definition: UserSecurityContext.cpp:274
Leosac::SecurityContext::Action::GROUP_UPDATE
@ GROUP_UPDATE
Leosac::Auth::GroupRank::ADMIN
@ ADMIN
Leosac::SecurityContext::UserActionParam
Definition: SecurityContext.hpp:172
Leosac::SecurityContext::Action::ACCESS_POINT_CREATE
@ ACCESS_POINT_CREATE
Leosac::UserSecurityContext::can_read_credential
bool can_read_credential(const CredentialActionParam &cap) const
Definition: UserSecurityContext.cpp:292
Leosac::UserSecurityContext::can_read_user
bool can_read_user(const UserActionParam &uap) const
Username, as well as a few basic (firstname, lastname) info are public.
Definition: UserSecurityContext.cpp:188
Leosac::SecurityContext::Action::USER_READ
@ USER_READ
Leosac::SecurityContext::ActionParam::group
GroupActionParam group
Definition: SecurityContext.hpp:232
Leosac::SecurityContext::MembershipActionParam::membership_id
Auth::UserGroupMembershipId membership_id
Definition: SecurityContext.hpp:188
Leosac::SecurityContext::Action::MEMBERSHIP_READ
@ MEMBERSHIP_READ
Leosac::SecurityContext::CredentialActionParam::credential_id
Cred::CredentialId credential_id
Definition: SecurityContext.hpp:181
Leosac::SecurityContext::Action::ZONE_CREATE
@ ZONE_CREATE
Leosac::SecurityContext::Action::GROUP_SEARCH
@ GROUP_SEARCH
Leosac::SecurityContext::Action::SMTP_GETCONFIG
@ SMTP_GETCONFIG
Retrieve SMTP configuration.
Leosac::SecurityContext::Action::DOOR_CREATE
@ DOOR_CREATE
Leosac::SecurityContext::ActionParam
Definition: SecurityContext.hpp:231
Leosac::SecurityContext::DoorActionParam
Definition: SecurityContext.hpp:203
Leosac::SecurityContext::Action::USER_CREATE
@ USER_CREATE
Leosac::SecurityContext::MembershipActionParam::rank
Auth::GroupRank rank
Definition: SecurityContext.hpp:191
Leosac::UserSecurityContext::self
Auth::UserPtr self() const
Load the User object that owns this security context.
Definition: UserSecurityContext.cpp:330
Leosac::SecurityContext::MembershipActionParam::group_id
Auth::GroupId group_id
Definition: SecurityContext.hpp:189
Leosac::SecurityContext::Action::IS_ADMIN
@ IS_ADMIN
A workaround permission that requires the user to be administrator.
Leosac::SecurityContext::Action::RESTART_SERVER
@ RESTART_SERVER
Perform to restart the Leosac server.
Leosac::SecurityContext::Action::USER_READ_EMAIL
@ USER_READ_EMAIL
Leosac::SecurityContext::Action::CREDENTIAL_UPDATE
@ CREDENTIAL_UPDATE
Leosac::SecurityContext::ScheduleActionParam::schedule_id
Tools::ScheduleId schedule_id
Definition: SecurityContext.hpp:198
Leosac::SecurityContext::Action::GROUP_MEMBERSHIP_JOINED
@ GROUP_MEMBERSHIP_JOINED
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
OptionalTransaction.hpp
Leosac::SecurityContext::Action::DOOR_UPDATE
@ DOOR_UPDATE
Leosac::SecurityContext::GroupActionParam::group_id
Auth::GroupId group_id
Definition: SecurityContext.hpp:167
Leosac::SecurityContext::Action::USER_DELETE
@ USER_DELETE
Leosac::UserSecurityContext::can_update_user
bool can_update_user(const UserActionParam &uap) const
Definition: UserSecurityContext.cpp:199
Leosac::UserSecurityContext::is_self
bool is_self(Auth::UserId id) const
Return true if the owner of the security context is the user whose id is id.
Definition: UserSecurityContext.cpp:320
MultiplexedTransaction.hpp
Leosac::db::MultiplexedTransaction
Acts like an odb::transaction, with the exception that it will becomes the active transaction at cons...
Definition: MultiplexedTransaction.hpp:35
Leosac::DBServicePtr
std::shared_ptr< DBService > DBServicePtr
Definition: db_fwd.hpp:34
Leosac::SecurityContext::DoorActionParam::door_id
Auth::DoorId door_id
Definition: SecurityContext.hpp:205
Leosac::UserSecurityContext::user_id_
Auth::UserId user_id_
Definition: UserSecurityContext.hpp:91
Leosac::SecurityContext::Action::GROUP_CREATE
@ GROUP_CREATE
Leosac::SecurityContext::Action::SMTP_SETCONFIG
@ SMTP_SETCONFIG
Edit the SMTP configuration.
Leosac::SecurityContext::Action::GROUP_DELETE
@ GROUP_DELETE
Leosac::SecurityContext::Action::IS_MANAGER
@ IS_MANAGER
Requires that the user be at least manager.
Leosac::SecurityContext::ActionParam::membership
MembershipActionParam membership
Definition: SecurityContext.hpp:233
Leosac::Auth::IDoorPtr
std::shared_ptr< IDoor > IDoorPtr
Definition: AuthFwd.hpp:104
Leosac::Auth::GroupPtr
std::shared_ptr< Group > GroupPtr
Definition: AuthFwd.hpp:37
Leosac::SecurityContext::Action::CREDENTIAL_DELETE
@ CREDENTIAL_DELETE
Leosac::SecurityContext::Action
Action
Definition: SecurityContext.hpp:45
Leosac::UserSecurityContext::is_admin
bool is_admin() const
Helper function that returns true if the user is an administrator.
Definition: UserSecurityContext.cpp:304
Leosac::SecurityContext::ActionParam::door
DoorActionParam door
Definition: SecurityContext.hpp:237
Leosac::Auth::UserGroupMembershipPtr
std::shared_ptr< UserGroupMembership > UserGroupMembershipPtr
Definition: AuthFwd.hpp:81
Leosac::SecurityContext::Action::GROUP_MEMBERSHIP_LEFT
@ GROUP_MEMBERSHIP_LEFT
Leosac::SecurityContext::Action::DOOR_DELETE
@ DOOR_DELETE
DBService.hpp
Leosac::UserSecurityContext::can_read_user_detail
bool can_read_user_detail(const UserActionParam &uap) const
Definition: UserSecurityContext.cpp:194
Leosac::SecurityContext::Action::SCHEDULE_SEARCH
@ SCHEDULE_SEARCH
Leosac::SecurityContext::Action::GROUP_LIST_MEMBERSHIP
@ GROUP_LIST_MEMBERSHIP
Ability to list member of a group.
Leosac::NullSecurityContext::check_permission_impl
virtual bool check_permission_impl(Action a, const ActionParam &ap) const override
Reimplement this method to provide permission checking.
Definition: UserSecurityContext.cpp:340
Leosac::SecurityContext::Action::USER_UPDATE_RANK
@ USER_UPDATE_RANK
Editing rank means being able to become administrator.
Leosac::SecurityContext::Action::ACCESS_POINT_READ
@ ACCESS_POINT_READ
Leosac::SecurityContext::CredentialActionParam
Definition: SecurityContext.hpp:179
Leosac::SecurityContext::Action::ZONE_DELETE
@ ZONE_DELETE
Leosac::Auth::UserRank::ADMIN
@ ADMIN
Site administrator.
log.hpp
Leosac::SecurityContext::Action::USER_CHANGE_PASSWORD
@ USER_CHANGE_PASSWORD
Leosac::SecurityContext::Action::ACCESS_POINT_UPDATE
@ ACCESS_POINT_UPDATE
Leosac::DBService::THROW_IF_NOT_FOUND
@ THROW_IF_NOT_FOUND
Definition: DBService.hpp:40
Leosac::SecurityContext::Action::ACCESS_POINT_SEARCH
@ ACCESS_POINT_SEARCH
Leosac::Auth::UserRank::MANAGER
@ MANAGER
Can access user management aswel as credential management.
Leosac::Auth::UserId
unsigned long UserId
Definition: AuthFwd.hpp:34
Leosac::SecurityContext::Action::AUDIT_READ
@ AUDIT_READ
Read the audit log.
Leosac::SecurityContext::Action::ZONE_UPDATE
@ ZONE_UPDATE
Leosac::UserSecurityContext::can_read_schedule
bool can_read_schedule(const ScheduleActionParam &sap) const
Definition: UserSecurityContext.cpp:253
Leosac::Auth::GroupRank
GroupRank
The rank of an User inside a Group.
Definition: AuthFwd.hpp:49
Leosac::SecurityContext::Action::USER_MANAGE_VALIDITY
@ USER_MANAGE_VALIDITY
Can we enable/disable the user or change its validity period ?
ScheduleMapping.hpp
Leosac::UserSecurityContext::can_delete_membership
bool can_delete_membership(const MembershipActionParam &map) const
Can we leave/kick someone from a group.
Definition: UserSecurityContext.cpp:225
Leosac::UserSecurityContext::check_permission_impl
virtual bool check_permission_impl(Action a, const ActionParam &ap) const override
Reimplement this method to provide permission checking.
Definition: UserSecurityContext.cpp:38
Leosac::SecurityContext::Action::SCHEDULE_DELETE
@ SCHEDULE_DELETE
Leosac::SecurityContext::ActionParam::cred
CredentialActionParam cred
Definition: SecurityContext.hpp:235
Leosac::SecurityContext::Action::SCHEDULE_UPDATE
@ SCHEDULE_UPDATE
Leosac::SecurityContext::dbsrv_
DBServicePtr dbsrv_
Definition: SecurityContext.hpp:273
Leosac::SecurityContext::Action::CREDENTIAL_READ
@ CREDENTIAL_READ
Leosac::SecurityContext::Action::ACCESS_POINT_DELETE
@ ACCESS_POINT_DELETE
Leosac::SecurityContext::MembershipActionParam
Definition: SecurityContext.hpp:186
Leosac::SecurityContext::UserActionParam::user_id
Auth::UserId user_id
Definition: SecurityContext.hpp:174
UserSecurityContext.hpp
Leosac::UserSecurityContext::can_create_membership
bool can_create_membership(const MembershipActionParam &map) const
Definition: UserSecurityContext.cpp:205
Leosac::NullSecurityContext::NullSecurityContext
NullSecurityContext()
Definition: UserSecurityContext.cpp:335
Leosac::SecurityContext::Action::CREDENTIAL_CREATE
@ CREDENTIAL_CREATE
Leosac::Auth::GroupRank::OPERATOR
@ OPERATOR
Leosac::SecurityContext::Action::AUDIT_READ_FULL
@ AUDIT_READ_FULL
Read the audit log and access additional information, such as the JSON "before" and "after" field.
Leosac::SecurityContext::Action::USER_UPDATE
@ USER_UPDATE
Leosac::SecurityContext
A SecurityContext is used to query permission while doing an operation.
Definition: SecurityContext.hpp:40
Leosac::SecurityContext::Action::LOG_READ
@ LOG_READ
Leosac::SecurityContext::Action::DOOR_SEARCH
@ DOOR_SEARCH
Leosac::SecurityContext::Action::SMTP_SENDMAIL
@ SMTP_SENDMAIL
Leosac::SecurityContext::ActionParam::user
UserActionParam user
Definition: SecurityContext.hpp:234