Merge lp:~ansharyan015/drizzle/auth_file_dynamic into lp:drizzle

Proposed by Daniel Nichter
Status: Merged
Merged at revision: 2565
Proposed branch: lp:~ansharyan015/drizzle/auth_file_dynamic
Merge into: lp:drizzle
Diff against target: 364 lines (+194/-53)
7 files modified
plugin/auth_file/auth_file.cc (+132/-50)
plugin/auth_file/docs/index.rst (+14/-3)
plugin/auth_file/tests/r/dynamic_plugin.result (+10/-0)
plugin/auth_file/tests/t/dynamic.users1 (+3/-0)
plugin/auth_file/tests/t/dynamic.users2 (+3/-0)
plugin/auth_file/tests/t/dynamic_plugin-master.opt (+1/-0)
plugin/auth_file/tests/t/dynamic_plugin.test (+31/-0)
To merge this branch: bzr merge lp:~ansharyan015/drizzle/auth_file_dynamic
Reviewer Review Type Date Requested Status
Daniel Nichter (community) code review Approve
Review via email: mp+108864@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

Overall the changes look godo. There are minor code style changes for later perhaps, like in

bool AuthFile::setUsersFile(std::string& usersFile)

the arg should probably be called "users_file" instead. Similarly, the use of "*_dummy" vars are more clear when named "new_*" (e.g. new_users_file), as was done in regex_policy.

review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugin/auth_file/auth_file.cc'
--- plugin/auth_file/auth_file.cc 2012-01-15 20:54:59 +0000
+++ plugin/auth_file/auth_file.cc 2012-06-06 03:05:26 +0000
@@ -27,6 +27,7 @@
27#include <boost/program_options.hpp>27#include <boost/program_options.hpp>
28#include <boost/filesystem.hpp>28#include <boost/filesystem.hpp>
2929
30#include <drizzled/item.h>
30#include <drizzled/configmake.h>31#include <drizzled/configmake.h>
31#include <drizzled/plugin/authentication.h>32#include <drizzled/plugin/authentication.h>
32#include <drizzled/identifier.h>33#include <drizzled/identifier.h>
@@ -43,24 +44,22 @@
43namespace auth_file {44namespace auth_file {
4445
45static const fs::path DEFAULT_USERS_FILE= SYSCONFDIR "/drizzle.users";46static const fs::path DEFAULT_USERS_FILE= SYSCONFDIR "/drizzle.users";
47typedef std::map<string, string> users_t;
48bool updateUsersFile(Session *, set_var *);
49bool parseUsersFile(std::string, users_t&);
4650
47class AuthFile : public plugin::Authentication51class AuthFile : public plugin::Authentication
48{52{
49public:53public:
50 AuthFile(fs::path users_file_arg);54 AuthFile(std::string users_file_arg);
5155
52 /**56 /**
53 * Retrieve the last error encountered in the class.57 * Retrieve the last error encountered in the class.
54 */58 */
55 const string& getError() const;59 const string& getError() const;
5660
57 /**61 std::string& getUsersFile();
58 * Load the users file into a map cache.62 bool setUsersFile(std::string& usersFile);
59 *
60 * @return True on success, false on error. If false is returned an error
61 * is set and can be retrieved with getError().
62 */
63 bool loadFile();
6463
65private:64private:
6665
@@ -85,18 +84,29 @@
85 const string &scrambled_password);84 const string &scrambled_password);
8685
87 string error;86 string error;
88 const fs::path users_file;87 fs::path users_file;
88 std::string sysvar_users_file;
8989
90 /**90 /**
91 * Cache or username:password entries from the file.91 * Cache or username:password entries from the file.
92 */92 */
93 typedef std::map<string, string> users_t;
94 users_t users;93 users_t users;
94 /**
95 * This method is called to update the users cache with the new
96 * username:password pairs given in new users file upon update.
97 */
98 void setUsers(users_t);
99 /**
100 * This method is called to delete all the cached username:password pairs
101 * when users file is updated.
102 */
103 void clearUsers();
95};104};
105AuthFile *auth_file= NULL;
96106
97AuthFile::AuthFile(fs::path users_file_arg) :107AuthFile::AuthFile(std::string users_file_arg) :
98 plugin::Authentication("auth_file"),108 plugin::Authentication("auth_file"),
99 users_file(users_file_arg)109 users_file(users_file_arg), sysvar_users_file(users_file_arg)
100{110{
101}111}
102112
@@ -105,41 +115,29 @@
105 return error;115 return error;
106}116}
107117
108bool AuthFile::loadFile()118std::string& AuthFile::getUsersFile()
109{119{
110 ifstream file(users_file.string().c_str());120 return sysvar_users_file;
111121}
112 if (!file.is_open())122
113 {123bool AuthFile::setUsersFile(std::string& usersFile)
114 error = "Could not open users file: " + users_file.string();124{
115 return false;125 if (usersFile.empty())
116 }126 {
117127 errmsg_printf(error::ERROR, _("users file cannot be an empty string"));
118 string line;128 return false; // error
119 while (getline(file, line))129 }
120 {130 users_t users_dummy;
121 /* Ignore blank lines and lines starting with '#'. */131 if(parseUsersFile(usersFile, users_dummy))
122 if (line.empty() || line[line.find_first_not_of(" \t")] == '#')132 {
123 continue;133 this->clearUsers();
124134 this->setUsers(users_dummy);
125 string username;135 sysvar_users_file= usersFile;
126 string password;136 fs::path newUsersFile(getUsersFile());
127 size_t password_offset = line.find(":");137 users_file= newUsersFile;
128 if (password_offset == string::npos)138 return true; //success
129 username = line;139 }
130 else140 return false; // error
131 {
132 username = string(line, 0, password_offset);
133 password = string(line, password_offset + 1);
134 }
135
136 if (not users.insert(pair<string, string>(username, password)).second)
137 {
138 error = "Duplicate entry found in users file: " + username;
139 return false;
140 }
141 }
142 return true;
143}141}
144142
145bool AuthFile::verifyMySQLHash(const string &password,143bool AuthFile::verifyMySQLHash(const string &password,
@@ -195,12 +193,96 @@
195 : password == *user;193 : password == *user;
196}194}
197195
196void AuthFile::setUsers(users_t users_dummy)
197{
198 users.insert(users_dummy.begin(), users_dummy.end());
199}
200
201void AuthFile::clearUsers()
202{
203 users.clear();
204}
205
206/**
207 * This function is called when the value of users file is changed in the system.
208 *
209 * @return False on success, True on error.
210 */
211bool updateUsersFile(Session *, set_var* var)
212{
213 if (not var->value->str_value.empty())
214 {
215 std::string newUsersFile(var->value->str_value.data());
216 if (auth_file->setUsersFile(newUsersFile))
217 return false; //success
218 else
219 return true; // error
220 }
221 errmsg_printf(error::ERROR, _("auth_file file cannot be NULL"));
222 return true; // error
223}
224
225/**
226 * Parse the users file into a map cache.
227 *
228 * @return True on success, false on error. If an error is encountered, false is
229 * returned with error message printed.
230 */
231bool parseUsersFile(std::string new_users_file, users_t& users_dummy)
232{
233 ifstream file(new_users_file.c_str());
234
235 if (!file.is_open())
236 {
237 string error_msg= "Could not open users file: " + new_users_file;
238 errmsg_printf(error::ERROR, _(error_msg.c_str()));
239 return false;
240 }
241
242 string line;
243 try
244 {
245 while (getline(file, line))
246 {
247 /* Ignore blank lines and lines starting with '#'. */
248 if (line.empty() || line[line.find_first_not_of(" \t")] == '#')
249 continue;
250
251 string username;
252 string password;
253 size_t password_offset = line.find(":");
254 if (password_offset == string::npos)
255 username = line;
256 else
257 {
258 username = string(line, 0, password_offset);
259 password = string(line, password_offset + 1);
260 }
261
262 if (not users_dummy.insert(pair<string, string>(username, password)).second)
263 {
264 string error_msg= "Duplicate entry found in users file: " + username;
265 errmsg_printf(error::ERROR, _(error_msg.c_str()));
266 return false;
267 }
268 }
269 return true;
270 }
271 catch (const std::exception &e)
272 {
273 /* On any non-EOF break, unparseable line */
274 string error_msg= "Unable to parse users file " + new_users_file + ":" + e.what();
275 errmsg_printf(error::ERROR, _(error_msg.c_str()));
276 return false;
277 }
278}
279
198static int init(module::Context &context)280static int init(module::Context &context)
199{281{
200 const module::option_map &vm= context.getOptions();282 const module::option_map &vm= context.getOptions();
201283
202 AuthFile *auth_file = new AuthFile(fs::path(vm["users"].as<string>()));284 auth_file= new AuthFile(vm["users"].as<string>());
203 if (not auth_file->loadFile())285 if (!auth_file->setUsersFile(auth_file->getUsersFile()))
204 {286 {
205 errmsg_printf(error::ERROR, _("Could not load auth file: %s\n"), auth_file->getError().c_str());287 errmsg_printf(error::ERROR, _("Could not load auth file: %s\n"), auth_file->getError().c_str());
206 delete auth_file;288 delete auth_file;
@@ -208,7 +290,7 @@
208 }290 }
209291
210 context.add(auth_file);292 context.add(auth_file);
211 context.registerVariable(new sys_var_const_string_val("users", vm["users"].as<string>()));293 context.registerVariable(new sys_var_std_string("users", auth_file->getUsersFile(), NULL, &updateUsersFile));
212294
213 return 0;295 return 0;
214}296}
215297
=== modified file 'plugin/auth_file/docs/index.rst'
--- plugin/auth_file/docs/index.rst 2011-11-06 00:00:03 +0000
+++ plugin/auth_file/docs/index.rst 2012-06-06 03:05:26 +0000
@@ -7,8 +7,8 @@
77
8 :program:`auth_file` is a security risk! Do not use this plugin with production servers!8 :program:`auth_file` is a security risk! Do not use this plugin with production servers!
99
10:program:`auth_file` is an authentication plugin that authenticates connections10:program:`auth_file` is an :doc:`/administration/authorization` plugin that authenticates connections
11using a list of ``username:password`` entries in a plain text file.11using a list of ``username:password`` entries in a plain text file. When :program:`drizzled` is started with ``--plugin-add=auth_file``, the file based authorization plugin is enabled with the default users file. Users file can be specified by either specifying ``--auth-file.users=<users file>`` at the time of server startup or by changing the ``auth_file_users`` with ``SET GLOBAL``.
1212
13.. note::13.. note::
1414
@@ -61,7 +61,7 @@
61* ``auth_file_users``61* ``auth_file_users``
6262
63 :Scope: Global63 :Scope: Global
64 :Dynamic: No64 :Dynamic: Yes
65 :Option: :option:`--auth-file.users`65 :Option: :option:`--auth-file.users`
6666
67 File to load for usernames and passwords.67 File to load for usernames and passwords.
@@ -94,6 +94,17 @@
94 Welcome to the Drizzle client.. Commands end with ; or \g.94 Welcome to the Drizzle client.. Commands end with ; or \g.
95 ...95 ...
9696
97Changing users file at runtime
98-------------------------------
99
100Users file can be reloaded by::
101
102 SET GLOBAL auth_file_users=@@auth_file_users
103
104Moreover, the users file can be changed by::
105
106 SET GLOBAL auth_file_users=/path/to/new/users/file
107
97.. _auth_file_authors:108.. _auth_file_authors:
98109
99Authors110Authors
100111
=== added file 'plugin/auth_file/tests/r/dynamic_plugin.result'
--- plugin/auth_file/tests/r/dynamic_plugin.result 1970-01-01 00:00:00 +0000
+++ plugin/auth_file/tests/r/dynamic_plugin.result 2012-06-06 03:05:26 +0000
@@ -0,0 +1,10 @@
1SET GLOBAL auth_file_users="";
2ERROR HY000: Incorrect arguments to SET
3SET GLOBAL auth_file_users="TOP_SRCDIR/plugin/auth_file/tests/t/dynamic.users3";
4ERROR HY000: Incorrect arguments to SET
5SET GLOBAL auth_file_users="TOP_SRCDIR/plugin/auth_file/tests/t/dynamic.users2";
6connect(localhost,auth_file_password,test_password1,test,MASTER_PORT,);
7ERROR 28000: Access denied for user 'auth_file_password' (using password: YES)
8SELECT 1;
91
101
011
=== added file 'plugin/auth_file/tests/t/dynamic.users1'
--- plugin/auth_file/tests/t/dynamic.users1 1970-01-01 00:00:00 +0000
+++ plugin/auth_file/tests/t/dynamic.users1 2012-06-06 03:05:26 +0000
@@ -0,0 +1,3 @@
1# Always allow root user with no password for drizzletest program
2root
3auth_file_password:test_password1
04
=== added file 'plugin/auth_file/tests/t/dynamic.users2'
--- plugin/auth_file/tests/t/dynamic.users2 1970-01-01 00:00:00 +0000
+++ plugin/auth_file/tests/t/dynamic.users2 2012-06-06 03:05:26 +0000
@@ -0,0 +1,3 @@
1# Always allow root user with no password for drizzletest program
2root
3auth_file_password:test_password2
04
=== added file 'plugin/auth_file/tests/t/dynamic_plugin-master.opt'
--- plugin/auth_file/tests/t/dynamic_plugin-master.opt 1970-01-01 00:00:00 +0000
+++ plugin/auth_file/tests/t/dynamic_plugin-master.opt 2012-06-06 03:05:26 +0000
@@ -0,0 +1,1 @@
1--plugin-remove=auth_all --plugin-add=auth_file --auth-file.users=$TOP_SRCDIR/plugin/auth_file/tests/t/dynamic.users1
02
=== added file 'plugin/auth_file/tests/t/dynamic_plugin.test'
--- plugin/auth_file/tests/t/dynamic_plugin.test 1970-01-01 00:00:00 +0000
+++ plugin/auth_file/tests/t/dynamic_plugin.test 2012-06-06 03:05:26 +0000
@@ -0,0 +1,31 @@
1# Making connection using the username:password pair provided in dynamic.users1 file.
2--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
3connect (connection1,localhost,auth_file_password,test_password1,,);
4connection connection1;
5
6#Test that the auth_file_users can't be replaced with an empty value
7--error ER_WRONG_ARGUMENTS
8SET GLOBAL auth_file_users="";
9
10#Test that the auth_file_users can't be replaced with a non existent file
11--replace_result $TOP_SRCDIR TOP_SRCDIR
12--error ER_WRONG_ARGUMENTS
13eval SET GLOBAL auth_file_users="$TOP_SRCDIR/plugin/auth_file/tests/t/dynamic.users3";
14
15#Test that the auth_file_users can be replaced with a different file
16--replace_result $TOP_SRCDIR TOP_SRCDIR
17eval SET GLOBAL auth_file_users="$TOP_SRCDIR/plugin/auth_file/tests/t/dynamic.users2";
18
19disconnect connection1;
20# Test that the connection to database can't be now made using the old username:password pair given in dynamic.users1 file.
21--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
22--replace_regex /@'.*?'/@'LOCALHOST'/
23--error ER_ACCESS_DENIED_ERROR
24connect (connection2,localhost,auth_file_password,test_password1,,);
25
26# Test that the connection to database can now be made using the username:password pair provided in dynamic.users2 file
27--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
28connect (connection3,localhost,auth_file_password,test_password2,,);
29connection connection3;
30SELECT 1;
31disconnect connection3;

Subscribers

People subscribed via source and target branches

to all changes: