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

Last change on this file since 2212 was 2212, checked in by sjboddie, 23 years ago

Fixed a bug that was causing the local library server to attempt to write
files to gsdlhome (i.e. the cd-rom drive if served from a cd) under certain
circumstances.

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