View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        wielemak@science.uva.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (C): 2007-2017, University of Amsterdam
    7
    8    This program is free software; you can redistribute it and/or
    9    modify it under the terms of the GNU General Public License
   10    as published by the Free Software Foundation; either version 2
   11    of the License, or (at your option) any later version.
   12
   13    This program is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16    GNU General Public License for more details.
   17
   18    You should have received a copy of the GNU Lesser General Public
   19    License along with this library; if not, write to the Free Software
   20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21
   22    As a special exception, if you link this library with other files,
   23    compiled with a Free Software compiler, to produce an executable, this
   24    library does not by itself cause the resulting executable to be covered
   25    by the GNU General Public License. This exception does not however
   26    invalidate any other reasons why the executable file might be covered by
   27    the GNU General Public License.
   28*/
   29
   30:- module(cliopatria_openid,
   31	  [ openid_for_local_user/2,		% +User, -URL
   32	    openid_for_local_user/3		% +User, -URL, +Options
   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).

OpenID server and client access

This module customizes login and OpenID handling for ClioPatria.

author
- Jan Wielemaker */
   59http:location(openid, root(openid), []).
   60
   61		 /*******************************
   62		 *	CUSTOMISE OPENID	*
   63		 *******************************/
   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)]).
 login_page(+Request)
HTTP Handler that shows both OpenID login and local login-page to the user. This handler overrules the default OpenID handler.
   92login_page(Request) :-
   93	http_open_session(_, []),		% we need sessions to login
   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, []).
 trusted_openid_servers(+Request)
HTTP handler to emit a list of OpenID servers we trust.
  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		 /*******************************
  181		 *	   OPENID SERVER	*
  182		 *******************************/
  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	).
 openid_userpage(+Request)
Server user page for a registered user
  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	[].
 openid_for_local_user(+User, -URL) is semidet
URL is the OpenID for the local user User.
  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		 /*******************************
  272		 *	       TEST		*
  273		 *******************************/
  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			])