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

Last change on this file since 22984 was 22984, checked in by ak19, 14 years ago
  1. Undoing commit of 22934 where decode_commas was called on stem and fold comma separated list: previously separated due to url-encoding of commas. Now that the problem has been fixed at the source, the decode_commas hack is no longer necessary. 2. Commas in stem and fold are no longer url-encoded because the multiple_value field of the continuously-reused struct arg_ainfo is always set back to the default false after ever being set to true. So it no longer subtly stays at true to affect Greenstone functioning in unforeseen ways (such as suddenly and unnecessarily URL-encoding commas where this is not wanted).
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1/**********************************************************************
2 *
3 * authenaction.cpp -- authenticating users
4 * Copyright (C) 1999 DigiLib Systems Limited, New Zealand
5 *
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.
9 *
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 *
24 *********************************************************************/
25
26#include "gsdl_modules_cfg.h"
27#ifdef GSDL_USE_AUTHEN_ACTION
28
29#include "authenaction.h"
30#include "fileutil.h"
31#include "cfgread.h"
32#include "cgiutils.h"
33#include "gsdltimes.h"
34
35
36///////////////
37// authenaction
38///////////////
39
40authenaction::authenaction () {
41 keydecay = 1800; // 30 minutes
42 recpt = NULL;
43
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;
49 arg_ainfo.multiplevalue = false;
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;
59 arg_ainfo.multiplevalue = false;
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.multiplevalue = false;
70 arg_ainfo.defaultstatus = cgiarginfo::weak;
71 arg_ainfo.argdefault = g_EmptyText;
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;
79 arg_ainfo.multiplevalue = false;
80 arg_ainfo.defaultstatus = cgiarginfo::weak;
81 arg_ainfo.argdefault = g_EmptyText;
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;
89 arg_ainfo.multiplevalue = false;
90 arg_ainfo.defaultstatus = cgiarginfo::weak;
91 arg_ainfo.argdefault = g_EmptyText;
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;
100 arg_ainfo.multiplevalue = false;
101 arg_ainfo.defaultstatus = cgiarginfo::weak;
102 arg_ainfo.argdefault = g_EmptyText;
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;
110 arg_ainfo.multiplevalue = false;
111 arg_ainfo.defaultstatus = cgiarginfo::weak;
112 arg_ainfo.argdefault = g_EmptyText;
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;
120 arg_ainfo.multiplevalue = false;
121 arg_ainfo.defaultstatus = cgiarginfo::weak;
122 arg_ainfo.argdefault = g_EmptyText;
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;
130 arg_ainfo.multiplevalue = false;
131 arg_ainfo.defaultstatus = cgiarginfo::weak;
132 arg_ainfo.argdefault = g_EmptyText;
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) {
142 if (dbhome.empty()) {
143 logout << "ERROR (authenaction::init) dbhome is not set\n";
144 return false;
145 }
146
147 return action::init (logout);
148}
149
150bool authenaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/,
151 recptprotolistclass * /*protos*/, ostream &/*logout*/) {
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,
160 const text_t &saveconf,
161 ostream &logout) {
162
163 // no need to go further unless authentication is
164 // required by this page
165 if (args["uan"].empty()) {
166 return true;
167 }
168
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
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"];
177 text_t &args_ua = args["ua"]; text_t &args_a = args["a"];
178
179 // we must have a username and a password or a key to
180 // do any authentication
181 args_ua.clear(); // default = false;
182 if (args_un.empty() || args_pw.empty()) {
183 args_us = "invalid";
184 }
185 else {
186 args_us = "failed";
187 }
188
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)) {
192 if (!args_pw.empty()) {
193 // we are authenticating using a password
194 if (user_database->check_passwd (thisuser.username, args_pw) == ERRNO_SUCCEED) {
195 args_ua = "1"; // succeeded
196 }
197
198 } else if (!args_ky.empty()) {
199 // we are authenticating using a key
200 if (key_database->check_key(thisuser, args_ky, args_ug, keydecay)) {
201 args_ua = "1";
202 }
203 else {
204 args_us = "stalekey";
205 }
206 }
207 }
208
209 args_pw.clear(); // password goes no further
210 if (!args_ua.empty()) {
211 if (thisuser.enabled) {
212 bool haspermission = true;
213
214 // check to make sure the user is in the required group
215 // one group is available only at the moment.
216 // this is what we are changing !
217
218 if (!args_ug.empty()) {
219
220 // Since we receive a comma separated list
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;
241 while (group_here != group_end) {
242 group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
243 if (splitgrps.find(thisgroup) != splitgrps.end() )
244 {
245 haspermission = true;
246 break;
247 }
248 }
249 }
250
251 if (haspermission) {
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";
255 args_ky = key_database->generate_key(args_un); // new key
256
257 // delete old keys around every 50 accesses
258 if (rand()%50 == 1) key_database->remove_old_keys(keydecay);
259
260 } else {
261 // succeeded, however, the user is not in the correct group
262 args_ua.clear();
263 args_us = "permissiondenied";
264 args_ky.clear();
265 }
266
267 } else {
268 // succeeded, however, the account is disabled
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
281 if ((!args_uan.empty()) && (args_ua.empty()) && (args_a != "a")) {
282 // need to save the current arguments in "er"
283 text_t &arg_er = args["er"];
284 if (!compress_save_args(argsinfo, saveconf, args, arg_er, outconvert, logout)) {
285 arg_er.clear();
286 }
287
288 // needs to be decoded for use within forms
289 decode_cgi_arg (arg_er);
290
291 // redirect to this action
292 args_a = "a";
293 }
294
295 return true;
296}
297
298void authenaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
299 response_t &response, text_t &response_data,
300 ostream &/*logout*/) {
301 response = content;
302 response_data = "text/html";
303}
304
305void authenaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
306 recptprotolistclass * /*protos*/, ostream &/*logout*/) {
307 // sets _authen:messageextra_ based on the value of args["us"]
308 // _authen:hiddenargs_ to contain all the arguments that were
309 // explicitly set
310 disp.setmacro ("messagestatus", "authen", ("_authen:message" + args["us"]
311 + "_"));
312 // change style of header and footer if page is a frame
313 if ((args["p"].empty()) || (args["p"] == "frameset")) {
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 }
319
320 // get a list of saved configuration arguments (if possible)
321 text_t saveconf;
322 text_tset saveconfset;
323 if (recpt != NULL) {
324 saveconf = recpt->get_configinfo().saveconf;
325 splitchar (saveconf.begin(), saveconf.end(), '-', saveconfset);
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
334 // password, or collect.cfg, and if it is not in the compressed arguments
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" &&
338 (*args_here).first != "cfgfile" &&
339 saveconfset.find((*args_here).first) == saveconfset.end()) {
340 hiddenargs += "<input type=hidden name=\"" + (*args_here).first +
341 "\" value=\"_cgiarg" + (*args_here).first + "_\">\n";
342 }
343 ++args_here;
344 }
345
346 disp.setmacro ("hiddenargs", "authen", hiddenargs);
347}
348
349bool authenaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
350 browsermapclass * /*browsers*/, displayclass &disp,
351 outconvertclass &outconvert, ostream &textout,
352 ostream &/*logout*/) {
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 }
359
360 // need to be authenticated
361 textout << outconvert << disp
362 << "_authen:header_\n_authen:content_\n_authen:footer_\n";
363
364 return true;
365}
366
367#endif //GSDL_USE_AUTHEN_ACTION
Note: See TracBrowser for help on using the repository browser.