source: main/trunk/greenstone2/runtime-src/src/recpt/authenaction.cpp@ 28899

Last change on this file since 28899 was 28899, checked in by ak19, 10 years ago

Third commit for security, for ensuring cgiargs macros are websafe. This time all the changes to the runtime action classes.

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