Leosac  0.8.0
Open Source Access Control
GroupCRUD.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 "api/GroupCRUD.hpp"
21 #include "Exceptions.hpp"
22 #include "api/APISession.hpp"
26 #include "core/auth/Group_odb.h"
27 #include "core/auth/User.hpp"
30 #include "tools/db/DBService.hpp"
31 #include "tools/log.hpp"
32 
33 using namespace Leosac;
34 using namespace Leosac::Module;
35 using namespace Leosac::Module::WebSockAPI;
36 
38  : CRUDResourceHandler(ctx)
39 {
40 }
41 
43 {
44  auto instance = CRUDResourceHandlerUPtr(new GroupCRUD(ctx));
45  return instance;
46 }
47 
48 boost::optional<json> GroupCRUD::create_impl(const json &req)
49 {
50  json rep;
51  DBPtr db = ctx_.dbsrv->db();
52  odb::transaction t(db->begin());
53 
54  // Sanitize input
55  Auth::GroupPtr new_group = std::make_shared<Auth::Group>();
56 
57  GroupJSONSerializer::unserialize(*new_group, req.at("attributes"),
59  validate_and_unique(new_group);
60 
61  db->persist(new_group);
62 
63  auto audit = Audit::Factory::GroupEvent(db, new_group, ctx_.audit);
64  audit->event_mask(Audit::EventType::GROUP_CREATED);
66  *new_group, SystemSecurityContext::instance()));
67  audit->finalize();
68 
69  // Add the current user to the group as administrator.
70  auto audit_add_to_group = Audit::Factory::UserGroupMembershipEvent(
71  db, new_group, ctx_.session->current_user(), ctx_.audit);
72  audit_add_to_group->event_mask(Audit::EventType::GROUP_MEMBERSHIP_JOINED);
73 
74  new_group->member_add(ctx_.session->current_user(), Auth::GroupRank::ADMIN);
75 
76  db->update(new_group);
77  audit_add_to_group->finalize();
78 
79  // Send the model back to the client, so it knows the ID.
80  rep["data"] = GroupJSONSerializer::serialize(*new_group, security_context());
81  t.commit();
82  return rep;
83 }
84 
85 boost::optional<json> GroupCRUD::read_impl(const json &req)
86 {
87  json rep;
88 
89  using Result = odb::result<Auth::Group>;
90  DBPtr db = ctx_.dbsrv->db();
91  odb::transaction t(db->begin());
92  auto gid = req.at("group_id").get<Auth::GroupId>();
93 
94  if (gid != 0)
95  {
96  auto group =
97  ctx_.dbsrv->find_group_by_id(gid, DBService::THROW_IF_NOT_FOUND);
98  rep["data"] = GroupJSONSerializer::serialize(*group, security_context());
99  }
100  else
101  {
102  Result result = db->query<Auth::Group>();
103  rep["data"] = json::array();
104  auto current_user = ctx_.session->current_user();
105 
106  // fixme: may be rather slow.
107  for (const auto &group : result)
108  {
109  if (ctx_.session->security_context().check_permission(
111  {.group = {.group_id = group.id()}}))
112  rep["data"].push_back(
114  }
115  }
116  t.commit();
117  return rep;
118 }
119 
120 boost::optional<json> GroupCRUD::update_impl(const json &req)
121 {
122  json rep;
123  DBPtr db = ctx_.dbsrv->db();
124  odb::transaction t(db->begin());
125  auto gid = req.at("group_id").get<Auth::GroupId>();
126 
127  auto grp = ctx_.dbsrv->find_group_by_id(gid, DBService::THROW_IF_NOT_FOUND);
128  auto audit = Audit::Factory::GroupEvent(db, grp, ctx_.audit);
129  audit->event_mask(Audit::EventType::GROUP_UPDATED);
132  GroupJSONSerializer::unserialize(*grp, req.at("attributes"), security_context());
133 
134  validate_and_unique(grp);
135  db->update(grp);
138 
139  audit->finalize();
140  rep["data"] = GroupJSONSerializer::serialize(*grp, security_context());
141  t.commit();
142  return rep;
143 }
144 
145 boost::optional<json> GroupCRUD::delete_impl(const json &req)
146 {
147  auto gid = req.at("group_id").get<Auth::GroupId>();
148  DBPtr db = ctx_.dbsrv->db();
149  odb::transaction t(db->begin());
150 
151  auto group = ctx_.dbsrv->find_group_by_id(gid, DBService::THROW_IF_NOT_FOUND);
152  auto audit = Audit::Factory::GroupEvent(db, group, ctx_.audit);
153  audit->event_mask(Audit::EventType::GROUP_DELETED);
156 
157  audit->finalize();
158  db->erase(group);
159  t.commit();
160 
161  return json{};
162 }
163 
164 void GroupCRUD::validate_and_unique(Auth::GroupPtr grp)
165 {
166  using Query = odb::query<Auth::Group>;
167 
169  auto grp_with_same_name =
170  ctx_.dbsrv->db()->query_one<Auth::Group>(Query::name == grp->name());
171  // Check that either the name is available, or the group under modification
172  // owns the name already.
173  if (grp_with_same_name && grp_with_same_name != grp)
174  {
175  throw ModelException(
176  "data/attributes/name",
177  BUILD_STR("A group named " << grp->name() << " already exists."));
178  }
179 }
180 
181 std::vector<CRUDResourceHandler::ActionActionParam>
182 GroupCRUD::required_permission(CRUDResourceHandler::Verb verb, const json &req) const
183 {
184  std::vector<CRUDResourceHandler::ActionActionParam> ret;
186  try
187  {
188  gap.group_id = req.at("group_id").get<Auth::GroupId>();
189  }
190  catch (const json::out_of_range &e)
191  {
192  gap.group_id = 0;
193  }
194  switch (verb)
195  {
196  case Verb::READ:
197  ret.push_back(std::make_pair(SecurityContext::Action::GROUP_READ, gap));
198  break;
199  case Verb::CREATE:
200  ret.push_back(std::make_pair(SecurityContext::Action::GROUP_CREATE, gap));
201  break;
202  case Verb::UPDATE:
203  ret.push_back(std::make_pair(SecurityContext::Action::GROUP_UPDATE, gap));
204  break;
205  case Verb::DELETE:
206  ret.push_back(std::make_pair(SecurityContext::Action::GROUP_DELETE, gap));
207  break;
208  }
209  return ret;
210 }
Leosac::SecurityContext::Action::GROUP_READ
@ GROUP_READ
Leosac::Audit::EventType::GROUP_CREATED
@ GROUP_CREATED
AuditFactory.hpp
Leosac::SystemSecurityContext::instance
static SecurityContext & instance()
Definition: SecurityContext.cpp:64
Leosac::GroupJSONSerializer::unserialize
static void unserialize(Auth::Group &out, const json &in, const SecurityContext &sc)
Definition: GroupSerializer.cpp:73
Leosac::SecurityContext::GroupActionParam
Definition: SecurityContext.hpp:165
Leosac::Module::WebSockAPI::GroupCRUD::validate_and_unique
void validate_and_unique(Auth::GroupPtr grp)
Make sure the group's attribute is valid (by calling GroupValidator) and that the name is unique.
Definition: GroupCRUD.cpp:164
Exceptions.hpp
BUILD_STR
#define BUILD_STR(param)
Internal macro.
Definition: log.hpp:63
Leosac::Module::WebSockAPI::GroupCRUD::create_impl
virtual boost::optional< json > create_impl(const json &req) override
Create a new group.
Definition: GroupCRUD.cpp:48
Leosac::Module::WebSockAPI::CRUDResourceHandlerUPtr
std::unique_ptr< CRUDResourceHandler > CRUDResourceHandlerUPtr
Definition: WebSockFwd.hpp:39
Leosac::Module::WebSockAPI::RequestContext::dbsrv
DBServicePtr dbsrv
Definition: RequestContext.hpp:39
Leosac::Audit::EventType::GROUP_MEMBERSHIP_JOINED
@ GROUP_MEMBERSHIP_JOINED
Someone joined the group.
Leosac::Module::WebSockAPI::CRUDResourceHandler
Base CRUD handler for use within the websocket module.
Definition: CRUDResourceHandler.hpp:84
Leosac::SecurityContext::Action::GROUP_UPDATE
@ GROUP_UPDATE
User.hpp
Leosac::Auth::GroupRank::ADMIN
@ ADMIN
Leosac::DBPtr
std::shared_ptr< odb::database > DBPtr
Definition: db_fwd.hpp:31
Leosac::Module
All modules that provides features to Leosac shall be in this namespace.
Query
odb::query< Tools::LogEntry > Query
Definition: LogEntry.cpp:36
IGroupEvent.hpp
Leosac::GroupJSONStringSerializer::serialize
static std::string serialize(const Auth::Group &in, const SecurityContext &sc)
Definition: GroupSerializer.cpp:82
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
Leosac::Audit::EventType::GROUP_DELETED
@ GROUP_DELETED
Leosac::SecurityContext::GroupActionParam::group_id
Auth::GroupId group_id
Definition: SecurityContext.hpp:167
Leosac::Module::WebSockAPI::GroupCRUD::GroupCRUD
GroupCRUD(RequestContext ctx)
Definition: GroupCRUD.cpp:37
Leosac::SecurityContext::Action::GROUP_CREATE
@ GROUP_CREATE
Leosac::SecurityContext::Action::GROUP_DELETE
@ GROUP_DELETE
Leosac::Module::WebSockAPI::CRUDResourceHandler::ctx_
RequestContext ctx_
Definition: CRUDResourceHandler.hpp:95
Leosac::Module::WebSockAPI::GroupCRUD::instanciate
static CRUDResourceHandlerUPtr instanciate(RequestContext)
Definition: GroupCRUD.cpp:42
Leosac::Auth::GroupPtr
std::shared_ptr< Group > GroupPtr
Definition: AuthFwd.hpp:37
Leosac::Auth::Group
A authentication group regroup users that share permissions.
Definition: Group.hpp:57
ModelException.hpp
IUserGroupMembershipEvent.hpp
ModelException
An exception class for general API error.
Definition: ModelException.hpp:33
Leosac::Audit::Factory::GroupEvent
static IGroupEventPtr GroupEvent(const DBPtr &database, Auth::GroupPtr target_group, IAuditEntryPtr parent)
Definition: AuditFactory.cpp:58
DBService.hpp
APISession.hpp
Leosac::GroupJSONSerializer::serialize
static json serialize(const Auth::Group &group, const SecurityContext &sc)
Definition: GroupSerializer.cpp:29
Leosac::Audit::EventType::GROUP_UPDATED
@ GROUP_UPDATED
Leosac::Auth::GroupId
unsigned long GroupId
Definition: AuthFwd.hpp:41
Leosac::Module::WebSockAPI::RequestContext::audit
Audit::IAuditEntryPtr audit
The initial audit trail for the request.
Definition: RequestContext.hpp:55
log.hpp
Leosac::DBService::THROW_IF_NOT_FOUND
@ THROW_IF_NOT_FOUND
Definition: DBService.hpp:40
Leosac::Module::WebSockAPI::json
nlohmann::json json
Definition: AccessOverview.hpp:30
Leosac::Module::WebSockAPI::RequestContext
Holds valuable pointer to provide context to a request.
Definition: RequestContext.hpp:36
Leosac::Auth::GroupValidator::validate
static void validate(const Group &grp)
Validate the group's attributes.
Definition: Group.cpp:167
Leosac::Module::WebSockAPI::GroupCRUD::read_impl
virtual boost::optional< json > read_impl(const json &req) override
Retrieve information about a group.
Definition: GroupCRUD.cpp:85
GroupSerializer.hpp
Leosac::Module::WebSockAPI
Definition: ActionActionParam.hpp:28
Leosac::Module::WebSockAPI::ICRUDResourceHandler::Verb
Verb
Definition: CRUDResourceHandler.hpp:43
GroupCRUD.hpp
Result
odb::result< Tools::LogEntry > Result
Definition: LogEntry.cpp:37
Leosac::Module::WebSockAPI::RequestContext::session
APIPtr session
Definition: RequestContext.hpp:38
Leosac::Module::WebSockAPI::CRUDResourceHandler::security_context
virtual UserSecurityContext & security_context() const override
Helper function that returns the security context.
Definition: CRUDResourceHandler.cpp:96
Leosac::Audit::Factory::UserGroupMembershipEvent
static IUserGroupMembershipEventPtr UserGroupMembershipEvent(const DBPtr &database, Auth::GroupPtr target_group, Auth::UserPtr target_user, IAuditEntryPtr parent)
Definition: AuditFactory.cpp:82