From 54c2d2b348dd6159d60e266fe4a64e4f8554cae0 Mon Sep 17 00:00:00 2001 From: Dominik Frantisek Bucik Date: Mon, 22 Jan 2024 12:28:19 +0100 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Load=20user=20mappin?= =?UTF-8?q?gs=20from=20a=20external=20JSON=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use option `usersFilePath` to configure path to the file containing mapping of users to accounts. This option is an alternative to the `users` option in the module configuration file. --- README.md | 5 ++-- .../config_template.json | 1 + examples/user_mappings.json | 11 +++++++ src/include/config.cpp | 29 +++++++++++++------ src/include/config.hpp | 6 ++++ 5 files changed, 41 insertions(+), 11 deletions(-) rename config_template.json => examples/config_template.json (95%) create mode 100644 examples/user_mappings.json diff --git a/README.md b/README.md index 3bf2d03..d517743 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,9 @@ Edit `/etc/pam_oauth2_device/config.json`. - 0 - low - 1 - medium - 2 - high -- `users` User mapping from claim configured in _username_attribute_ - to the local account name. +- `users` User mapping from claim configured in _username_attribute_ to the local account name. +- `usersFilePath` Path to a JSON file containing user mappings. An alternative to the `users` option +of the module configuration file. - `oauth` configuration for the OIDC identity provider. - `require_mfa`: if `true` the module will modify the requests to ask user to perform the MFA. diff --git a/config_template.json b/examples/config_template.json similarity index 95% rename from config_template.json rename to examples/config_template.json index 3e21eba..a0ea105 100644 --- a/config_template.json +++ b/examples/config_template.json @@ -27,6 +27,7 @@ "show": true, "error_correction_level": 0 }, + "usersFilePath": "./user_mappings.json", "users": { "provider_user_id_1": [ "root", diff --git a/examples/user_mappings.json b/examples/user_mappings.json new file mode 100644 index 0000000..29eda35 --- /dev/null +++ b/examples/user_mappings.json @@ -0,0 +1,11 @@ +{ + "users": { + "provider_user_id_1": [ + "root", + "bob" + ], + "provider_user_id_2": [ + "mike" + ] + } +} \ No newline at end of file diff --git a/src/include/config.cpp b/src/include/config.cpp index 3b4d877..626a4b0 100644 --- a/src/include/config.cpp +++ b/src/include/config.cpp @@ -37,16 +37,27 @@ void Config::load(const char *path) { ldap_filter = j.at("ldap").at("filter").get(); ldap_attr = j.at("ldap").at("attr").get(); } + json users_json; if (j.find("users") != j.end()) { - for (auto &element : j["users"].items()) { - for (auto &local_user : element.value()) { - if (usermap.find(element.key()) == usermap.end()) { - std::set userset; - userset.insert((std::string)local_user); - usermap[element.key()] = userset; - } else { - usermap[element.key()].insert((std::string)local_user); - } + users_json = j.at("users"); + Config::fill_user_map_from_json(usermap, j); + } else if (j.find("usersFilePath") != j.end()) { + std::string users_path = j.at("usersFilePath").get(); + std::ifstream users_fstream(users_path); + users_fstream >> users_json; + Config::fill_user_map_from_json(usermap, j); + } +} + +void Config::fill_user_map_from_json(std::map>& user_map, json& j) { + for (auto const &element : j["users"].items()) { + for (auto const &local_user : element.value()) { + if (user_map.find(element.key()) == user_map.end()) { + std::set userset; + userset.insert((std::string)local_user); + user_map[element.key()] = userset; + } else { + user_map[element.key()].insert((std::string)local_user); } } } diff --git a/src/include/config.hpp b/src/include/config.hpp index dee3546..2a5194a 100644 --- a/src/include/config.hpp +++ b/src/include/config.hpp @@ -5,6 +5,10 @@ #include #include +#include "nlohmann/json.hpp" + +using json = nlohmann::json; + class Config { public: void load(const char *path); @@ -15,6 +19,8 @@ class Config { std::set ldap_hosts; int qr_error_correction_level; std::map> usermap; + private: + void fill_user_map_from_json(std::map>& user_map, json& j); }; #endif // PAM_OAUTH2_DEVICE_CONFIG_HPP From 15729c7c8aa6ed00a96bdad72cbec1683cda69af Mon Sep 17 00:00:00 2001 From: Dominik Frantisek Bucik Date: Mon, 22 Jan 2024 12:29:00 +0100 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Add=20`.idea`=20fol?= =?UTF-8?q?der=20to=20`.gitignore`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e283998..bcc81a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ # Created by .ignore support plugin (hsz.mobi) +.idea + ### Python template # Byte-compiled / optimized / DLL files __pycache__/ From 9cf60207f2551d37e85954c8c7c38827a6aeea9d Mon Sep 17 00:00:00 2001 From: Dominik Frantisek Bucik Date: Mon, 22 Jan 2024 12:53:24 +0100 Subject: [PATCH 3/5] =?UTF-8?q?style:=20=F0=9F=92=84=20files=20config.cpp?= =?UTF-8?q?=20and=20config.hpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/user_mappings.json | 2 +- src/include/config.cpp | 62 +++++++++++++++++++------------------ src/include/config.hpp | 34 +++++++++++++++----- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/examples/user_mappings.json b/examples/user_mappings.json index 29eda35..58ad102 100644 --- a/examples/user_mappings.json +++ b/examples/user_mappings.json @@ -8,4 +8,4 @@ "mike" ] } -} \ No newline at end of file +} diff --git a/src/include/config.cpp b/src/include/config.cpp index 626a4b0..079c3bf 100644 --- a/src/include/config.cpp +++ b/src/include/config.cpp @@ -5,60 +5,62 @@ #include "nlohmann/json.hpp" +using namespace std; using json = nlohmann::json; void Config::load(const char *path) { - std::ifstream config_fstream(path); + ifstream config_fstream(path); json j; config_fstream >> j; + + json oauth_json = j.at("oauth"); - client_id = j.at("oauth").at("client").at("id").get(); - client_secret = j.at("oauth").at("client").at("secret").get(); - scope = j.at("oauth").at("scope").get(); - device_endpoint = j.at("oauth").at("device_endpoint").get(); - token_endpoint = j.at("oauth").at("token_endpoint").get(); - userinfo_endpoint = j.at("oauth").at("userinfo_endpoint").get(); - username_attribute = - j.at("oauth").at("username_attribute").get(); - require_mfa = j["oauth"].contains("require_mfa") - ? j.at("oauth").at("require_mfa").get() - : false; + client_id = oauth_json.at("client").at("id").get(); + client_secret = oauth_json.at("client").at("secret").get(); + scope = oauth_json.at("scope").get(); + device_endpoint = oauth_json.at("device_endpoint").get(); + token_endpoint = oauth_json.at("token_endpoint").get(); + userinfo_endpoint = oauth_json.at("userinfo_endpoint").get(); + username_attribute = oauth_json.at("username_attribute").get(); + require_mfa = oauth_json.contains("require_mfa") && oauth_json.at("require_mfa").get(); + + json qr_json = j.at("qr"); qr_error_correction_level = - j.at("qr").at("error_correction_level").get(); - qr_show = - (j["qr"].contains("show")) ? j.at("qr").at("show").get() : true; - if (j.find("ldap") != j.end() && j["ldap"].find("hosts") != j["ldap"].end()) { - for (auto &host : j["ldap"]["hosts"]) { - ldap_hosts.insert((std::string)host); + qr_json.at("error_correction_level").get(); + qr_show = qr_json.contains("show") && qr_json.at("show").get(); + + if (j.find("ldap") != j.end() && j.at("ldap").find("hosts") != j.at("ldap").end()) { + json ldap_json = j.at("ldap"); + for (auto const &host : ldap_json.at("hosts")) { + ldap_hosts.insert((string)host); } - ldap_basedn = j.at("ldap").at("basedn").get(); - ldap_user = j.at("ldap").at("user").get(); - ldap_passwd = j.at("ldap").at("passwd").get(); - ldap_filter = j.at("ldap").at("filter").get(); - ldap_attr = j.at("ldap").at("attr").get(); + ldap_basedn = ldap_json.at("basedn").get(); + ldap_user = ldap_json.at("user").get(); + ldap_passwd = ldap_json.at("passwd").get(); + ldap_filter = ldap_json.at("filter").get(); + ldap_attr = ldap_json.at("attr").get(); } + json users_json; if (j.find("users") != j.end()) { users_json = j.at("users"); Config::fill_user_map_from_json(usermap, j); } else if (j.find("usersFilePath") != j.end()) { - std::string users_path = j.at("usersFilePath").get(); - std::ifstream users_fstream(users_path); + string users_path = j.at("usersFilePath").get(); + ifstream users_fstream(users_path); users_fstream >> users_json; Config::fill_user_map_from_json(usermap, j); } } -void Config::fill_user_map_from_json(std::map>& user_map, json& j) { +void Config::fill_user_map_from_json(map>& user_map, json& j) { for (auto const &element : j["users"].items()) { for (auto const &local_user : element.value()) { if (user_map.find(element.key()) == user_map.end()) { - std::set userset; - userset.insert((std::string)local_user); + set userset; user_map[element.key()] = userset; - } else { - user_map[element.key()].insert((std::string)local_user); } + user_map[element.key()].insert((string)local_user); } } } diff --git a/src/include/config.hpp b/src/include/config.hpp index 2a5194a..27a0fd1 100644 --- a/src/include/config.hpp +++ b/src/include/config.hpp @@ -3,7 +3,6 @@ #include #include -#include #include "nlohmann/json.hpp" @@ -11,16 +10,35 @@ using json = nlohmann::json; class Config { public: - void load(const char *path); - std::string client_id, client_secret, scope, device_endpoint, token_endpoint, - userinfo_endpoint, username_attribute, ldap_basedn, ldap_user, - ldap_passwd, ldap_filter, ldap_attr; - bool require_mfa, qr_show; - std::set ldap_hosts; + // OAuth2 + std::string client_id; + std::string client_secret; + std::string scope; + std::string device_endpoint; + std::string token_endpoint; + std::string userinfo_endpoint; + std::string username_attribute; + bool require_mfa; + + // QR code + bool qr_show; int qr_error_correction_level; + + // LDAP + std::string ldap_basedn; + std::string ldap_user; + std::string ldap_passwd; + std::string ldap_filter; + std::string ldap_attr; + std::set ldap_hosts; + + // usermap std::map> usermap; + + // functions + void load(const char *path); private: - void fill_user_map_from_json(std::map>& user_map, json& j); + static void fill_user_map_from_json(std::map>& user_map, json& j); }; #endif // PAM_OAUTH2_DEVICE_CONFIG_HPP From 3e686414d81a9fb6472d374465746472d4525072 Mon Sep 17 00:00:00 2001 From: Dominik Frantisek Bucik Date: Tue, 23 Jan 2024 10:58:44 +0100 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=F0=9F=90=9B=20pass=20correct=20JSON?= =?UTF-8?q?=20to=20fill=20users=20map?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/include/config.cpp | 13 +++++++------ src/include/config.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/include/config.cpp b/src/include/config.cpp index 079c3bf..c8964f0 100644 --- a/src/include/config.cpp +++ b/src/include/config.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "nlohmann/json.hpp" @@ -44,23 +45,23 @@ void Config::load(const char *path) { json users_json; if (j.find("users") != j.end()) { users_json = j.at("users"); - Config::fill_user_map_from_json(usermap, j); + Config::fill_user_map_from_json(users_json); } else if (j.find("usersFilePath") != j.end()) { string users_path = j.at("usersFilePath").get(); ifstream users_fstream(users_path); users_fstream >> users_json; - Config::fill_user_map_from_json(usermap, j); + Config::fill_user_map_from_json(users_json); } } -void Config::fill_user_map_from_json(map>& user_map, json& j) { +void Config::fill_user_map_from_json(json& j) { for (auto const &element : j["users"].items()) { for (auto const &local_user : element.value()) { - if (user_map.find(element.key()) == user_map.end()) { + if (usermap.find(element.key()) == usermap.end()) { set userset; - user_map[element.key()] = userset; + usermap[element.key()] = userset; } - user_map[element.key()].insert((string)local_user); + usermap[element.key()].insert((string)local_user); } } } diff --git a/src/include/config.hpp b/src/include/config.hpp index 27a0fd1..4024d11 100644 --- a/src/include/config.hpp +++ b/src/include/config.hpp @@ -38,7 +38,7 @@ class Config { // functions void load(const char *path); private: - static void fill_user_map_from_json(std::map>& user_map, json& j); + void fill_user_map_from_json(json& j); }; #endif // PAM_OAUTH2_DEVICE_CONFIG_HPP From 46ebcda8ec74f4be43115d26e509ab0f6bdb213a Mon Sep 17 00:00:00 2001 From: Dominik Frantisek Bucik Date: Tue, 23 Jan 2024 13:45:36 +0100 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=F0=9F=90=9B=20remove=20ANSI=20chars?= =?UTF-8?q?=20from=20QR=20Code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pam_oauth2_device.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/pam_oauth2_device.cpp b/src/pam_oauth2_device.cpp index 7bf4519..4b3aab6 100644 --- a/src/pam_oauth2_device.cpp +++ b/src/pam_oauth2_device.cpp @@ -59,20 +59,21 @@ std::string getQr(const char *text, const int ecc = 0, const int border = 1) { qrcodegen::QrCode::encodeText(text, error_correction_level); std::ostringstream oss; - int i, j, size, top, bottom; - size = qr.getSize(); - for (j = -border; j < size + border; j += 2) { - for (i = -border; i < size + border; ++i) { - top = qr.getModule(i, j); - bottom = qr.getModule(i, j + 1); + + int size = qr.getSize(); + for (int j = -border; j < size + border; j += 2) { + for (int i = -border; i < size + border; ++i) { + int top = qr.getModule(i, j); + int bottom = qr.getModule(i, j + 1); + if (top && bottom) { - oss << "\033[40;97m \033[0m"; - } else if (top && !bottom) { - oss << "\033[40;97m\u2584\033[0m"; - } else if (!top && bottom) { - oss << "\033[40;97m\u2580\033[0m"; + oss << " "; + } else if (top != 0) { + oss << "\u2584"; + } else if (bottom != 0) { + oss << "\u2580"; } else { - oss << "\033[40;97m\u2588\033[0m"; + oss << "\u2588"; } } oss << std::endl;