source: trunk/gsdl/src/recpt/authenaction.cpp@ 14014

Last change on this file since 14014 was 14014, checked in by qq6, 17 years ago

close the user and key database after verification

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
RevLine 
[363]1/**********************************************************************
2 *
3 * authenaction.cpp -- authenticating users
4 * Copyright (C) 1999 DigiLib Systems Limited, New Zealand
5 *
[533]6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
[363]9 *
[533]10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
[363]24 *********************************************************************/
25
[7371]26#include "gsdl_modules_cfg.h"
27#ifdef GSDL_USE_AUTHEN_ACTION
28
[363]29#include "authenaction.h"
30#include "fileutil.h"
31#include "cfgread.h"
32#include "cgiutils.h"
[369]33#include "infodbclass.h"
34#include "gsdltimes.h"
[374]35#include "userdb.h"
[363]36
37
38///////////////
39// authenaction
40///////////////
41
42authenaction::authenaction () {
[1402]43 keydecay = 1800; // 30 minutes
[369]44 recpt = NULL;
45
[363]46 // this action uses cgi variable "a"
47 cgiarginfo arg_ainfo;
48 arg_ainfo.shortname = "a";
49 arg_ainfo.longname = "action";
50 arg_ainfo.multiplechar = true;
51 arg_ainfo.defaultstatus = cgiarginfo::weak;
52 arg_ainfo.argdefault = "a";
53 arg_ainfo.savedarginfo = cgiarginfo::must;
54 argsinfo.addarginfo (NULL, arg_ainfo);
55
56 // "us"
57 arg_ainfo.shortname = "us";
58 arg_ainfo.longname = "user account status";
59 arg_ainfo.multiplechar = true;
60 arg_ainfo.defaultstatus = cgiarginfo::weak;
61 arg_ainfo.argdefault = "invalid";
62 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
63 argsinfo.addarginfo (NULL, arg_ainfo);
64
65 // "ug"
66 arg_ainfo.shortname = "ug";
67 arg_ainfo.longname = "user groups"; // comma seperated list
68 arg_ainfo.multiplechar = true;
69 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]70 arg_ainfo.argdefault = g_EmptyText;
[363]71 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
72 argsinfo.addarginfo (NULL, arg_ainfo);
73
74 // "un"
75 arg_ainfo.shortname = "un";
76 arg_ainfo.longname = "user name";
77 arg_ainfo.multiplechar = true;
78 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]79 arg_ainfo.argdefault = g_EmptyText;
[363]80 arg_ainfo.savedarginfo = cgiarginfo::must;
81 argsinfo.addarginfo (NULL, arg_ainfo);
82
83 // "pw"
84 arg_ainfo.shortname = "pw";
85 arg_ainfo.longname = "password";
86 arg_ainfo.multiplechar = true;
87 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]88 arg_ainfo.argdefault = g_EmptyText;
[363]89 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
90 argsinfo.addarginfo (NULL, arg_ainfo);
91
92 // "ky" - gives a specific user authentication for a
93 // limited amount of time
94 arg_ainfo.shortname = "ky";
95 arg_ainfo.longname = "user time key";
96 arg_ainfo.multiplechar = true;
97 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]98 arg_ainfo.argdefault = g_EmptyText;
[363]99 arg_ainfo.savedarginfo = cgiarginfo::must;
100 argsinfo.addarginfo (NULL, arg_ainfo);
101
102 // "ua" - ""=no, "1"=yes
103 arg_ainfo.shortname = "ua";
104 arg_ainfo.longname = "whether a user has been authenticated";
105 arg_ainfo.multiplechar = true;
106 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]107 arg_ainfo.argdefault = g_EmptyText;
[363]108 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
109 argsinfo.addarginfo (NULL, arg_ainfo);
110
111 // "er" - compressed arguments for the referer page
112 arg_ainfo.shortname = "er";
113 arg_ainfo.longname = "the compressed args of the refer page";
114 arg_ainfo.multiplechar = true;
115 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]116 arg_ainfo.argdefault = g_EmptyText;
[363]117 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
118 argsinfo.addarginfo (NULL, arg_ainfo);
119
120 // "uan" - whether user authentication is needed
121 arg_ainfo.shortname = "uan";
122 arg_ainfo.longname = "whether user authentication is needed";
123 arg_ainfo.multiplechar = true;
124 arg_ainfo.defaultstatus = cgiarginfo::weak;
[7425]125 arg_ainfo.argdefault = g_EmptyText;
[363]126 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
127 argsinfo.addarginfo (NULL, arg_ainfo);
128}
129
130void authenaction::configure (const text_t &key, const text_tarray &cfgline) {
131 // get the password filename
132 if (cfgline.size() == 1) {
[374]133 if (key == "usersfile") usersfile = cfgline[0];
[369]134 else if (key == "keyfile") keyfile = cfgline[0];
135 else if (key == "keydecay") keydecay = cfgline[0].getint();
[363]136 }
137
138 action::configure (key, cfgline);
139}
140
141bool authenaction::init (ostream &logout) {
[2212]142
143 if (gdbmhome.empty()) {
144 logout << "ERROR (authenaction::init) gdbmhome is not set\n";
145 return false;
146 }
147
148 if (usersfile.empty()) usersfile = filename_cat (gdbmhome, "etc", "users.db");
149 if (keyfile.empty()) keyfile = filename_cat (gdbmhome, "etc", "key.db");
150
[363]151 return action::init (logout);
152}
153
154bool authenaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/,
[3546]155 recptprotolistclass * /*protos*/, ostream &/*logout*/) {
[363]156 return true;
157}
158
159// returns false if there is a major problem with the cgi arguments -- not
160// if authentication fails. If the authentication fails "un" will be empty
161bool authenaction::check_external_cgiargs (cgiargsinfoclass &argsinfo,
162 cgiargsclass &args,
163 outconvertclass &outconvert,
[7432]164 const text_t &saveconf,
[363]165 ostream &logout) {
[1505]166
167 // no need to go further unless authentication is
168 // required by this page
169 if (args["uan"].empty()) return true;
170
[13844]171 userdbclass *user_database = new userdbclass(usersfile);
172 keydbclass *key_database = new keydbclass(keyfile);
[1505]173
[363]174 // failure means we have to redirect to this action to get authentication
175 // (if we are not already doing this)
176
177 userinfo_t thisuser;
178
[374]179 text_t &args_uan = args["uan"]; text_t &args_un = args["un"];
180 text_t &args_pw = args["pw"]; text_t &args_us = args["us"];
181 text_t &args_ug = args["ug"]; text_t &args_ky = args["ky"];
[507]182 text_t &args_ua = args["ua"]; text_t &args_a = args["a"];
[374]183
184 // we must have a username and a password or a key to
185 // do any authentication
[363]186 args_ua.clear(); // default = false;
187 if (args_un.empty() || args_pw.empty()) args_us = "invalid";
188 else args_us = "failed";
189
190 // make sure we have a username
[13844]191 if (!args_un.empty() && (user_database->get_user_info (args_un, thisuser) == ERRNO_SUCCEED)) {
[363]192 if (!args_pw.empty()) {
193 // we are authenticating using a password
[13844]194 if (user_database->check_passwd (thisuser.username, args_pw) == ERRNO_SUCCEED) args_ua = "1"; // succeeded
[363]195
196 } else if (!args_ky.empty()) {
197 // we are authenticating using a key
[13844]198 if (key_database->check_key(thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
[369]199 else args_us = "stalekey";
[363]200 }
201 }
202
203 args_pw.clear(); // password goes no further
204 if (!args_ua.empty()) {
[374]205 if (thisuser.enabled) {
206 bool haspermission = true;
[4974]207
[369]208 // check to make sure the user is in the required group
[4974]209 // one group is available only at the moment.
210 // this is what we are changing !
211
[369]212 if (!args_ug.empty()) {
[4974]213
214 // Since we recieve a comma seperated list
215 // of groups like mygroup,yourgroup,ourgroup
216 // we want to split them into individual groups
217 // and examine them. This is what is done here.
218
219 text_tset splitgrps;
220 text_t::const_iterator split_here = args_ug.begin();
221 text_t::const_iterator split_end = args_ug.end();
222
223 splitchar(split_here,split_end,',',splitgrps);
224
225 haspermission = false;
226
227 // This examines the current user to be authenticated and
228 // tries to see if he or she is in the group that we have in
229 // thisuser structure. We compare args_ua contents with that
230 // of the user database.
231
232 text_t::const_iterator group_here = thisuser.groups.begin();
233 text_t::const_iterator group_end = thisuser.groups.end();
234 text_t thisgroup;
[369]235 while (group_here != group_end) {
[4974]236 group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
237 if (splitgrps.find(thisgroup) != splitgrps.end() )
238 {
239 haspermission = true;
240 break;
241 }
[369]242 }
243 }
[4974]244
[374]245 if (haspermission) {
[4974]246 // succeeded, get info about this user
247 // note: we don't need to set "ug" as it is already set to what it needs to be
248 args_us = "enabled";
[13844]249 args_ky = key_database->generate_key(args_un); // new key
[4974]250
[374]251 // delete old keys around every 50 accesses
[13844]252 if (rand()%50 == 1) key_database->remove_old_keys(keydecay);
[369]253
254 } else {
255 // succeeded, however, the user is not in the correct group
[4974]256 args_ua.clear();
257 args_us = "permissiondenied";
258 args_ky.clear();
[369]259 }
[4974]260
[363]261 } else {
[4974]262 // succeeded, however, the account is disabled
[363]263 args_ua.clear();
264 args_us = "disabled";
265 args_ky.clear();
266 }
267
268 } else {
269 // failure, reset info about the user
270 args_ky.clear();
271 }
272
273 // we will have to redirect the user if authentication is needed,
274 // it failed, and we weren't on our way to be authenticated anyway
[507]275 if ((!args_uan.empty()) && (args_ua.empty()) && (args_a != "a")) {
[363]276 // need to save the current arguments in "er"
277 text_t &arg_er = args["er"];
278 if (!compress_save_args(argsinfo, saveconf, args, arg_er, outconvert, logout))
279 arg_er.clear();
280
[1432]281 // needs to be decoded for use within forms
282 decode_cgi_arg (arg_er);
283
[363]284 // redirect to this action
[507]285 args_a = "a";
[363]286 }
[14014]287
288 //close the database
289 user_database->closedatabase();
290 key_database->closedatabase();
[363]291 return true;
292}
293
[755]294void authenaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
295 response_t &response, text_t &response_data,
296 ostream &/*logout*/) {
[363]297 response = content;
298 response_data = "text/html";
299}
300
[755]301void authenaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
302 recptprotolistclass * /*protos*/, ostream &/*logout*/) {
[363]303 // sets _authen:messageextra_ based on the value of args["us"]
[369]304 // _authen:hiddenargs_ to contain all the arguments that were
305 // explicitly set
[363]306 disp.setmacro ("messagestatus", "authen", ("_authen:message" + args["us"]
[369]307 + "_"));
[722]308 // change style of header and footer if page is a frame
[1796]309 if ((args["p"].empty()) || (args["p"] == "frameset")) {
[722]310 disp.setmacro ("header", "authen", "_status:infoheader_(Log in)");
311 disp.setmacro ("header", "authenok", "_status:infoheader_(Log in)");
312 disp.setmacro ("footer", "authen", "_status:infofooter_(Log in)");
313 disp.setmacro ("footer", "authenok", "_status:infofooter_(Log in)");
314 }
[369]315
316 // get a list of saved configuration arguments (if possible)
[7432]317 text_t saveconf;
[369]318 text_tset saveconfset;
319 if (recpt != NULL) {
[7432]320 saveconf = recpt->get_configinfo().saveconf;
321 splitchar (saveconf.begin(), saveconf.end(), '-', saveconfset);
[369]322 }
323
324 text_t hiddenargs;
325 cgiargsclass::const_iterator args_here = args.begin();
326 cgiargsclass::const_iterator args_end = args.end();
327 while (args_here != args_end) {
328 // set this as a hidden argument if it came from the cgi arguments,
329 // its not the compressed arguments, the query string, a user name or
[3423]330 // password, or collect.cfg, and if it is not in the compressed arguments
[369]331 if ((*args_here).second.source == cgiarg_t::cgi_arg &&
332 (*args_here).first != "e" && (*args_here).first != "q" &&
333 (*args_here).first != "un" && (*args_here).first != "pw" &&
[3423]334 (*args_here).first != "cfgfile" &&
[369]335 saveconfset.find((*args_here).first) == saveconfset.end()) {
336 hiddenargs += "<input type=hidden name=\"" + (*args_here).first +
337 "\" value=\"_cgiarg" + (*args_here).first + "_\">\n";
338 }
[9620]339 ++args_here;
[369]340 }
341
342 disp.setmacro ("hiddenargs", "authen", hiddenargs);
[363]343}
344
[755]345bool authenaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
346 browsermapclass * /*browsers*/, displayclass &disp,
[421]347 outconvertclass &outconvert, ostream &textout,
348 ostream &/*logout*/) {
[363]349 if (args["us"] == "enabled") {
350 // have been authenticated
351 textout << outconvert << disp
352 << "_authenok:header_\n_authenok:content_\n_authenok:footer_\n";
353 return true;
354 }
[755]355
[363]356 // need to be authenticated
357 textout << outconvert << disp
358 << "_authen:header_\n_authen:content_\n_authen:footer_\n";
359
360 return true;
361}
[7371]362
363#endif //GSDL_USE_AUTHEN_ACTION
Note: See TracBrowser for help on using the repository browser.