Skip to content

Commit 667cf30

Browse files
authored
Merge pull request #224 from Sambruk/feature/223
New functionality for blacklisting users.
2 parents cdd28b8 + e7c4d6c commit 667cf30

12 files changed

+337
-5
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Releases
22

3+
## Unreleased
4+
#### Features
5+
- New functionality for blacklisting users (#223)
6+
37
## v2.18 (2024-11-19)
48
#### Features
59
- Configurable thresholds to prevent accidental large changes (#196)

src/load_limiter.cpp

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* This file is part of the EGIL SCIM client.
33
*
4-
* Copyright (C) 2017-2019 Föreningen Sambruk
4+
* Copyright (C) 2017-2024 Föreningen Sambruk
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU Affero General Public License as
@@ -25,6 +25,31 @@
2525

2626
namespace pt = boost::property_tree;
2727

28+
namespace {
29+
std::shared_ptr<load_limiter> user_blacklist;
30+
}
31+
32+
void set_user_blacklist(const std::string &filename,
33+
const std::string &attribute) {
34+
user_blacklist = std::make_shared<not_limiter>(std::make_shared<list_limiter>(filename, attribute));
35+
}
36+
37+
/** If there is a user blacklist set, this function will return a new limiter based on the
38+
* passed in limiter. The returned limiter will work like the passed in limiter except that
39+
* it will exclude users from the blacklist.
40+
*
41+
* If no user blacklist is set the limiter will be returned as it is.
42+
*
43+
*/
44+
std::shared_ptr<load_limiter> combine_with_user_blacklist(std::shared_ptr<load_limiter> limiter) {
45+
if (user_blacklist == nullptr) {
46+
return limiter;
47+
}
48+
else {
49+
return std::make_shared<and_limiter>(std::vector<std::shared_ptr<load_limiter>>{limiter, user_blacklist});
50+
}
51+
}
52+
2853
std::shared_ptr<load_limiter> create_limiter_from_json(const pt::ptree& root);
2954

3055
std::vector<std::shared_ptr<load_limiter>> create_limiters_from_json_array(const pt::ptree& root) {
@@ -62,6 +87,13 @@ std::shared_ptr<load_limiter> create_limiter_from_json(const pt::ptree& root) {
6287
}
6388
}
6489

90+
/** Returns the limiter for a specific type, or for the SCIM endpoint
91+
* if there's no type specific limiter (or a null_limiter if there's
92+
* no endpoint limiter).
93+
* Note that if there's a user blacklist, it is not created here, the
94+
* caller of this function is expected to combine the limiter with
95+
* the user blacklist if the type is a user type.
96+
*/
6597
std::shared_ptr<load_limiter> create_limiter(const std::string& type) {
6698
config_file &conf = config_file::instance();
6799

@@ -118,7 +150,15 @@ std::shared_ptr<load_limiter> get_limiter(const std::string& type) {
118150
}
119151

120152
if (limiters.find(type) == limiters.end()) {
121-
limiters[type] = create_limiter(type);
153+
auto l = create_limiter(type);
154+
155+
// Figure out if we should add the user blacklist to the limiter
156+
auto endpoint_variable = type + "-scim-url-endpoint";
157+
if (conf.has(endpoint_variable) && conf.get(endpoint_variable) == "Users") {
158+
limiters[type] = combine_with_user_blacklist(l);
159+
} else {
160+
limiters[type] = l;
161+
}
122162
}
123163
return limiters[type];
124164
}

src/load_limiter.hpp

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* This file is part of the EGIL SCIM client.
33
*
4-
* Copyright (C) 2017-2019 Föreningen Sambruk
4+
* Copyright (C) 2017-2024 Föreningen Sambruk
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU Affero General Public License as
@@ -37,4 +37,18 @@ class load_limiter {
3737

3838
std::shared_ptr<load_limiter> get_limiter(const std::string& type);
3939

40+
/**
41+
* Sets a user blacklist. The blacklist works like a list limiter,
42+
* so the blacklisted users are listed in a file. If an attribute
43+
* is given, the values in the file are matched against that attribute
44+
* in the data source, otherwise the values are assumed to be UUIDs.
45+
*
46+
* If a blacklist is used, it will be combined with the limiters
47+
* returned by get_limiter (if called for a type that has "Users" as
48+
* the endpoint), so that the returned limiter excludes users from
49+
* the blacklist.
50+
*/
51+
void set_user_blacklist(const std::string &filename,
52+
const std::string &attrib);
53+
4054
#endif // EGILSCIM_LOAD_LIMITER_HPP

src/main.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ std::shared_ptr<rendered_object_list> read_cache(const post_processing::plugins&
187187
return rendered_cache;
188188
}
189189

190+
// TODO: Add the rest of the options names here
191+
namespace options {
192+
const char* USER_BLACKLIST_FILE = "user-blacklist-file";
193+
const char* USER_BLACKLIST_ATTRIBUTE = "user-blacklist-attribute";
194+
}
195+
190196
int main(int argc, char *argv[]) {
191197
try {
192198
po::options_description cmdline_options("All options");
@@ -231,6 +237,10 @@ int main(int argc, char *argv[]) {
231237
("force-update", po::value<std::vector<std::string>>(), "update object even if it hasn't changed")
232238
("force-create", po::value<std::vector<std::string>>(), "create object even if it's already in the cache");
233239

240+
generic.add_options()
241+
(options::USER_BLACKLIST_FILE, po::value<std::string>(), "a file of users which shall be blocked from loading")
242+
(options::USER_BLACKLIST_ATTRIBUTE, po::value<std::string>(), "attribute (in the data source) to match against user blacklist file");
243+
234244
hidden.add_options()
235245
("config-file", po::value<std::vector<std::string>>(), "config file");
236246

@@ -346,6 +356,16 @@ int main(int argc, char *argv[]) {
346356
}
347357
}
348358

359+
if (vm.count(options::USER_BLACKLIST_FILE)) {
360+
auto user_blacklist_file = filesystem::absolute(vm[options::USER_BLACKLIST_FILE].as<std::string>()).u8string();
361+
std::string user_blacklist_attribute;
362+
if (vm.count(options::USER_BLACKLIST_ATTRIBUTE)) {
363+
user_blacklist_attribute = vm[options::USER_BLACKLIST_ATTRIBUTE].as<std::string>();
364+
}
365+
set_user_blacklist(user_blacklist_file, user_blacklist_attribute);
366+
}
367+
368+
349369
/** Get objects from data source */
350370
data_server &server = data_server::instance();
351371
bool skip_load = vm.count("skip-load");

src/rendered_cache_file.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void write_object(ofstream& ofs, std::shared_ptr<rendered_object> object) {
138138
void write_objects(ofstream& ofs, std::shared_ptr<rendered_object_list> objects) {
139139
write<uint64_t>(ofs, objects->size());
140140

141-
for (const auto obj : *objects) {
141+
for (const auto& obj : *objects) {
142142
write_object(ofs, obj.second);
143143
}
144144
}

src/utility/simplescim_error_string.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static char prefix_buffer[1024];
3535
static int message_present = 0;
3636
static char message_buffer[1024];
3737

38-
static char error_string_buffer[1024];
38+
static char error_string_buffer[2051];
3939

4040
static const char *no_error = "No error";
4141

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
Activities /Activities/7f9f75d8-9c01-5c1d-83df-b0d47cf1e4c9 PUT
3+
4+
{
5+
"schemas": ["urn:scim:schemas:extension:sis:school:1.0:Activity"],
6+
"externalId": "7f9f75d8-9c01-5c1d-83df-b0d47cf1e4c9",
7+
"displayName": "grupp2-Activity",
8+
"owner": {
9+
"value": "8d371858-3fbd-4af2-ae33-84225ead4a1b",
10+
"$ref": "SchoolUnits/8d371858-3fbd-4af2-ae33-84225ead4a1b"
11+
},
12+
"groups": [{
13+
"value": "645ebd9d-55b5-4e7a-900a-92b9369c8f6a",
14+
"$ref": "StudentGroups/645ebd9d-55b5-4e7a-900a-92b9369c8f6a"
15+
}],
16+
"teachers": [
17+
18+
]
19+
}
20+
---
21+
---
22+
Activities /Activities/857d1f1d-3e23-5896-9877-406ce84be599 PUT
23+
24+
{
25+
"schemas": ["urn:scim:schemas:extension:sis:school:1.0:Activity"],
26+
"externalId": "857d1f1d-3e23-5896-9877-406ce84be599",
27+
"displayName": "grupp1-Activity",
28+
"owner": {
29+
"value": "8d371858-3fbd-4af2-ae33-84225ead4a1b",
30+
"$ref": "SchoolUnits/8d371858-3fbd-4af2-ae33-84225ead4a1b"
31+
},
32+
"groups": [{
33+
"value": "39074b36-e0ed-4443-a501-5148992014b9",
34+
"$ref": "StudentGroups/39074b36-e0ed-4443-a501-5148992014b9"
35+
}],
36+
"teachers": [
37+
38+
]
39+
}
40+
---
41+
---
42+
Activities /Activities/ce4d51e5-f563-5105-8a13-849088f1fc2d PUT
43+
44+
{
45+
"schemas": ["urn:scim:schemas:extension:sis:school:1.0:Activity"],
46+
"externalId": "ce4d51e5-f563-5105-8a13-849088f1fc2d",
47+
"displayName": "DNP-GRGRMAT01_6-Activity",
48+
"owner": {
49+
"value": "8d371858-3fbd-4af2-ae33-84225ead4a1b",
50+
"$ref": "SchoolUnits/8d371858-3fbd-4af2-ae33-84225ead4a1b"
51+
},
52+
"groups": [{
53+
"value": "def59679-3808-4210-a707-ebce13467206",
54+
"$ref": "StudentGroups/def59679-3808-4210-a707-ebce13467206"
55+
}],
56+
"teachers": [
57+
58+
]
59+
}
60+
---
61+
---
62+
Activities /Activities/3df5c3cd-1194-574e-b107-6973f5695a66 DELETE
63+
---
64+
---
65+
Activities /Activities/b2880a10-4561-5818-ae8c-27411b6d5a24 DELETE
66+
---
67+
---
68+
StudentGroups /StudentGroups/0d9a892f-3698-4b56-91c2-44fdb61dedf1 DELETE
69+
---
70+
---
71+
StudentGroups /StudentGroups/9e2b1131-aac4-4ba3-adc8-a232a2b553d8 DELETE
72+
---
73+
---
74+
Employments /Employments/163cbddb-9fd0-53df-81e4-e022c5dd5c71 DELETE
75+
---
76+
---
77+
Employments /Employments/3b86c590-551e-5464-84ee-d505effff97e DELETE
78+
---
79+
---
80+
Employments /Employments/db405316-e9d1-50d2-89c5-776f91ac2c98 DELETE
81+
---
82+
---
83+
Users /Users/75c666db-e60e-4687-bdd3-1af191fa6799 DELETE
84+
---
85+
---
86+
Users /Users/88c0f298-8e33-4566-ace7-6e26228a9bc6 DELETE
87+
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
StudentGroups /StudentGroups/0d9a892f-3698-4b56-91c2-44fdb61dedf1 PUT
3+
4+
{
5+
"schemas": [
6+
"urn:scim:schemas:extension:sis:school:1.0:StudentGroup"
7+
],
8+
"externalId": "0d9a892f-3698-4b56-91c2-44fdb61dedf1",
9+
"displayName": "DNP-SVASVA03_GY",
10+
"studentGroupType": "Undervisning",
11+
"owner": {
12+
"value": "7bbc6be0-5fa1-45d1-ba50-0736582190e2",
13+
"$ref": "SchoolUnits/7bbc6be0-5fa1-45d1-ba50-0736582190e2"
14+
},
15+
"studentMemberships": [
16+
17+
]
18+
}---
19+
---
20+
StudentGroups /StudentGroups/9e2b1131-aac4-4ba3-adc8-a232a2b553d8 PUT
21+
22+
{
23+
"schemas": [
24+
"urn:scim:schemas:extension:sis:school:1.0:StudentGroup"
25+
],
26+
"externalId": "9e2b1131-aac4-4ba3-adc8-a232a2b553d8",
27+
"displayName": "grupp3",
28+
"studentGroupType": "Undervisning",
29+
"owner": {
30+
"value": "7bbc6be0-5fa1-45d1-ba50-0736582190e2",
31+
"$ref": "SchoolUnits/7bbc6be0-5fa1-45d1-ba50-0736582190e2"
32+
},
33+
"studentMemberships": [
34+
35+
]
36+
}---
37+
---
38+
Users /Users/39732dea-e4a6-4d8f-96de-925a679c56ff DELETE
39+
---

test/tests/blacklist/pejo.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pejo

test/tests/blacklist/pejo_uuid.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2b3a480f-d0b9-4c09-bbac-70f915964b02

test/tests/blacklist/spec.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"description": "User blacklisting",
3+
"config": "configs/base/master.conf",
4+
"steps": [
5+
{ "scenario": [ "scenarios/base" ],
6+
"requests": "../base/init.txt"
7+
},
8+
{ "scenario": [],
9+
"commandLine": ["--user-blacklist-file=tests/blacklist/pejo.txt", "--user-blacklist-attribute=uid"],
10+
"requests": "../delete_student/delete.txt"
11+
},
12+
{ "scenario": [],
13+
"commandLine": ["--user-blacklist-file=tests/blacklist/pejo_uuid.txt"],
14+
"requests": null
15+
},
16+
{ "scenario": [],
17+
"commandLine": ["--user-blacklist-file=tests/blacklist/pejo_uuid.txt",
18+
"--D", "Student-limit-with=regex",
19+
"--D", "Student-limit-by=departmentNumber",
20+
"--D", "Student-limit-regex=6"],
21+
"requests": "limitstudentstograde6.txt"
22+
},
23+
{ "scenario": [],
24+
"commandLine": ["--user-blacklist-file=tests/blacklist/pejo_uuid.txt",
25+
"--D", "Users-limit-with=regex",
26+
"--D", "Users-limit-by=departmentNumber",
27+
"--D", "Users-limit-regex=6"],
28+
"requests": "limitalluserstograde6.txt"
29+
},
30+
{ "scenario": [],
31+
"commandLine": ["--D", "Users-limit-with=regex",
32+
"--D", "Users-limit-by=departmentNumber",
33+
"--D", "Users-limit-regex=6"],
34+
"requests": "unblacklistpejo.txt"
35+
}
36+
]
37+
}

0 commit comments

Comments
 (0)