Chris@0
|
1 /* $Id$
|
Chris@0
|
2
|
Chris@0
|
3 Part of SWI-Prolog
|
Chris@0
|
4
|
Chris@0
|
5 Author: Jan Wielemaker
|
Chris@0
|
6 E-mail: wielemak@science.uva.nl
|
Chris@0
|
7 WWW: http://www.swi-prolog.org
|
Chris@0
|
8 Copyright (C): 2007, University of Amsterdam
|
Chris@0
|
9
|
Chris@0
|
10 This program is free software; you can redistribute it and/or
|
Chris@0
|
11 modify it under the terms of the GNU General Public License
|
Chris@0
|
12 as published by the Free Software Foundation; either version 2
|
Chris@0
|
13 of the License, or (at your option) any later version.
|
Chris@0
|
14
|
Chris@0
|
15 This program is distributed in the hope that it will be useful,
|
Chris@0
|
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@0
|
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@0
|
18 GNU General Public License for more details.
|
Chris@0
|
19
|
Chris@0
|
20 You should have received a copy of the GNU Lesser General Public
|
Chris@0
|
21 License along with this library; if not, write to the Free Software
|
Chris@0
|
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Chris@0
|
23
|
Chris@0
|
24 As a special exception, if you link this library with other files,
|
Chris@0
|
25 compiled with a Free Software compiler, to produce an executable, this
|
Chris@0
|
26 library does not by itself cause the resulting executable to be covered
|
Chris@0
|
27 by the GNU General Public License. This exception does not however
|
Chris@0
|
28 invalidate any other reasons why the executable file might be covered by
|
Chris@0
|
29 the GNU General Public License.
|
Chris@0
|
30 */
|
Chris@0
|
31
|
Chris@0
|
32 :- module(rdfql_openid,
|
Chris@0
|
33 [ openid_for_local_user/2
|
Chris@0
|
34 ]).
|
Chris@0
|
35 :- use_module(library('http/http_dispatch')).
|
Chris@0
|
36 :- use_module(library('http/http_wrapper')).
|
Chris@0
|
37 :- use_module(library('http/http_openid')).
|
Chris@0
|
38 :- use_module(library('http/http_parameters')).
|
Chris@0
|
39 :- use_module(library('http/http_session')).
|
Chris@0
|
40 :- use_module(library('http/html_write')).
|
Chris@0
|
41 :- use_module(library(lists)).
|
Chris@0
|
42 :- use_module(library(error)).
|
Chris@0
|
43 :- use_module(library(option)).
|
Chris@0
|
44 :- use_module(library(url)).
|
Chris@0
|
45 :- use_module(library(socket)).
|
Chris@0
|
46 :- use_module(library(debug)).
|
Chris@0
|
47 :- use_module(library(settings)).
|
Chris@0
|
48 :- use_module(http_admin).
|
Chris@0
|
49 :- use_module(user_db).
|
Chris@0
|
50
|
Chris@0
|
51
|
Chris@0
|
52 /** <module> OpenID server and client access
|
Chris@0
|
53
|
Chris@0
|
54 @author Jan Wielemaker
|
Chris@0
|
55 */
|
Chris@0
|
56
|
Chris@0
|
57 /*******************************
|
Chris@0
|
58 * CUSTOMISE OPENID *
|
Chris@0
|
59 *******************************/
|
Chris@0
|
60
|
Chris@0
|
61 :- http_handler(prefix('/openid/grant'), openid_grant, []).
|
Chris@0
|
62 :- http_handler(prefix('/openid/file'), openid_file, []).
|
Chris@0
|
63
|
Chris@0
|
64 :- multifile
|
Chris@0
|
65 http_openid:openid_hook/2.
|
Chris@0
|
66
|
Chris@0
|
67 http_openid:openid_hook(login(OpenID)) :-
|
Chris@0
|
68 login(OpenID).
|
Chris@0
|
69 http_openid:openid_hook(logout(OpenID)) :-
|
Chris@0
|
70 logout(OpenID).
|
Chris@0
|
71 http_openid:openid_hook(logged_in(OpenID)) :-
|
Chris@0
|
72 http_session_id(Session),
|
Chris@0
|
73 user_property(OpenID, session(Session)).
|
Chris@0
|
74 http_openid:openid_hook(trusted(OpenID, Server)) :-
|
Chris@0
|
75 ( openid_server_properties(Server, _)
|
Chris@0
|
76 -> true
|
Chris@0
|
77 ; format(string(Msg), 'OpenID server ~w is not trusted', [Server]),
|
Chris@0
|
78 throw(error(permission_error(login, openid, OpenID),
|
Chris@0
|
79 context(_, Msg)))
|
Chris@0
|
80 ).
|
Chris@0
|
81
|
Chris@0
|
82
|
Chris@0
|
83 :- http_handler('/openid/login', login_page, [priority(10)]).
|
Chris@0
|
84
|
Chris@0
|
85 login_page(Request) :-
|
Chris@0
|
86 http_parameters(Request,
|
Chris@0
|
87 [ 'openid.return_to'(ReturnTo, [])
|
Chris@0
|
88 ]),
|
Chris@0
|
89 reply_html_page([ title('Login'),
|
Chris@0
|
90 \openid_css,
|
Chris@0
|
91 link([ rel(stylesheet),
|
Chris@0
|
92 type('text/css'),
|
Chris@0
|
93 href('../rdfql.css')
|
Chris@0
|
94 ])
|
Chris@0
|
95 ],
|
Chris@0
|
96 [ \explain_login(ReturnTo),
|
Chris@0
|
97 \openid_login_form(ReturnTo, []),
|
Chris@0
|
98 \local_login(ReturnTo)
|
Chris@0
|
99 ]).
|
Chris@0
|
100
|
Chris@0
|
101 explain_login(ReturnTo) -->
|
Chris@0
|
102 { parse_url(ReturnTo, Parts),
|
Chris@0
|
103 memberchk(path(Path), Parts)
|
Chris@0
|
104 },
|
Chris@0
|
105 html(div(class('rdfql-login'),
|
Chris@0
|
106 [ p([ 'You are trying to access a page (~w) that requires authorization.'-[Path],
|
Chris@0
|
107 'You can either login using an ', a(href('http://www.openid.net'), 'OpenID'),
|
Chris@0
|
108 \explain_trusted_openid
|
Chris@0
|
109 ])
|
Chris@0
|
110 ])).
|
Chris@0
|
111
|
Chris@0
|
112 explain_trusted_openid -->
|
Chris@0
|
113 { openid_current_server(*) }, !,
|
Chris@0
|
114 html(' or a local login.').
|
Chris@0
|
115 explain_trusted_openid -->
|
Chris@0
|
116 html([' from one of our ', a(href(list_trusted_servers), 'trusted providers'), ' or a local login']).
|
Chris@0
|
117
|
Chris@0
|
118 local_login(ReturnTo) -->
|
Chris@0
|
119 html(div(class('local-login'),
|
Chris@0
|
120 [ div(class('local-message'),
|
Chris@0
|
121 'Login with your local username and password'),
|
Chris@0
|
122 form([ action('../user/login'),
|
Chris@0
|
123 method('GET')
|
Chris@0
|
124 ],
|
Chris@0
|
125 [ \hidden('openid.return_to', ReturnTo),
|
Chris@0
|
126 div(input([name(user), size(20)])),
|
Chris@0
|
127 div([ input([name(password), size(20), type(password)]),
|
Chris@0
|
128 input([type(submit), value('login')])
|
Chris@0
|
129 ])
|
Chris@0
|
130 ])
|
Chris@0
|
131 ])).
|
Chris@0
|
132
|
Chris@0
|
133 hidden(Name, Value) -->
|
Chris@0
|
134 html(input([type(hidden), name(Name), value(Value)])).
|
Chris@0
|
135
|
Chris@0
|
136
|
Chris@0
|
137 :- http_handler('/openid/list_trusted_servers', trusted_openid_servers, []).
|
Chris@0
|
138
|
Chris@0
|
139 %% trusted_openid_servers(+Request)
|
Chris@0
|
140 %
|
Chris@0
|
141 % HTTP handler to emit a list of OpenID servers we trust.
|
Chris@0
|
142
|
Chris@0
|
143 trusted_openid_servers(_Request) :-
|
Chris@0
|
144 findall(S, openid_current_server(S), Servers),
|
Chris@0
|
145 reply_html_page(title('Trusted OpenID servers'),
|
Chris@0
|
146 [ h4('Trusted OpenID servers'),
|
Chris@0
|
147 p([ 'We accept OpenID logins from the following OpenID providers. ',
|
Chris@0
|
148 'Please register with one of them.'
|
Chris@0
|
149 ]),
|
Chris@0
|
150 ul(\trusted_openid_servers(Servers))
|
Chris@0
|
151 ]).
|
Chris@0
|
152
|
Chris@0
|
153 trusted_openid_servers([]) -->
|
Chris@0
|
154 [].
|
Chris@0
|
155 trusted_openid_servers([H|T]) -->
|
Chris@0
|
156 trusted_openid_server(H),
|
Chris@0
|
157 trusted_openid_servers(T).
|
Chris@0
|
158
|
Chris@0
|
159 trusted_openid_server(*) --> !.
|
Chris@0
|
160 trusted_openid_server(URL) -->
|
Chris@0
|
161 html(li(a(href(URL), URL))).
|
Chris@0
|
162
|
Chris@0
|
163
|
Chris@0
|
164 /*******************************
|
Chris@0
|
165 * OPENID SERVER *
|
Chris@0
|
166 *******************************/
|
Chris@0
|
167
|
Chris@0
|
168 :- http_handler(prefix('/user/'), openid_userpage, []).
|
Chris@0
|
169 :- http_handler(prefix('/openid/server'), openid_server([]), []).
|
Chris@0
|
170
|
Chris@0
|
171 http_openid:openid_hook(grant(Request, Options)) :-
|
Chris@0
|
172 ( option(identity(Identity), Options),
|
Chris@0
|
173 option(password(Password), Options),
|
Chris@0
|
174 file_base_name(Identity, User),
|
Chris@0
|
175 validate_password(User, Password)
|
Chris@0
|
176 -> option(trustroot(TrustRoot), Options),
|
Chris@0
|
177 debug(openid, 'Granted access for ~w to ~w', [Identity, TrustRoot])
|
Chris@0
|
178 ; memberchk(path(Path), Request),
|
Chris@0
|
179 throw(error(permission_error(http_location, access, Path),
|
Chris@0
|
180 context(_, 'Wrong password')))
|
Chris@0
|
181 ).
|
Chris@0
|
182
|
Chris@0
|
183
|
Chris@0
|
184 %% openid_userpage(+Request)
|
Chris@0
|
185 %
|
Chris@0
|
186 % Server user page for a registered user
|
Chris@0
|
187
|
Chris@0
|
188 openid_userpage(Request) :-
|
Chris@0
|
189 memberchk(path(Path), Request),
|
Chris@0
|
190 concat_atom(Parts, /, Path),
|
Chris@0
|
191 append(_, [user, User], Parts), !,
|
Chris@0
|
192 file_base_name(Path, User),
|
Chris@0
|
193 ( current_user(User)
|
Chris@0
|
194 -> http_global_url('../openid/server', Me),
|
Chris@0
|
195 findall(P, user_property(User, P), Props),
|
Chris@0
|
196 reply_html_page([ link([ rel('openid.server'),
|
Chris@0
|
197 href(Me)
|
Chris@0
|
198 ]),
|
Chris@0
|
199 title('OpenID page for user ~w'-[User])
|
Chris@0
|
200 ],
|
Chris@0
|
201 [ h1('OpenID page for user ~w'-[User]),
|
Chris@0
|
202 \user_properties(Props)
|
Chris@0
|
203 ])
|
Chris@0
|
204 ; existence_error(http_location, Path)
|
Chris@0
|
205 ).
|
Chris@0
|
206
|
Chris@0
|
207
|
Chris@0
|
208 user_properties([]) -->
|
Chris@0
|
209 [].
|
Chris@0
|
210 user_properties([H|T]) -->
|
Chris@0
|
211 user_property(H),
|
Chris@0
|
212 user_properties(T).
|
Chris@0
|
213
|
Chris@0
|
214 user_property(realname(Name)) --> !,
|
Chris@0
|
215 html(div(['Real name: ', Name])).
|
Chris@0
|
216 user_property(connection(Login, IdleF)) --> !,
|
Chris@0
|
217 { format_time(string(S), '%+', Login),
|
Chris@0
|
218 Idle is round(IdleF),
|
Chris@0
|
219 Hours is Idle // 3600,
|
Chris@0
|
220 Min is Idle mod 3600 // 60,
|
Chris@0
|
221 Sec is Idle mod 60
|
Chris@0
|
222 },
|
Chris@0
|
223 html(div(['Logged in since ~s, idle for ~d:~d:~d'-
|
Chris@0
|
224 [S, Hours,Min,Sec]])).
|
Chris@0
|
225 user_property(_) -->
|
Chris@0
|
226 [].
|
Chris@0
|
227
|
Chris@0
|
228
|
Chris@0
|
229 %% openid_for_local_user(+User, -URL) is semidet.
|
Chris@0
|
230 %
|
Chris@0
|
231 % URL is the OpenID for the local user User.
|
Chris@0
|
232
|
Chris@0
|
233 openid_for_local_user(User, URL) :-
|
Chris@0
|
234 http_current_request(Request),
|
Chris@0
|
235 openid_current_host(Request, Host, Port),
|
Chris@0
|
236 ( catch(setting(http:prefix, Prefix), _, fail)
|
Chris@0
|
237 -> true
|
Chris@0
|
238 ; Prefix = '/'
|
Chris@0
|
239 ),
|
Chris@0
|
240 ( Port == 80
|
Chris@0
|
241 -> format(atom(URL), 'http://~w~w/user/~w',
|
Chris@0
|
242 [ Host, Prefix, User ])
|
Chris@0
|
243 ; format(atom(URL), 'http://~w:~w/~w/user/~w',
|
Chris@0
|
244 [ Host, Port, Prefix, User ])
|
Chris@0
|
245 ).
|
Chris@0
|
246
|
Chris@0
|
247
|
Chris@0
|
248
|
Chris@0
|
249 /*******************************
|
Chris@0
|
250 * UTIL *
|
Chris@0
|
251 *******************************/
|
Chris@0
|
252
|
Chris@0
|
253 %% http_global_url(+Relative, -URL) is det.
|
Chris@0
|
254 %
|
Chris@0
|
255 % URL is a fully qualified URL relative to the current request.
|
Chris@0
|
256
|
Chris@0
|
257 http_global_url(Local, URL) :-
|
Chris@0
|
258 http_current_request(Request),
|
Chris@0
|
259 openid_current_host(Request, Host, Port),
|
Chris@0
|
260 option(path(Path), Request, '/'),
|
Chris@0
|
261 option(protocol(Protocol), Request, http),
|
Chris@0
|
262 Base = [ protocol(Protocol),
|
Chris@0
|
263 host(Host),
|
Chris@0
|
264 port(Port),
|
Chris@0
|
265 path(Path)
|
Chris@0
|
266 ],
|
Chris@0
|
267 global_url(Local, Base, URL).
|
Chris@0
|
268
|
Chris@0
|
269
|
Chris@0
|
270 /*******************************
|
Chris@0
|
271 * TEST *
|
Chris@0
|
272 *******************************/
|
Chris@0
|
273
|
Chris@0
|
274 :- http_handler('/user/form/login', login_handler, [priority(10)]).
|
Chris@0
|
275
|
Chris@0
|
276 login_handler(_Request) :-
|
Chris@0
|
277 ensure_logged_on(User),
|
Chris@0
|
278 user_property(User, url(URL)),
|
Chris@0
|
279 reload_attr(sidebar, OnLoad),
|
Chris@0
|
280 reply_html_page(title('Login ok'),
|
Chris@0
|
281 body(OnLoad,
|
Chris@0
|
282 [ h1('Login ok'),
|
Chris@0
|
283 p(['You''re logged on with OpenID ',
|
Chris@0
|
284 a(href(URL), URL)])
|
Chris@0
|
285 ])).
|