32
33:- module(user_db,
34 [ set_user_database/1, 35
36 user_add/2, 37 user_del/1, 38 set_user_property/2, 39
40 openid_add_server/2, 41 openid_del_server/1, 42 openid_set_property/2, 43 openid_current_server/1, 44 openid_server_property/2, 45 openid_server_properties/2, 46
47 user_property/2, 48 check_permission/2, 49 validate_password/2, 50 password_hash/2, 51
52 login/1, 53 logout/1, 54 current_user/1, 55 logged_on/1, 56 logged_on/2, 57 ensure_logged_on/1, 58 authorized/1, 59
60 deny_all_users/1 61 ]).
62:- use_module(library(http/http_session)).
63:- use_module(library(http/http_wrapper)).
64:- use_module(library(http/http_openid)).
65:- use_module(library(http/http_authenticate)).
66:- use_module(library(lists)).
67:- use_module(library(broadcast)).
68:- use_module(library(error)).
69:- use_module(library(uri)).
70:- use_module(library(debug)).
71:- use_module(library(persistency)).
72:- use_module(openid).
73
86
87:- dynamic
88 logged_in/3, 89 user/2, 90 denied/1. 91
92
93 96
97:- persistent
98 user(_Name, _UserOptions),
99 grant_openid_server(_Server, _ServerOptions).
100
104
105set_user_database(File) :-
106 db_attach(File, [sync(close)]).
107
111
112user_add(Name, Options) :-
113 must_be(atom, Name),
114 assert_user(Name, Options).
115
119
120user_del(Name) :-
121 must_be(atom, Name),
122 ( user(Name, _)
123 -> retractall_user(Name, _)
124 ; existence_error(user, Name)
125 ).
126
130
131set_user_property(Name, Prop) :-
132 must_be(atom, Name),
133 ( user(Name, OldProps)
134 -> ( memberchk(Prop, OldProps)
135 -> true
136 ; functor(Prop, PropName, Arity),
137 functor(Unbound, PropName, Arity),
138 delete(OldProps, Unbound, NewProps),
139 retractall_user(Name, _),
140 assert_user(Name, [Prop|NewProps])
141 )
142 ; existence_error(user, Name)
143 ).
144
145
149
150openid_add_server(Server, _Options) :-
151 openid_current_server(Server), !,
152 throw(error(permission_error(create, openid_server, Server),
153 context(_, 'Already present'))).
154openid_add_server(Server, Options) :-
155 assert_grant_openid_server(Server, Options).
156
157
161
162openid_del_server(Server) :-
163 retractall_grant_openid_server(Server, _).
164
165
169
170openid_set_property(Server, Prop) :-
171 must_be(atom, Server),
172 ( grant_openid_server(Server, OldProps)
173 -> ( memberchk(Prop, OldProps)
174 -> true
175 ; functor(Prop, PropName, Arity),
176 functor(Unbound, PropName, Arity),
177 delete(OldProps, Unbound, NewProps),
178 retractall_grant_openid_server(Server, _),
179 assert_grant_openid_server(Server, [Prop|NewProps])
180 )
181 ; existence_error(openid_server, Server)
182 ).
183
184
187
188openid_current_server(Server) :-
189 grant_openid_server(Server, _).
190
196
197:- dynamic
198 registered_server/2.
199
200openid_server_properties(Server, Properties) :-
201 ( registered_server(Server, Registered)
202 -> grant_openid_server(Registered, Properties)
203 ; grant_openid_server(Server, Properties)
204 -> true
205 ; grant_openid_server(Registered, Properties),
206 match_server(Server, Registered)
207 -> assert(registered_server(Server, Registered))
208 ; grant_openid_server(*, Properties)
209 ).
210
214
215match_server(Server, Registered) :-
216 uri_host(Server, SHost),
217 uri_host(Registered, RHost),
218 atomic_list_concat(SL, '.', SHost),
219 atomic_list_concat(RL, '.', RHost),
220 append(_, RL, SL), !.
221
222uri_host(URI, Host) :-
223 uri_components(URI, CL),
224 uri_data(authority, CL, Authority),
225 uri_authority_components(Authority, AC),
226 uri_authority_data(host, AC, Host).
227
234
235openid_server_property(Server, Property) :-
236 openid_server_properties(Server, Properties),
237 ( var(Property)
238 -> member(Property, Properties)
239 ; memberchk(Property, Properties)
240 ).
241
242
243 246
250
251current_user(User) :-
252 user(User, _).
253
269
270user_property(User, Property) :-
271 nonvar(User), nonvar(Property), !,
272 uprop(Property, User), !.
273user_property(User, Property) :-
274 uprop(Property, User).
275
276uprop(session(SessionID), User) :-
277 ( nonvar(SessionID) % speedup
278 -> !
279 ; true
280 ),
281 logged_in(SessionID, User, _).
282uprop(connection(LoginTime, Idle), User) :-
283 logged_in(SessionID, User, LoginTime),
284 http_current_session(SessionID, idle(Idle)).
285uprop(url(URL), User) :-
286 user_url(User, URL).
287uprop(Prop, User) :-
288 nonvar(User), !,
289 ( user(User, Properties)
290 -> true
291 ; openid_server(User, OpenID, Server),
292 openid_server_properties(Server, ServerProperties)
293 -> Properties = [ type(openid),
294 openid(OpenID),
295 openid_server(Server)
296 | ServerProperties
297 ]
298 ),
299 ( nonvar(Prop)
300 -> memberchk(Prop, Properties)
301 ; member(Prop, Properties)
302 ).
303uprop(Prop, User) :-
304 user(User, Properties),
305 member(Prop, Properties).
306
307
308user_url(User, URL) :-
309 uri_is_global(User), !,
310 URL = User.
311user_url(User, URL) :-
312 openid_for_local_user(User, URL).
313
314
315 318
322
323validate_password(User, Password) :-
324 user(User, Options),
325 memberchk(password(Hash), Options),
326 password_hash(Password, Hash).
327
328
333
334password_hash(Password, Hash) :-
335 var(Hash), !,
336 phrase("$1$", HashString, _),
337 crypt(Password, HashString),
338 atom_codes(Hash, HashString).
339password_hash(Password, Hash) :-
340 crypt(Password, Hash).
341
342
343 346
350
351logged_on(User) :-
352 http_in_session(SessionID),
353 user_property(User, session(SessionID)), !.
354logged_on(User) :-
355 http_current_request(Request),
356 memberchk(authorization(Text), Request),
357 http_authorization_data(Text, basic(User, Password)),
358 validate_password(User, Password), !.
359
360
365
366logged_on(User, Default) :-
367 ( logged_on(User0)
368 -> User = User0
369 ; User = Default
370 ).
371
372
377
378ensure_logged_on(User) :-
379 http_current_request(Request),
380 openid_user(Request, User, []).
381
382
389
390authorized(Action) :-
391 catch(check_permission(anonymous, Action), _, fail), !.
392authorized(Action) :-
393 ensure_logged_on(User),
394 check_permission(User, Action).
395
396
402
403check_permission(User, Operation) :-
404 \+ denied(User, Operation),
405 user_property(User, allow(Operations)),
406 memberchk(Operation, Operations), !.
407check_permission(_, _) :-
408 http_current_request(Request),
409 memberchk(path(Path), Request),
410 permission_error(http_location, access, Path).
411
417
418denied(admin, _) :- !, fail.
419denied(_, Operation) :-
420 denied(Operation).
421
422
426
427deny_all_users(Term) :-
428 ( denied(X),
429 X =@= Term
430 -> true
431 ; assert(denied(Term))
432 ).
433
434
439
440login(User) :-
441 must_be(atom, User),
442 get_time(Time),
443 open_session(Session),
444 retractall(logged_in(Session, _, _)),
445 asserta(logged_in(Session, User, Time)),
446 broadcast(cliopatria(login(User, Session))),
447 debug(login, 'Login user ~w on session ~w', [User, Session]).
448
449
453
454logout(User) :-
455 must_be(atom, User),
456 broadcast(cliopatria(logout(User))),
457 retractall(logged_in(_Session, User, _Time)),
458 debug(login, 'Logout user ~w', [User]).
459
461
462:- listen(http_session(end(Session, _Peer)),
463 ( atom(Session),
464 retractall(logged_in(Session, _User, _Time))
465 )).
466
468
469:- http_set_session_options([ create(noauto)
470 ]).
471open_session(Session) :-
472 http_open_session(Session, []).