30
31:- module(user_db,
32 [ set_user_database/1, 33
34 user_add/2, 35 user_del/1, 36 set_user_property/2, 37
38 openid_add_server/2, 39 openid_del_server/1, 40 openid_set_property/2, 41 openid_current_server/1, 42 openid_server_property/2, 43 openid_server_properties/2, 44
45 user_property/2, 46 check_permission/2, 47 validate_password/2, 48 password_hash/2, 49
50 login/1, 51 login/2, 52 logout/1, 53 current_user/1, 54 logged_on/1, 55 logged_on/2, 56 ensure_logged_on/1, 57 authorized/1, 58
59 deny_all_users/1 60 ]). 61:- use_module(library(http/http_session)). 62:- use_module(library(http/http_wrapper)). 63:- use_module(library(http/http_openid)). 64:- use_module(library(http/http_authenticate)). 65:- use_module(library(lists)). 66:- use_module(library(broadcast)). 67:- use_module(library(error)). 68:- use_module(library(uri)). 69:- use_module(library(debug)). 70:- use_module(library(persistency)). 71:- use_module(openid). 72
85
86:- dynamic
87 logged_in/4, 88 user/2, 89 denied/1. 90
91
92 95
96:- persistent
97 user(_Name, _UserOptions),
98 grant_openid_server(_Server, _ServerOptions). 99
103
104set_user_database(File) :-
105 db_attach(File, [sync(close)]).
106
110
111user_add(Name, Options) :-
112 must_be(atom, Name),
113 assert_user(Name, Options).
114
118
119user_del(Name) :-
120 must_be(atom, Name),
121 ( user(Name, _)
122 -> retractall_user(Name, _)
123 ; existence_error(user, Name)
124 ).
125
129
130set_user_property(Name, Prop) :-
131 must_be(atom, Name),
132 ( user(Name, OldProps)
133 -> ( memberchk(Prop, OldProps)
134 -> true
135 ; functor(Prop, PropName, Arity),
136 functor(Unbound, PropName, Arity),
137 delete(OldProps, Unbound, NewProps),
138 retractall_user(Name, _),
139 assert_user(Name, [Prop|NewProps])
140 )
141 ; existence_error(user, Name)
142 ).
143
144
148
149openid_add_server(Server, _Options) :-
150 openid_current_server(Server), !,
151 throw(error(permission_error(create, openid_server, Server),
152 context(_, 'Already present'))).
153openid_add_server(Server, Options) :-
154 assert_grant_openid_server(Server, Options).
155
156
160
161openid_del_server(Server) :-
162 retractall_grant_openid_server(Server, _).
163
164
168
169openid_set_property(Server, Prop) :-
170 must_be(atom, Server),
171 ( grant_openid_server(Server, OldProps)
172 -> ( memberchk(Prop, OldProps)
173 -> true
174 ; functor(Prop, PropName, Arity),
175 functor(Unbound, PropName, Arity),
176 delete(OldProps, Unbound, NewProps),
177 retractall_grant_openid_server(Server, _),
178 assert_grant_openid_server(Server, [Prop|NewProps])
179 )
180 ; existence_error(openid_server, Server)
181 ).
182
183
186
187openid_current_server(Server) :-
188 grant_openid_server(Server, _).
189
195
196:- dynamic
197 registered_server/2. 198
199openid_server_properties(Server, Properties) :-
200 ( registered_server(Server, Registered)
201 -> grant_openid_server(Registered, Properties)
202 ; grant_openid_server(Server, Properties)
203 -> true
204 ; grant_openid_server(Registered, Properties),
205 match_server(Server, Registered)
206 -> assert(registered_server(Server, Registered))
207 ; grant_openid_server(*, Properties)
208 ).
209
213
214match_server(Server, Registered) :-
215 uri_host(Server, SHost),
216 uri_host(Registered, RHost),
217 atomic_list_concat(SL, '.', SHost),
218 atomic_list_concat(RL, '.', RHost),
219 append(_, RL, SL), !.
220
221uri_host(URI, Host) :-
222 uri_components(URI, CL),
223 uri_data(authority, CL, Authority),
224 uri_authority_components(Authority, AC),
225 uri_authority_data(host, AC, Host).
226
233
234openid_server_property(Server, Property) :-
235 openid_server_properties(Server, Properties),
236 ( var(Property)
237 -> member(Property, Properties)
238 ; memberchk(Property, Properties)
239 ).
240
241
242 245
249
250current_user(User) :-
251 user(User, _).
252
268
269user_property(User, Property) :-
270 nonvar(User), nonvar(Property), !,
271 uprop(Property, User), !.
272user_property(User, Property) :-
273 uprop(Property, User).
274
275uprop(session(SessionID), User) :-
276 ( nonvar(SessionID) 277 -> !
278 ; true
279 ),
280 logged_in(SessionID, User, _, _).
281uprop(connection(LoginTime, Idle), User) :-
282 logged_in(SessionID, User, LoginTime, _),
283 http_current_session(SessionID, idle(Idle)).
284uprop(url(URL), User) :-
285 ( http_in_session(SessionID),
286 logged_in(SessionID, User, _LoginTime, Options)
287 -> true
288 ; Options = []
289 ),
290 user_url(User, URL, Options).
291uprop(Prop, User) :-
292 nonvar(User), !,
293 ( user(User, Properties)
294 -> true
295 ; openid_server(User, OpenID, Server),
296 openid_server_properties(Server, ServerProperties)
297 -> Properties = [ type(openid),
298 openid(OpenID),
299 openid_server(Server)
300 | ServerProperties
301 ]
302 ),
303 ( nonvar(Prop)
304 -> memberchk(Prop, Properties)
305 ; member(Prop, Properties)
306 ).
307uprop(Prop, User) :-
308 user(User, Properties),
309 member(Prop, Properties).
310
311
312user_url(User, URL, _) :-
313 uri_is_global(User), !,
314 URL = User.
315user_url(User, URL, Options) :-
316 openid_for_local_user(User, URL, Options).
317
318
319 322
326
327validate_password(User, Password) :-
328 user(User, Options),
329 memberchk(password(Hash), Options),
330 password_hash(Password, Hash).
331
332
337
338password_hash(Password, Hash) :-
339 var(Hash), !,
340 phrase("$1$", HashString, _),
341 crypt(Password, HashString),
342 atom_codes(Hash, HashString).
343password_hash(Password, Hash) :-
344 crypt(Password, Hash).
345
346
347 350
354
355logged_on(User) :-
356 http_in_session(SessionID),
357 user_property(User, session(SessionID)), !.
358logged_on(User) :-
359 http_current_request(Request),
360 memberchk(authorization(Text), Request),
361 http_authorization_data(Text, basic(User, Password)),
362 validate_password(User, Password), !.
363
364
369
370logged_on(User, Default) :-
371 ( logged_on(User0)
372 -> User = User0
373 ; User = Default
374 ).
375
376
381
382ensure_logged_on(User) :-
383 http_current_request(Request),
384 openid_user(Request, User, []).
385
386
393
394authorized(Action) :-
395 catch(check_permission(anonymous, Action), _, fail), !.
396authorized(Action) :-
397 ensure_logged_on(User),
398 check_permission(User, Action).
399
400
406
407check_permission(User, Operation) :-
408 \+ denied(User, Operation),
409 user_property(User, allow(Operations)),
410 memberchk(Operation, Operations), !.
411check_permission(_, _) :-
412 http_current_request(Request),
413 memberchk(path(Path), Request),
414 permission_error(http_location, access, Path).
415
421
422denied(admin, _) :- !, fail.
423denied(_, Operation) :-
424 denied(Operation).
425
426
430
431deny_all_users(Term) :-
432 ( denied(X),
433 X =@= Term
434 -> true
435 ; assert(denied(Term))
436 ).
437
438
443
444login(User) :-
445 login(User, []).
446login(User, Options) :-
447 must_be(atom, User),
448 get_time(Time),
449 open_session(Session),
450 retractall(logged_in(Session, _, _, _)),
451 asserta(logged_in(Session, User, Time, Options)),
452 broadcast(cliopatria(login(User, Session))),
453 debug(login, 'Login user ~w on session ~w', [User, Session]).
454
455
459
460logout(User) :-
461 must_be(atom, User),
462 broadcast(cliopatria(logout(User))),
463 retractall(logged_in(_Session, User, _Time, _Options)),
464 debug(login, 'Logout user ~w', [User]).
465
467
468:- listen(http_session(end(Session, _Peer)),
469 ( atom(Session),
470 retractall(logged_in(Session, _User, _Time, _Options))
471 )). 472
474
475:- http_set_session_options([ create(noauto)
476 ]). 477open_session(Session) :-
478 http_open_session(Session, [])