29
30:- module(cliopatria_openid,
31 [ openid_for_local_user/2, 32 openid_for_local_user/3 33 ]). 34:- use_module(library(http/http_dispatch)). 35:- use_module(library(http/http_wrapper)). 36:- use_module(library(http/http_openid)). 37:- use_module(library(http/http_parameters)). 38:- use_module(library(http/http_session)). 39:- use_module(library(http/html_write)). 40:- use_module(library(http/html_head)). 41:- use_module(library(http/http_hook)). 42:- use_module(library(lists)). 43:- use_module(library(error)). 44:- use_module(library(option)). 45:- use_module(library(uri)). 46:- use_module(library(socket)). 47:- use_module(library(debug)). 48:- use_module(library(settings)). 49:- use_module(user_db).
59http:location(openid, root(openid), []).
60
61 64
65:- http_handler(openid(grant), openid_grant, [prefix]). 66
67:- multifile
68 http_openid:openid_hook/1. 69
70http_openid:openid_hook(login(OpenID)) :-
71 login(OpenID).
72http_openid:openid_hook(logout(OpenID)) :-
73 logout(OpenID).
74http_openid:openid_hook(logged_in(OpenID)) :-
75 logged_on(OpenID).
76http_openid:openid_hook(trusted(OpenID, Server)) :-
77 ( openid_server_properties(Server, _)
78 -> true
79 ; format(string(Msg), 'OpenID server ~w is not trusted', [Server]),
80 throw(error(permission_error(login, openid, OpenID),
81 context(_, Msg)))
82 ).
83
84
85:- http_handler(openid(login), login_page, [priority(10)]).
92login_page(Request) :-
93 http_open_session(_, []), 94 http_parameters(Request,
95 [ 'openid.return_to'(ReturnTo,
96 [ description('Page to visit after login')
97 ])
98 ]),
99 reply_html_page(cliopatria(default),
100 title('Login'),
101 [ \explain_login(ReturnTo),
102 \cond_openid_login_form(ReturnTo),
103 \local_login(ReturnTo)
104 ]).
105
106explain_login(ReturnTo) -->
107 { uri_components(ReturnTo, Components),
108 uri_data(path, Components, Path)
109 },
110 html(div(class('rdfql-login'),
111 [ p([ 'You are trying to access a page (~w) that requires authorization. '-[Path],
112 \explain_open_id_login
113 ])
114 ])).
115
116explain_open_id_login -->
117 { \+ openid_current_server(_) }, !.
118explain_open_id_login -->
119 html([ 'You can login either as a local user',
120 ' or with your ', a(href('http://www.openid.net'), 'OpenID'), '.']),
121 ( { openid_current_server(*) }
122 -> []
123 ; { http_link_to_id(trusted_openid_servers, [], HREF) },
124 html([ ' from one of our ', a(href(HREF), 'trusted providers')])
125 ).
126
127cond_openid_login_form(_) -->
128 { \+ openid_current_server(_) }, !.
129cond_openid_login_form(ReturnTo) -->
130 openid_login_form(ReturnTo, []).
131
132
133local_login(ReturnTo) -->
134 html(div(class('local-login'),
135 [ div(class('local-message'),
136 'Login with your local username and password'),
137 form([ action(location_by_id(user_login)),
138 method('GET')
139 ],
140 [ \hidden('openid.return_to', ReturnTo),
141 div(input([name(user), size(20)])),
142 div([ input([name(password), size(20), type(password)]),
143 input([type(submit), value('login')])
144 ])
145 ])
146 ])).
147
148hidden(Name, Value) -->
149 html(input([type(hidden), name(Name), value(Value)])).
150
151
152:- http_handler(openid(list_trusted_servers), trusted_openid_servers, []).
158trusted_openid_servers(_Request) :-
159 findall(S, openid_current_server(S), Servers),
160 reply_html_page(cliopatria(default),
161 title('Trusted OpenID servers'),
162 [ h4('Trusted OpenID servers'),
163 p([ 'We accept OpenID logins from the following OpenID providers. ',
164 'Please register with one of them.'
165 ]),
166 ul(\trusted_openid_servers(Servers))
167 ]).
168
169trusted_openid_servers([]) -->
170 [].
171trusted_openid_servers([H|T]) -->
172 trusted_openid_server(H),
173 trusted_openid_servers(T).
174
175trusted_openid_server(*) --> !.
176trusted_openid_server(URL) -->
177 html(li(a(href(URL), URL))).
178
179
180 183
184:- http_handler(root(user), openid_userpage, [prefix]). 185:- http_handler(openid(server), openid_server([]), [prefix]). 186
187http_openid:openid_hook(grant(Request, Options)) :-
188 ( option(identity(Identity), Options),
189 option(password(Password), Options),
190 file_base_name(Identity, User),
191 validate_password(User, Password)
192 -> option(trustroot(TrustRoot), Options),
193 debug(openid, 'Granted access for ~w to ~w', [Identity, TrustRoot])
194 ; memberchk(path(Path), Request),
195 throw(error(permission_error(http_location, access, Path),
196 context(_, 'Wrong password')))
197 ).
204openid_userpage(Request) :-
205 memberchk(path(Path), Request),
206 atomic_list_concat(Parts, /, Path),
207 append(_, [user, User], Parts), !,
208 file_base_name(Path, User),
209 ( current_user(User)
210 -> findall(P, user_property(User, P), Props),
211 reply_html_page(cliopatria(default),
212 [ link([ rel('openid.server'),
213 href(location_by_id(openid_server))
214 ]),
215 title('OpenID page for user ~w'-[User])
216 ],
217 [ h1('OpenID page for user ~w'-[User]),
218 \user_properties(Props)
219 ])
220 ; existence_error(http_location, Path)
221 ).
222
223
224user_properties([]) -->
225 [].
226user_properties([H|T]) -->
227 user_property(H),
228 user_properties(T).
229
230user_property(realname(Name)) --> !,
231 html(div(['Real name: ', Name])).
232user_property(connection(Login, IdleF)) --> !,
233 { format_time(string(S), '%+', Login),
234 Idle is round(IdleF),
235 Hours is Idle // 3600,
236 Min is Idle mod 3600 // 60,
237 Sec is Idle mod 60
238 },
239 html(div(['Logged in since ~s, idle for ~d:~d:~d'-
240 [S, Hours,Min,Sec]])).
241user_property(_) -->
242 [].
249openid_for_local_user(User, URL) :-
250 openid_for_local_user(User, URL, []).
251
252openid_for_local_user(User, URL, Options) :-
253 option(public_host(Host), Options), !,
254 http_location_by_id(openid_userpage, UserPages),
255 atom_concat(/, BelowRoot, UserPages),
256 format(atom(URL), '~w~w/~w',
257 [ Host, BelowRoot, User ]).
258openid_for_local_user(User, URL, _Options) :-
259 http_current_request(Request),
260 openid_current_host(Request, Host, Port),
261 http_location_by_id(openid_userpage, UserPages),
262 ( Port == 80
263 -> format(atom(URL), 'http://~w~w/~w',
264 [ Host, UserPages, User ])
265 ; format(atom(URL), 'http://~w:~w~w/~w',
266 [ Host, Port, UserPages, User ])
267 ).
268
269
270
271 274
275:- http_handler(cliopatria('user/form/login'), login_handler, [priority(10)]). 276
277login_handler(_Request) :-
278 ensure_logged_on(User),
279 user_property(User, url(URL)),
280 reply_html_page(cliopatria(default),
281 title('Login ok'),
282 [ h1('Login ok'),
283 p(['You''re logged on with OpenID ',
284 a(href(URL), URL)])
285 ])
OpenID server and client access
This module customizes login and OpenID handling for ClioPatria.