34
35:- module(user_profile,
36 [ profile_open_db/1, 37
38 profile_create/2, 39 current_profile/1, 40 current_profile/2, 41 profile_property/2, 42 set_profile/2, 43 set_profile/3, 44 profile_remove/2, 45 profile_remove/1, 46
47 profile_add_session/3, 48 profile_remove_session/2, 49 profile_session/2, 50 profile_refresh_session/2, 51
52 profile_canonical_value/3 53 ]). 54:- use_module(library(uuid)). 55:- use_module(library(error)). 56:- use_module(library(apply)). 57:- use_module(library(option)). 58:- use_module(library(settings)). 59:- use_module(library(uri)). 60:- use_module(library(lists)).
89:- multifile
90 attribute/3. 91
92:- setting(backend, atom, user_profile_prolog,
93 "Backend to use (name of the module"). 94:- setting(session_timeout, number, 900,
95 "Default timeout for session based logins"). 96:- setting(session_persistency, boolean, false,
97 "Default session persistency handling"). 98
99
100
110profile_open_db(Options) :-
111 setting(backend, Backend),
112 Backend:impl_profile_open_db(Options).
113
114
115
125profile_create(ProfileID, Attributes) :-
126 instantiate_profile_id(ProfileID),
127 maplist(typecheck_attribute, Attributes, CanAttributes),
128 ( current_profile(ProfileID)
129 -> permission_error(redefine, user_profile, ProfileID)
130 ; true
131 ),
132 setting(backend, Backend),
133 Backend:impl_profile_create(ProfileID, CanAttributes).
134
135instantiate_profile_id(ProfileID) :-
136 var(ProfileID), !,
137 uuid(ProfileID).
138instantiate_profile_id(ProfileID) :-
139 must_be(atom, ProfileID).
140
141typecheck_attribute(Term, Canonical) :-
142 attribute_nv(Term, Name, Value0),
143 profile_canonical_value(Name, Value0, Value),
144 Canonical =.. [Name,Value].
155profile_canonical_value(Name, Value0, Value) :-
156 ( attribute(Name, Type, _)
157 -> must_be(ground, Type),
158 ( convert_attribute_value(Type, Value0, Value)
159 -> true
160 ; Value = Value0,
161 must_be(Type, Value)
162 )
163 ; existence_error(profile_attribute, Name)
164 ).
170convert_attribute_value(Type, Text, String) :-
171 string_value(Type),
172 text(Text), !,
173 atom_string(Text, String).
174convert_attribute_value(float, Int, Float) :-
175 integer(Int),
176 Float is float(Int).
177convert_attribute_value(string, ip(A,B,C,D), String) :-
178 format(string(String), '~w.~w.~w.~w', [A,B,C,D]).
179convert_attribute_value(oneof(Values), Text, Value) :-
180 member(Value, Values),
181 string_value(Text, Value), !.
182
183string_value(string).
184string_value(url).
185string_value(url(_Scheme)).
186string_value(email).
187
188string_value(Value, Value) :- !.
189string_value(String, Value) :-
190 atom(Value),
191 atom_string(Value, String), !.
192string_value(String, Value) :-
193 number(Value),
194 number_string(String, Value1),
195 Value1 =:= Value.
196
197text(T) :- atom(T), !.
198text(T) :- string(T), !.
199
200attribute_nv(Term, _Name, _Value) :-
201 var(Term), !,
202 instantiation_error(Term).
203attribute_nv(Term, Name, Value) :-
204 compound(Term),
205 compound_name_arguments(Term, Name, [Value]), !.
206attribute_nv(Name = Value, Name, Value) :- !,
207 must_be(atom, Name).
208attribute_nv(Name - Value, Name, Value) :- !,
209 must_be(atom, Name).
210attribute_nv(Term, _Name, _Value) :-
211 type_error(name_value, Term).
212
213
214
222current_profile(ProfileID) :-
223 setting(backend, Backend),
224 Backend:impl_current_profile(ProfileID).
231current_profile(ProfileID, Attributes) :-
232 setting(backend, Backend),
233 Backend:impl_current_profile(ProfileID, Attributes0),
234 add_defaults(Attributes0, Attributes).
235
236add_defaults(Attributes0, Attributes) :-
237 findall(Name-Value, default_attribute(Name, Value), Pairs),
238 Pairs \== [], !,
239 dict_pairs(Defaults, user_profile, Pairs),
240 Attributes = Defaults.put(Attributes0).
241add_defaults(Attributes, Attributes).
242
243default_attribute(Name, Value) :-
244 attribute(Name, _Type, Options),
245 memberchk(default(Value), Options).
253profile_property(ProfileID, Property) :-
254 nonvar(ProfileID),
255 nonvar(Property), !,
256 attribute_nv(Property, Name, Value),
257 setting(backend, Backend),
258 ( VarP =.. [Name,Value0],
259 Backend:impl_profile_property(ProfileID, VarP)
260 -> Value = Value0
261 ; default_attribute(Name, Value)
262 ).
263profile_property(ProfileID, Property) :-
264 setting(backend, Backend),
265 Backend:impl_profile_property(ProfileID, Property).
266
267
268
281set_profile(ProfileID, Attribute) :-
282 set_profile(ProfileID, Attribute, _).
283
284set_profile(ProfileID, Attribute, Modified) :-
285 must_be(atom, ProfileID),
286 typecheck_attribute(Attribute, CanAttribute),
287 setting(backend, Backend),
288 Backend:impl_set_profile(ProfileID, CanAttribute, Modified).
294profile_remove(ProfileID) :-
295 must_be(atom, ProfileID),
296 setting(backend, Backend),
297 Backend:impl_profile_remove(ProfileID).
303profile_remove(ProfileID, Attribute) :-
304 must_be(atom, ProfileID),
305 must_be(atom, Attribute),
306 setting(backend, Backend),
307 Backend:impl_profile_remove(ProfileID, Attribute).
308
309
310
324profile_add_session(ProfileID, SessionID, Options) :-
325 must_be(atom, ProfileID),
326 must_be(atom, SessionID),
327 setting(session_timeout, DefTimeOut),
328 setting(session_persistency, DefPresistency),
329 option(timeout(TimeOut), Options, DefTimeOut),
330 option(persistent(Persistent), Options, DefPresistency),
331 local_add_session(ProfileID, SessionID,
332 [ timeout(TimeOut),
333 persistent(Persistent)
334 ]).
340profile_refresh_session(ProfileID, SessionID) :-
341 must_be(atom, ProfileID),
342 must_be(atom, SessionID),
343 local_refresh_session(ProfileID, SessionID).
349profile_remove_session(ProfileID, SessionID) :-
350 must_be(atom, ProfileID),
351 must_be(atom, SessionID),
352 local_remove_session(ProfileID, SessionID).
358profile_session(ProfileID, SessionID) :-
359 local_session(ProfileID, SessionID).
360
361
362 365
366:- dynamic
367 tmp_session/3, 368 session_last_usage/2. 369:- volatile
370 tmp_session/3,
371 session_last_usage/2. 372
373local_add_session(ProfileID, SessionID, Options) :-
374 option(persistent(false), Options), !,
375 option(timeout(Timeout), Options),
376 get_time(Now),
377 asserta(tmp_session(ProfileID, SessionID, Timeout)),
378 asserta(session_last_usage(SessionID, Now)).
379local_add_session(ProfileID, SessionID, Options) :-
380 setting(backend, Backend),
381 Backend:impl_profile_add_session(ProfileID, SessionID, Options).
382
383local_refresh_session(ProfileID, SessionID) :-
384 tmp_session(ProfileID, SessionID, _Timeout), !,
385 get_time(Now),
386 retractall(session_last_usage(SessionID, _)),
387 asserta(session_last_usage(SessionID, Now)).
388local_refresh_session(ProfileID, SessionID) :-
389 setting(backend, Backend),
390 Backend:impl_profile_refresh_session(ProfileID, SessionID).
391
392local_remove_session(ProfileID, SessionID) :-
393 retract(tmp_session(ProfileID, SessionID, _)), !.
394local_remove_session(ProfileID, SessionID) :-
395 setting(backend, Backend),
396 Backend:impl_profile_remove_session(ProfileID, SessionID).
397
398local_session(ProfileID, SessionID) :-
399 var(ProfileID), var(SessionID), !,
400 ( tmp_session(_, SessionID, _),
401 local_session(ProfileID, SessionID)
402 ; setting(backend, Backend),
403 Backend:impl_profile_session(ProfileID, SessionID)
404 ).
405local_session(ProfileID, SessionID) :-
406 tmp_session(ProfileID, SessionID, TimeOut), !,
407 session_last_usage(SessionID, LastUsage),
408 get_time(Now),
409 ( LastUsage+TimeOut < Now
410 -> true
411 ; retractall(tmp_session(ProfileID, SessionID, _)),
412 retractall(session_last_usage(SessionID, _)),
413 fail
414 ).
415local_session(ProfileID, SessionID) :-
416 setting(backend, Backend),
417 Backend:impl_profile_session(ProfileID, SessionID).
418
419
420 423
424:- multifile error:has_type/2.
434error:has_type(url(http), URI) :-
435 string(URI),
436 uri_components(URI, Components),
437 valid_http_scheme(Components),
438 valid_authority(Components).
439error:has_type(email, Email) :-
440 string(Email),
441 split_string(Email, "@", "", [_,_]).
442error:has_type(time_stamp(_Format), Stamp) :-
443 number(Stamp).
444
445valid_http_scheme(Components) :-
446 uri_data(scheme, Components, Scheme),
447 nonvar(Scheme),
448 http_scheme(Scheme).
449
450http_scheme(http).
451http_scheme(https).
452
453valid_authority(Components) :-
454 uri_data(authority, Components, Authority),
455 nonvar(Authority).
456
457
458
User Profile Management
This module implements user profile management, in particular for managing authentication and authorization for HTTP servers. It mainly defines the interface that can be used within an HTTP application.
The actual storage is left to a plugin providing the backend implementation. Backend choices may depend on integration needs with other services, scale of the site (number of users), distribution, ease of installation.
The typical setup sequence is
*/