% This LaTeX document was generated using the LaTeX backend of PlDoc, % The SWI-Prolog documentation system \subsection{library(http/http_openid): OpenID consumer and server library} \label{sec:httpopenid} This library implements the OpenID protocol (\url{http://openid.net/)}. OpenID is a protocol to share identities on the network. The protocol itself uses simple basic HTTP, adding reliability using digitally signed messages. Steps, as seen from the \textit{consumer} (or \textit{relying partner}). \begin{enumerate} \item Show login form, asking for \verb$openid_identifier$ \item Get HTML page from \verb$openid_identifier$ and lookup \verb$$ \item Associate to \textit{server} \item Redirect browser (302) to server using mode \verb$checkid_setup$, asking to validate the given OpenID. \item OpenID server redirects back, providing digitally signed conformation of the claimed identity. \item Validate signature and redirect to the target location. \end{enumerate} A \textbf{consumer} (an application that allows OpenID login) typically uses this library through \predref{openid_user}{3}. In addition, it must implement the hook http_openid:\verb$openid_hook(trusted(OpenId, Server))$ to define accepted OpenID servers. Typically, this hook is used to provide a white-list of acceptable servers. Note that accepting any OpenID server is possible, but anyone on the internet can setup a dummy OpenID server that simply grants and signs every request. Here is an example: \begin{code} :- multifile http_openid:openid_hook/1. http_openid:openid_hook(trusted(_, OpenIdServer)) :- ( trusted_server(OpenIdServer) -> true ; throw(http_reply(moved_temporary('/openid/trustedservers'))) ). trusted_server('http://www.myopenid.com/server'). \end{code} By default, information who is logged on is maintained with the session using \predref{http_session_assert}{1} with the term \verb$openid(Identity)$. The hooks login/logout/logged_in can be used to provide alternative administration of logged-in users (e.g., based on client-IP, using cookies, etc.). To create a \textbf{server}, you must do four things: bind the handlers \predref{openid_server}{2} and \predref{openid_grant}{1} to HTTP locations, provide a user-page for registered users and define the \verb$grant(Request, Options)$ hook to verify your users. An example server is provided in in $<$plbase$>$/\file{doc/packages/examples/demo_openid.pl}\vspace{0.7cm} \begin{description} \predicate[multifile]{openid_hook}{1}{+Action} Call hook on the OpenID management library. Defined hooks are: \begin{description} \termitem{login}{+OpenID} Consider \arg{OpenID} logged in. \termitem{logout}{+OpenID} Logout \arg{OpenID} \termitem{logged_in}{?OpenID} True if \arg{OpenID} is logged in \termitem{grant}{+Request, +Options} Server: Reply positive on OpenID \termitem{trusted}{+OpenID, +Server} True if \arg{Server} is a trusted \arg{OpenID} server \termitem{ax}{Values} Called if the server provided AX attributes \termitem{x_parameter}{+Server, -Name, -Value} Called to find additional HTTP parameters to send with the OpenID verify request. \end{description} \predicate[det]{openid_login}{1}{+OpenID} Associate the current HTTP session with \arg{OpenID}. If another \arg{OpenID} is already associated, this association is first removed. \predicate[det]{openid_logout}{1}{+OpenID} Remove the association of the current session with any \arg{OpenID} \predicate[semidet]{openid_logged_in}{1}{-OpenID} True if session is associated with \arg{OpenID}. \predicate[det]{openid_user}{3}{+Request:http_request, -OpenID:url, +Options} True if \arg{OpenID} is a validated \arg{OpenID} associated with the current session. The scenario for which this predicate is designed is to allow an HTTP handler that requires a valid login to use the transparent code below. \begin{code} handler(Request) :- openid_user(Request, OpenID, []), ... \end{code} If the user is not yet logged on a sequence of redirects will follow: \begin{enumerate} \item Show a page for login (default: page /openid/login), predicate \predref{reply_openid_login}{1}) \item By default, the \arg{OpenID} login page is a form that is submitted to the \const{verify}, which calls \predref{openid_verify}{2}. \item \predref{openid_verify}{2} does the following: \begin{shortlist} \item Find the \arg{OpenID} claimed identity and server \item Associate to the \arg{OpenID} server \item redirects to the \arg{OpenID} server for validation \end{shortlist} \item The \arg{OpenID} server will redirect here with the authetication information. This is handled by \predref{openid_authenticate}{4}. \end{enumerate} \arg{Options}: \begin{description} \termitem{login_url}{Login} (Local) URL of page to enter \arg{OpenID} information. Default is the handler for \predref{openid_login_page}{1} \end{description} \begin{tags} \tag{See also} \predref{openid_authenticate}{4} produces errors if login is invalid or cancelled. \end{tags} \dcg[det]{openid_login_form}{2}{+ReturnTo, +Options} Create the OpenID form. This exported as a separate DCG, allowing applications to redefine /openid/login and reuse this part of the page. \arg{Options} processed: \begin{description} \termitem{action}{Action} URL of action to call. Default is the handler calling \predref{openid_verify}{1}. \termitem{buttons}{+Buttons} \arg{Buttons} is a list of \const{img} structures where the \const{href} points to an OpenID 2.0 endpoint. These buttons are displayed below the OpenID URL field. Clicking the button sets the URL field and submits the form. Requires Javascript support. If the \const{href} is \textit{relative}, clicking it opens the given location after adding 'openid.return_to' and `stay'. \termitem{show_stay}{+Boolean} If \const{true}, show a checkbox that allows the user to stay logged on. \end{description} \predicate{openid_verify}{2}{+Options, +Request} Handle the initial login form presented to the user by the relying party (consumer). This predicate discovers the OpenID server, associates itself with this server and redirects the user's browser to the OpenID server, providing the extra openid.X name-value pairs. \arg{Options} is, against the conventions, placed in front of the \arg{Request} to allow for smooth cooperation with \file{http_dispatch.pl}. \arg{Options} processes: \begin{description} \termitem{return_to}{+URL} Specifies where the OpenID provider should return to. Normally, that is the current location. \termitem{trust_root}{+URL} Specifies the \verb$openid.trust_root$ attribute. Defaults to the root of the current server (i.e., \verb$http://host[.port]/$). \termitem{realm}{+URL} Specifies the \verb$openid.realm$ attribute. Default is the \verb$trust_root$. \termitem{ax}{+Spec} \arg{Request} the exchange of additional attributes from the identity provider. See \predref{http_ax_attributes}{2} for details. \end{description} The OpenId server will redirect to the \verb$openid.return_to$ URL. \begin{tags} \tag{throws} \verb$http_reply(moved_temporary(Redirect))$ \end{tags} \predicate[nondet]{openid_server}{3}{?OpenIDLogin, ?OpenID, ?Server} True if \arg{OpenIDLogin} is the typed id for \arg{OpenID} verified by \arg{Server}. \begin{arguments} \arg{OpenIDLogin} & ID as typed by user (canonized) \\ \arg{OpenID} & ID as verified by server \\ \arg{Server} & URL of the \arg{OpenID} server \\ \end{arguments} \predicate[det]{openid_current_url}{2}{+Request, -URL} Find the public \arg{URL} for \arg{Request} that we can make available to our identity provider. This must be an absolute \arg{URL} where we can be contacted. Before trying a configured version through \predref{http_public_url}{2}, we try to see wether the login message contains a referer parameter or wether the browser provided one. \predicate{openid_current_host}{3}{Request, Host, Port} Find current location of the server. \begin{tags} \tag{deprecated} New code should use \predref{http_current_host}{4} with the option \verb$global(true)$. \end{tags} \predicate{ssl_verify}{5}{+SSL, +ProblemCert, +AllCerts, +FirstCert, +Error} Accept all certificates. We do not care too much. Only the user cares s/he is not entering her credentials with a spoofed side. As we redirect, the browser will take care of this. \predicate[semidet]{openid_authenticate}{4}{+Request, -Server:url, -OpenID:url, -ReturnTo:url} Succeeds if \arg{Request} comes from the \arg{OpenID} server and confirms that User is a verified \arg{OpenID} user. \arg{ReturnTo} provides the URL to return to. After \predref{openid_verify}{2} has redirected the browser to the \arg{OpenID} server, and the \arg{OpenID} server did its magic, it redirects the browser back to this address. The work is fairly trivial. If \const{mode} is \const{cancel}, the OpenId server denied. If \verb$id_res$, the OpenId server replied positive, but we must verify what the server told us by checking the HMAC-SHA signature. This call fails silently if their is no \verb$openid.mode$ field in the request. \begin{tags} \mtag{throws}- \verb$openid(cancel)$ if request was cancelled by the OpenId server \\- \verb$openid(signature_mismatch)$ if the HMAC signature check failed \end{tags} \predicate{openid_server}{2}{+Options, +Request} Realise the OpenID server. The protocol demands a POST request here. \predicate{openid_grant}{1}{+Request} Handle the reply from \predref{checkid_setup_server}{3}. If the reply is \const{yes}, check the authority (typically the password) and if all looks good redirect the browser to ReturnTo, adding the OpenID properties needed by the Relying Party to verify the login. \predicate[det]{openid_associate}{3}{?URL, ?Handle, ?Assoc} Calls \predref{openid_associate}{4} as \begin{code} openid_associate(URL, Handle, Assoc, []). \end{code} \predicate[det]{openid_associate}{4}{+URL, -Handle, -Assoc, +Options} \nodescription \predicate[semidet]{openid_associate}{4}{?URL, +Handle, -Assoc, +Options} Associate with an open-id server. We first check for a still valid old association. If there is none or it is expired, we esstablish one and remember it. \arg{Options}: \begin{description} \termitem{ns}{URL} One of \verb$http://specs.openid.net/auth/2.0$ (default) or \verb$http://openid.net/signon/1.1$. \end{description} \begin{tags} \tag{To be done} Should we store known associations permanently? Where? \end{tags} \end{description}