irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

user_administration.cpp
Go to the documentation of this file.
2 
3 #undef rxGeneralAdmin
4 
5 #ifdef IRODS_USER_ADMINISTRATION_ENABLE_SERVER_SIDE_API
6  #include "rsGeneralAdmin.hpp"
7  #define rxGeneralAdmin rsGeneralAdmin
8  #define RODS_SERVER 1 // For irods::query<rsComm_t>
9 #else
10  #include "generalAdmin.h"
11  #define rxGeneralAdmin rcGeneralAdmin
12 #endif // IRODS_USER_ADMINISTRATION_ENABLE_SERVER_SIDE_API
13 
14 #include "obf.h"
15 #include "authenticate.h"
16 #include "irods_query.hpp"
17 #include "query_builder.hpp"
18 
19 #include <array>
20 #include <iostream>
21 
23 {
24  inline namespace v1
25  {
26  namespace
27  {
28  auto to_user_type(std::string_view user_type_string) -> user_type
29  {
30  // clang-format off
31  if (user_type_string == "rodsuser") { return user_type::rodsuser; }
32  else if (user_type_string == "groupadmin") { return user_type::groupadmin; }
33  else if (user_type_string == "rodsadmin") { return user_type::rodsadmin; }
34  // clang-format on
35 
36  throw user_management_error{"undefined user type"};
37  }
38 
39  auto to_zone_type(std::string_view zone_type_string) -> zone_type
40  {
41  // clang-format off
42  if (zone_type_string == "local") { return zone_type::local; }
43  else if (zone_type_string == "remote") { return zone_type::remote; }
44  // clang-format on
45 
46  throw user_management_error{"undefined zone type"};
47  }
48 
49  auto to_c_str(user_type user_type) -> const char*
50  {
51  // clang-format off
52  switch (user_type) {
53  case user_type::rodsuser: return "rodsuser";
54  case user_type::groupadmin: return "groupadmin";
55  case user_type::rodsadmin: return "rodsadmin";
56  default: break;
57  }
58  // clang-format on
59 
60  throw user_management_error{"cannot convert user_type to string"};
61  }
62 
63  auto get_local_zone(rxComm& conn) -> std::string
64  {
65 #ifdef IRODS_USER_ADMINISTRATION_ENABLE_SERVER_SIDE_API
66  return getLocalZoneName();
67 #else
68  for (auto&& row : irods::query{&conn, "select ZONE_NAME where ZONE_TYPE = 'local'"}) {
69  return row[0];
70  }
71 
72  throw user_management_error{"cannot get local zone name"};
73 #endif // IRODS_USER_ADMINISTRATION_ENABLE_SERVER_SIDE_API
74  }
75 
76  auto obfuscate_password(std::string_view new_password) -> std::string
77  {
78  std::array<char, MAX_PASSWORD_LEN + 10> plain_text_password{};
79  std::strncpy(plain_text_password.data(), new_password.data(), MAX_PASSWORD_LEN);
80 
81  if (const auto lcopy = MAX_PASSWORD_LEN - 10 - new_password.size(); lcopy > 15) {
82  // The random string (second argument) is used for padding and must match
83  // what is defined on the server-side.
84  std::strncat(plain_text_password.data(), "1gCBizHWbwIYyWLoysGzTe6SyzqFKMniZX05faZHWAwQKXf6Fs", lcopy);
85  }
86 
87  std::array<char, MAX_PASSWORD_LEN + 10> key{};
88 
89  // Decode (or prompt for current password) and store the obfuscated password in key.
90  // "obfGetPw" decodes the obfuscated password stored in .irods/.irodsA.
91  if (obfGetPw(key.data()) != 0) {
92  throw user_management_error{"password obfuscation failed"};
93  }
94 
95  std::array<char, MAX_PASSWORD_LEN + 100> obfuscate_password{};
96  obfEncodeByKey(plain_text_password.data(), key.data(), obfuscate_password.data());
97 
98  return obfuscate_password.data();
99  }
100  } // anonymous namespace
101 
102  auto add_user(rxComm& conn,
103  const user& user,
105  zone_type zone_type) -> std::error_code
106  {
107  std::string name = local_unique_name(conn, user);
108  std::string zone;
109 
110  if (zone_type::local == zone_type) {
111  zone = get_local_zone(conn);
112  }
113 
114  generalAdminInp_t input{};
115  input.arg0 = "add";
116  input.arg1 = "user";
117  input.arg2 = name.data();
118  input.arg3 = to_c_str(user_type);
119  input.arg4 = zone.data();
120 
121  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
122  return std::error_code{ec, std::generic_category()};
123  }
124 
125  return {};
126  }
127 
128  auto remove_user(rxComm& conn, const user& user) -> std::error_code
129  {
130  const auto name = local_unique_name(conn, user);
131 
132  generalAdminInp_t input{};
133  input.arg0 = "rm";
134  input.arg1 = "user";
135  input.arg2 = name.data();
136  input.arg3 = user.zone.data();
137 
138  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
139  return std::error_code{ec, std::generic_category()};
140  }
141 
142  return {};
143  }
144 
145  auto set_user_password(rxComm& conn, const user& user, std::string_view new_password) -> std::error_code
146  {
147  const auto obfuscated_password = obfuscate_password(new_password);
148 
149  generalAdminInp_t input{};
150  input.arg0 = "modify";
151  input.arg1 = "user";
152  input.arg2 = user.name.data();
153  input.arg3 = "password";
154  input.arg4 = obfuscated_password.data();
155 
156  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
157  return std::error_code{ec, std::generic_category()};
158  }
159 
160  return {};
161  }
162 
163  auto set_user_type(rxComm& conn, const user& user, user_type new_user_type) -> std::error_code
164  {
165  const auto name = local_unique_name(conn, user);
166 
167  generalAdminInp_t input{};
168  input.arg0 = "modify";
169  input.arg1 = "user";
170  input.arg2 = name.data();
171  input.arg3 = "type";
172  input.arg4 = to_c_str(new_user_type);
173 
174  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
175  return std::error_code{ec, std::generic_category()};
176  }
177 
178  return {};
179  }
180 
181  auto add_user_auth(rxComm& conn, const user& user, std::string_view auth) -> std::error_code
182  {
183  const auto name = local_unique_name(conn, user);
184 
185  generalAdminInp_t input{};
186  input.arg0 = "modify";
187  input.arg1 = "user";
188  input.arg2 = name.data();
189  input.arg3 = "addAuth";
190  input.arg4 = auth.data();
191 
192  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
193  return std::error_code{ec, std::generic_category()};
194  }
195 
196  return {};
197  }
198 
199  auto remove_user_auth(rxComm& conn, const user& user, std::string_view auth) -> std::error_code
200  {
201  const auto name = local_unique_name(conn, user);
202 
203  generalAdminInp_t input{};
204  input.arg0 = "modify";
205  input.arg1 = "user";
206  input.arg2 = name.data();
207  input.arg3 = "rmAuth";
208  input.arg4 = auth.data();
209 
210  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
211  return std::error_code{ec, std::generic_category()};
212  }
213 
214  return {};
215  }
216 
217  // Group Management
218 
219  auto add_group(rxComm& conn, const group& group) -> std::error_code
220  {
221  const auto zone = get_local_zone(conn);
222 
223  generalAdminInp_t input{};
224  input.arg0 = "add";
225  input.arg1 = "user";
226  input.arg2 = group.name.data();
227  input.arg3 = "rodsgroup";
228  input.arg4 = zone.data();
229 
230  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
231  return std::error_code{ec, std::generic_category()};
232  }
233 
234  return {};
235  }
236 
237  auto remove_group(rxComm& conn, const group& group) -> std::error_code
238  {
239  const auto zone = get_local_zone(conn);
240 
241  generalAdminInp_t input{};
242  input.arg0 = "rm";
243  input.arg1 = "user";
244  input.arg2 = group.name.data();
245  input.arg3 = zone.data();
246 
247  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
248  return std::error_code{ec, std::generic_category()};
249  }
250 
251  return {};
252  }
253 
254  auto add_user_to_group(rxComm& conn, const group& group, const user& user) -> std::error_code
255  {
256  generalAdminInp_t input{};
257  input.arg0 = "modify";
258  input.arg1 = "group";
259  input.arg2 = group.name.data();
260  input.arg3 = "add";
261  input.arg4 = user.name.data();
262  input.arg5 = user.zone.data();
263 
264  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
265  return std::error_code{ec, std::generic_category()};
266  }
267 
268  return {};
269  }
270 
271  auto remove_user_from_group(rxComm& conn, const group& group, const user& user) -> std::error_code
272  {
273  generalAdminInp_t input{};
274  input.arg0 = "modify";
275  input.arg1 = "group";
276  input.arg2 = group.name.data();
277  input.arg3 = "remove";
278  input.arg4 = user.name.data();
279  input.arg5 = user.zone.data();
280 
281  if (const auto ec = rxGeneralAdmin(&conn, &input); ec != 0) {
282  return std::error_code{ec, std::generic_category()};
283  }
284 
285  return {};
286  }
287 
288  // Query
289 
290  auto users(rxComm& conn) -> std::vector<user>
291  {
292  std::vector<user> users;
293 
294  for (auto&& row : irods::query{&conn, "select USER_NAME, USER_ZONE where USER_TYPE != 'rodsgroup'"}) {
295  users.emplace_back(row[0], row[1]);
296  }
297 
298  return users;
299  }
300 
301  auto users(rxComm& conn, const group& group) -> std::vector<user>
302  {
303  std::vector<user> users;
304 
305  std::string gql = "select USER_NAME, USER_ZONE "
306  "where USER_TYPE != 'rodsgroup' and USER_GROUP_NAME = '";
307  gql += group.name;
308  gql += "'";
309 
310  for (auto&& row : irods::query{&conn, gql}) {
311  users.emplace_back(row[0], row[1]);
312  }
313 
314  return users;
315  }
316 
317  auto groups(rxComm& conn) -> std::vector<group>
318  {
319  std::vector<group> groups;
320 
321  for (auto&& row : irods::query{&conn, "select USER_GROUP_NAME where USER_TYPE = 'rodsgroup'"}) {
322  groups.emplace_back(row[0]);
323  }
324 
325  return groups;
326  }
327 
328  auto groups(rxComm& conn, const user& user) -> std::vector<group>
329  {
330  std::vector<std::string> args{local_unique_name(conn, user)};
331 
332  query_builder qb;
333 
335  .zone_hint(user.zone.empty() ? get_local_zone(conn) : user.zone)
336  .bind_arguments(args);
337 
338  std::vector<group> groups;
339 
340  try {
341  for (auto&& row : qb.build(conn, "listGroupsForUser")) {
342  groups.emplace_back(row[1]);
343  }
344  }
345  catch (...) {
346  // GenQuery fallback.
347  groups.clear();
348 
349  for (auto&& g : NAMESPACE_IMPL::groups(conn)) {
350  if (user_is_member_of_group(conn, g, user)) {
351  groups.push_back(std::move(g));
352  }
353  }
354  }
355 
356  return groups;
357  }
358 
359  auto exists(rxComm& conn, const user& user) -> bool
360  {
361  std::string gql = "select USER_ID where USER_TYPE != 'rodsgroup' and USER_NAME = '";
362  gql += user.name;
363  gql += "' and USER_ZONE = '";
364  gql += (user.zone.empty() ? get_local_zone(conn) : user.zone);
365  gql += "'";
366 
367  for (auto&& row : irods::query{&conn, gql}) {
368  static_cast<void>(row);
369  return true;
370  }
371 
372  return false;
373  }
374 
375  auto exists(rxComm& conn, const group& group) -> bool
376  {
377  std::string gql = "select USER_GROUP_ID where USER_TYPE = 'rodsgroup' and USER_GROUP_NAME = '";
378  gql += group.name;
379  gql += "'";
380 
381  for (auto&& row : irods::query{&conn, gql}) {
382  static_cast<void>(row);
383  return true;
384  }
385 
386  return false;
387  }
388 
389  auto id(rxComm& conn, const user& user) -> std::optional<std::string>
390  {
391  std::string gql = "select USER_ID where USER_TYPE != 'rodsgroup' and USER_NAME = '";
392  gql += local_unique_name(conn, user);
393  gql += "' and USER_ZONE = '";
394  gql += (user.zone.empty() ? get_local_zone(conn) : user.zone);
395  gql += "'";
396 
397  for (auto&& row : irods::query{&conn, gql}) {
398  return row[0];
399  }
400 
401  return std::nullopt;
402  }
403 
404  auto id(rxComm& conn, const group& group) -> std::optional<std::string>
405  {
406  std::string gql = "select USER_GROUP_ID where USER_TYPE = 'rodsgroup' and USER_GROUP_NAME = '";
407  gql += group.name;
408  gql += "'";
409 
410  for (auto&& row : irods::query{&conn, gql}) {
411  return row[0];
412  }
413 
414  return std::nullopt;
415  }
416 
417  auto type(rxComm& conn, const user& user) -> std::optional<user_type>
418  {
419  std::string gql = "select USER_TYPE where USER_TYPE != 'rodsgroup' and USER_NAME = '";
420  gql += local_unique_name(conn, user);
421  gql += "' and USER_ZONE = '";
422  gql += (user.zone.empty() ? get_local_zone(conn) : user.zone);
423  gql += "'";
424 
425  for (auto&& row : irods::query{&conn, gql}) {
426  return to_user_type(row[0]);
427  }
428 
429  return std::nullopt;
430  }
431 
432  auto auth_names(rxComm& conn, const user& user) -> std::vector<std::string>
433  {
434  std::vector<std::string> auth_names;
435 
436  std::string gql = "select USER_DN where USER_TYPE != 'rodsgroup' and USER_NAME = '";
437  gql += local_unique_name(conn, user);
438  gql += "' and USER_ZONE = '";
439  gql += (user.zone.empty() ? get_local_zone(conn) : user.zone);
440  gql += "'";
441 
442  for (auto&& row : irods::query{&conn, gql}) {
443  auth_names.push_back(row[0]);
444  }
445 
446  return auth_names;
447  }
448 
449  auto user_is_member_of_group(rxComm& conn, const group& group, const user& user) -> bool
450  {
451  std::string gql = "select USER_ID where USER_TYPE != 'rodsgroup' and USER_NAME = '";
452  gql += local_unique_name(conn, user);
453  gql += "' and USER_ZONE = '";
454  gql += (user.zone.empty() ? get_local_zone(conn) : user.zone);
455  gql += "' and USER_GROUP_NAME = '";
456  gql += group.name;
457  gql += "'";
458 
459  for (auto&& row : irods::query{&conn, gql}) {
460  static_cast<void>(row);
461  return true;
462  }
463 
464  return false;
465  }
466 
467  // Utility
468 
469  auto local_unique_name(rxComm& conn, const user& user) -> std::string
470  {
471  // Implies that the user belongs to the local zone and
472  // is not a remote user (i.e. federation).
473  if (user.zone.empty()) {
474  return user.name;
475  }
476 
477  auto name = user.name;
478 
479  if (user.zone != get_local_zone(conn)) {
480  name += '#';
481  name += user.zone;
482  }
483 
484  return name;
485  }
486  } // namespace v1
487 } // namespace irods::experimental::administration::NAMESPACE_IMPL
488 
irods::experimental::administration::client::v1::add_user
auto add_user(rcComm_t &conn, const user &user, user_type user_type=user_type::rodsuser, zone_type zone_type=zone_type::local) -> std::error_code
Definition: user_administration.cpp:102
generalAdminInp_t
Definition: generalAdmin.h:6
obf.h
authenticate.h
irods::experimental::query_type::general
@ general
irods::experimental::administration::client::v1::add_group
auto add_group(rcComm_t &conn, const group &group) -> std::error_code
Definition: user_administration.cpp:219
generalAdmin.h
irods::experimental::administration::client::v1::exists
auto exists(rcComm_t &conn, const user &user) -> bool
Definition: user_administration.cpp:359
NAMESPACE_IMPL
#define NAMESPACE_IMPL
Definition: default_transport.hpp:36
rxComm
#define rxComm
Definition: default_transport.hpp:38
irods::experimental::administration::v1::user
Definition: user.hpp:13
irods::experimental::query_builder
Definition: query_builder.hpp:19
generate_iadmin_commands_for_41_to_42_upgrade.name
name
Definition: generate_iadmin_commands_for_41_to_42_upgrade.py:23
generalAdminInp_t::arg0
const char * arg0
Definition: generalAdmin.h:7
MAX_PASSWORD_LEN
#define MAX_PASSWORD_LEN
Definition: authenticate.h:9
id
long long id
Definition: filesystem.cpp:105
irods::experimental::administration::v1::user_type
user_type
Definition: user_administration.hpp:33
rxGeneralAdmin
#define rxGeneralAdmin
Definition: user_administration.cpp:11
irods::auth
Definition: irods_auth_plugin.hpp:17
rsGeneralAdmin.hpp
irods_query.hpp
irods::experimental::administration::v1::group::name
std::string name
Definition: group.hpp:19
irods::experimental::administration::client::v1::local_unique_name
auto local_unique_name(rcComm_t &conn, const user &user) -> std::string
Definition: user_administration.cpp:469
irods::experimental::query_builder::type
auto type(query_type _v) noexcept -> query_builder &
Definition: query_builder.hpp:21
irods::experimental::administration::client::v1::add_user_auth
auto add_user_auth(rcComm_t &conn, const user &user, std::string_view auth) -> std::error_code
Definition: user_administration.cpp:181
obfGetPw
int obfGetPw(char *pw)
Definition: obf.cpp:159
irods::experimental::administration::client::v1::remove_user_auth
auto remove_user_auth(rcComm_t &conn, const user &user, std::string_view auth) -> std::error_code
Definition: user_administration.cpp:199
irods::experimental::administration::v1::user::zone
std::string zone
Definition: user.hpp:21
irods::experimental::filesystem::client::move
auto move(rcComm_t &_comm, const path &_old_p, const path &_new_p) -> void
Definition: filesystem.cpp:881
user_administration.hpp
irods::experimental::query_builder::build
auto build(ConnectionType &_conn, const std::string &_query) -> irods::query< ConnectionType >
Definition: query_builder.hpp:63
irods::experimental::administration::client::v1::add_user_to_group
auto add_user_to_group(rcComm_t &conn, const group &group, const user &user) -> std::error_code
Definition: user_administration.cpp:254
irods::experimental::administration::client::v1::users
auto users(rcComm_t &conn) -> std::vector< user >
Definition: user_administration.cpp:290
getLocalZoneName
char * getLocalZoneName()
Definition: rodsConnect.cpp:685
irods::experimental::administration::client::v1::set_user_type
auto set_user_type(rcComm_t &conn, const user &user, user_type new_user_type) -> std::error_code
Definition: user_administration.cpp:163
irods::experimental::administration::client::v1::user_is_member_of_group
auto user_is_member_of_group(rcComm_t &conn, const group &group, const user &user) -> bool
Definition: user_administration.cpp:449
query_builder.hpp
irods::experimental::administration::client::v1::remove_user_from_group
auto remove_user_from_group(rcComm_t &conn, const group &group, const user &user) -> std::error_code
Definition: user_administration.cpp:271
irods::experimental::administration::client::v1::set_user_password
auto set_user_password(rcComm_t &conn, const user &user, std::string_view new_password) -> std::error_code
Definition: user_administration.cpp:145
irods::experimental::administration::v1::user::name
std::string name
Definition: user.hpp:20
irods::experimental::administration::v1::group
Definition: group.hpp:12
irods::query
Definition: irods_query.hpp:25
irods::experimental::administration::client::v1::remove_user
auto remove_user(rcComm_t &conn, const user &user) -> std::error_code
Definition: user_administration.cpp:128
irods::experimental::administration::client::v1::groups
auto groups(rcComm_t &conn) -> std::vector< group >
Definition: user_administration.cpp:317
irods::experimental::administration::client::v1::auth_names
auto auth_names(rcComm_t &conn, const user &user) -> std::vector< std::string >
Definition: user_administration.cpp:432
obfEncodeByKey
void obfEncodeByKey(const char *in, const char *key, char *out)
Definition: obf.cpp:1007
irods::experimental::administration::v1::zone_type
zone_type
Definition: user_administration.hpp:40
type
int type
Definition: filesystem.cpp:103
irods::experimental::administration::client::v1::remove_group
auto remove_group(rcComm_t &conn, const group &group) -> std::error_code
Definition: user_administration.cpp:237