This library implements the OpenID protocol (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
Steps, as seen from the consumer (or relying partner).
- Show login form, asking for
- Get HTML page from
openid_identifier and lookup
<link rel="openid.server" href="server">
- Associate to server
- Redirect browser (302) to server using mode
asking to validate the given OpenID.
- OpenID server redirects back, providing digitally signed
conformation of the claimed identity.
- Validate signature and redirect to the target location.
A consumer (an application that allows OpenID login) typically uses
this library through openid_user/3. In addition, it must implement the
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:
:- multifile http_openid:openid_hook/1.
http_openid:openid_hook(trusted(_, OpenIdServer)) :-
By default, information who is logged on is maintained with the session
using http_session_assert/1 with the term
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 server, you must do four things: bind the handlers
openid_server/2 and openid_grant/1 to HTTP locations, provide a
user-page for registered users and define the
hook to verify your users. An example server is provided in in
- Call hook on the OpenID management library. Defined hooks are:
- Consider OpenID logged in.
- Logout OpenID
- True if OpenID is logged in
- grant(+Request, +Options)
- Server: Reply positive on OpenID
- trusted(+OpenID, +Server)
- True if Server is a trusted OpenID server
- Called if the server provided AX attributes
- x_parameter(+Server, -Name, -Value)
- Called to find additional HTTP parameters to send with the
OpenID verify request.
- openid_login(+OpenID) is det
- Associate the current HTTP session with OpenID. If another
OpenID is already associated, this association is first removed.
- openid_logout(+OpenID) is det
- Remove the association of the current session with any OpenID
- openid_logged_in(-OpenID) is semidet
- True if session is associated with OpenID.
- openid_user(+Request:http_request, -OpenID:url, +Options) is det
- True if OpenID is a validated 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.
openid_user(Request, OpenID, ),
If the user is not yet logged on a sequence of redirects will
- Show a page for login (default: page /openid/login),
- By default, the OpenID login page is a form that is
submitted to the
verify, which calls openid_verify/2.
- openid_verify/2 does the following:
- Find the OpenID claimed identity and server
- Associate to the OpenID server
- redirects to the OpenID server for validation
- The OpenID server will redirect here with the authetication
information. This is handled by openid_authenticate/4.
- (Local) URL of page to enter OpenID information. Default
is the handler for openid_login_page/1
- See also
- - openid_authenticate/4 produces errors if login is invalid
- Reply to a request for "Discovering OpenID Relying Parties".
This may happen as part of the provider verification procedure.
The provider will do a Yadis discovery request on
openid.realm. This is picked up by
openid_user/3, pointing the provider to
openid(xrds). Now, we
reply with the locations marked
openid and the locations that
have actually been doing OpenID validations.
- openid_login_page(+Request) is det[private]
- Present a login-form for OpenID. There are two ways to redefine
this default login page. One is to provide the option
login_url to openid_user/3 and the other is to define a new
/openid/login using http_handler/3.
- openid_login_form(+ReturnTo, +Options)// is det
- Create the OpenID form. This exported as a separate DCG,
allowing applications to redefine /openid/login and reuse this
part of the page. Options processed:
- URL of action to call. Default is the handler calling
- Buttons is a list of
img structures where the
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
href is relative, clicking it opens the given
location after adding 'openid.return_to' and `stay'.
true, show a checkbox that allows the user to stay
- prelogin_button(+Image)// is det[private]
- Handle OpenID 2.0 and other pre-login buttons. If the image has
href attribute that is absolute, it is taken as an OpenID
2.0 endpoint. Otherwise it is taken as a link on the current
server. This allows us to present non-OpenId logons in the same
screen. The dedicated handler is passed the HTTP parameters
- openid_verify(+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. Options is, against the conventions,
placed in front of the Request to allow for smooth cooperation
with http_dispatch.pl. Options processes:
- Specifies where the OpenID provider should return to.
Normally, that is the current location.
- Specifies the
openid.trust_root attribute. Defaults to
the root of the current server (i.e.,
- Specifies the
openid.realm attribute. Default is the
- Request the exchange of additional attributes from the
identity provider. See http_ax_attributes/2 for details.
The OpenId server will redirect to the
- Called if the user ask to stay signed in. This is called
before control is handed to the OpenID server. It leaves the
openid_stay_signed_in(true) in the current session.
- Handle stay_signed_in option after the user has logged on
- assert_openid(+OpenIDLogin, +OpenID, +Server, +Target) is det[private]
- Associate the OpenID as typed by the user, the OpenID as
validated by the Server with the current HTTP session.
|OpenIDLogin||- Canonized OpenID typed by user|
|OpenID||- OpenID verified by Server.|
- openid_server(?OpenIDLogin, ?OpenID, ?Server) is nondet
- True if OpenIDLogin is the typed id for OpenID verified by
|OpenIDLogin||- ID as typed by user (canonized)|
|OpenID||- ID as verified by server|
|Server||- URL of the OpenID server|
- public_url(+Request, +Path, -URL) is det[private]
- True when URL is a publically useable URL that leads to Path on
the current server.
- openid_current_url(+Request, -URL) is det
- Find the public URL for Request that we can make available to our
identity provider. This must be an absolute URL where we can be
contacted. Before trying a configured version through
http_public_url/2, we try to see wether the login message contains a
referer parameter or wether the browser provided one.
- openid_current_host(Request, Host, Port)
- Find current location of the server.
- - New code should use http_current_host/4 with the
- redirect_browser(+URL, +FormExtra)[private]
- Generate a 302 temporary redirect to URL, adding the extra form
information from FormExtra. The specs says we must retain the
search specification already attached to the URL.
- openid_resolve(+URL, -OpenIDOrig, -OpenID, -Server, -ServerOptions)[private]
- True if OpenID is the claimed OpenID that belongs to URL and
Server is the URL of the OpenID server that can be asked to
verify this claim.
|URL||- The OpenID typed by the user|
|OpenIDOrig||- Canonized OpenID typed by user|
|OpenID||- Possibly delegated OpenID|
|Server||- OpenID server that must validate OpenID|
|ServerOptions||- provides additional XRDS information about
the server. Currently supports |
- To be done
- - Implement complete URL canonization as defined by the
OpenID 2.0 proposal.
- ssl_verify(+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.
- HTTP handler when redirected back from the OpenID provider.
- openid_authenticate(+Request, -Server:url, -OpenID:url, -ReturnTo:url) is semidet
- Succeeds if Request comes from the OpenID server and confirms
that User is a verified OpenID user. ReturnTo provides the URL
to return to.
After openid_verify/2 has redirected the browser to the OpenID
server, and the OpenID server did its magic, it redirects the
browser back to this address. The work is fairly trivial. If
cancel, the OpenId server denied. If
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
openid.mode field in
if request was cancelled by the OpenId server
if the HMAC signature check failed
- signed_pairs(+FieldNames, +Pairs:list(Field-Value), +Form, -SignedPairs) is det[private]
- Extract the signed field in the order they appear in FieldNames.
- check_obligatory_fields(+SignedFields:list) is det[private]
- Verify fields from obligatory_field/1 are in the signed field
- check_authentication(+Request, +Form) is semidet[private]
- Implement the stateless verification method. This seems needed
for stackexchange.com, which provides the
res_id with a new
- ax_options(+ServerOptions, +Options, +AXAttrs) is det[private]
- True when AXAttrs is a list of additional attribute exchange
options to add to the OpenID redirect request.
- Extract reported AX data and store this into the session. If
there is a non-empty list of exchanged values, this calls
If this hook fails, Values are added to the session data using
- openid_server(+Options, +Request)
- Realise the OpenID server. The protocol demands a POST request
- associate_server(+Request, +Form, +Options)[private]
- Handle the association-request. If successful, create a clause
for server_association/3 to record the current association.
- checkid_setup_server(+Request, +Form, +Options)[private]
- Validate an OpenID for a TrustRoot and redirect the browser back
to the ReturnTo argument. There are many possible scenarios
- Check some cookie and if present, grant immediately
- Use a 401 challenge page
- Present a normal grant/password page
- As (3), but use HTTPS for the exchange
First thing to check is the immediate acknowledgement.
- Handle the reply from checkid_setup_server/3. If the reply is
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.
- grant_login(+Request, +Options) is det[private]
- Validate login from Request (can be used to get cookies) and
Options, which contains at least:
- trusted(+OpenID, +Server)[private]
- True if we trust the given OpenID server. Must throw an
exception, possibly redirecting to a page with trusted servers
if the given server is not trusted.
- signed_fields(+Pairs, -Signed) is det[private]
- Create a comma-separated atom from the field-names without
'openid.' from Pairs.
- signature(+Pairs, +Association, -Signature)[private]
- Determine the signature for Pairs
- openid_associate(?URL, ?Handle, ?Assoc) is det
- Calls openid_associate/4 as
openid_associate(URL, Handle, Assoc, ).
- openid_associate(+URL, -Handle, -Assoc, +Options) is det
- openid_associate(?URL, +Handle, -Assoc, +Options) is semidet
- 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. Options:
- One of
http://specs.openid.net/auth/2.0 (default) or
- To be done
- - Should we store known associations permanently? Where?
- shared_secret(+Pairs, +P, +X, -Secret:list(codes))[private]
- Find the shared secret from the peer's reply and our data. First
clause deals with the (deprecated) non-encoded version.
- expires_at(+Pairs, -Time) is det[private]
- Unify Time with a time-stamp stating when the association
- associate_data(-Data, -P, -G, -X, +Options) is det[private]
- Generate the data to initiate an association using Diffie-Hellman
shared secret key negotiation.
- random_bytes(+N, -Bytes) is det[private]
- Bytes is a list of N random bytes (integers 0..255).
- key_values_data(+KeyValues:list(Key-Value), -Data:list(code)) is det[private]
- key_values_data(-KeyValues:list(Key-Value), +Data:list(code)) is det[private]
- Encoding and decoding of key-value pairs for OpenID POST
messages according to Appendix C of the OpenID 1.1
- utf8_string(-Codes)// is nondet[private]
- Take a short UTF-8 code-list from input. Extend on backtracking.
- base64_btwoc(+Int, -Base64:list(code)) is det[private]
- base64_btwoc(-Int, +Base64:list(code)) is det[private]
- base64_btwoc(-Int, +Base64:atom) is det[private]
- btwoc(+Integer, -Bytes) is det[private]
- btwoc(-Integer, +Bytes) is det[private]
- Translate between a big integer and and its representation in
bytes. The first bit is always 0, as Integer is nonneg.
- xor_codes(+C1:list(int), +C2:list(int), -XOR:list(int)) is det[private]
- Compute xor of two strings.
length_mismatch(L1, L2) if the two lists do not have equal