source: gsdl/branches/gsdl-2.74/src/recpt/authenaction.cpp@ 14270

Last change on this file since 14270 was 14270, checked in by oranfry, 17 years ago

merged selected changes to the gsdl trunk since r14217 into the 2.74 branch

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