306 lines
8.1 KiB
Plaintext
306 lines
8.1 KiB
Plaintext
note
|
|
description: "Summary description for {OPENID_CONSUMER_VALIDATION}."
|
|
author: ""
|
|
date: "$Date$"
|
|
revision: "$Revision$"
|
|
|
|
class
|
|
OPENID_CONSUMER_VALIDATION
|
|
|
|
create
|
|
make_from_items
|
|
|
|
feature {NONE} -- Initialization
|
|
|
|
make_from_items (o: OPENID_CONSUMER; lst: like values)
|
|
do
|
|
openid := o
|
|
values := lst
|
|
return_url := o.return_url
|
|
create attributes.make (0)
|
|
end
|
|
|
|
values: detachable ITERABLE [TUPLE [name: READABLE_STRING_32; value: detachable READABLE_STRING_32]]
|
|
|
|
return_url: READABLE_STRING_8
|
|
|
|
feature -- Access
|
|
|
|
openid: OPENID_CONSUMER
|
|
|
|
identity: detachable READABLE_STRING_8
|
|
|
|
attributes: HASH_TABLE [READABLE_STRING_32, STRING_8]
|
|
|
|
feature -- Access: attributes
|
|
|
|
email_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("contact/email")
|
|
end
|
|
|
|
nickname_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("namePerson/friendly")
|
|
end
|
|
|
|
fullname_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("namePerson")
|
|
end
|
|
|
|
gender_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("person/gender")
|
|
end
|
|
|
|
postcode_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("contact/postalCode/home")
|
|
end
|
|
|
|
country_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("contact/country/home")
|
|
end
|
|
|
|
language_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("pref/language")
|
|
end
|
|
|
|
timezone_attribute: detachable READABLE_STRING_32
|
|
do
|
|
Result := attributes.item ("pref/timezone")
|
|
end
|
|
|
|
feature -- Basic operation
|
|
|
|
validate
|
|
-- Is openid identifier validated?
|
|
local
|
|
l_claimed_id: detachable READABLE_STRING_8
|
|
tb: HASH_TABLE [detachable READABLE_STRING_32, STRING_8]
|
|
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
|
ret: URI
|
|
sess: HTTP_CLIENT_SESSION
|
|
do
|
|
is_valid := False
|
|
create ret.make_from_string (return_url)
|
|
create tb.make (5)
|
|
if attached values as q_lst then
|
|
if attached item_by_name ("openid.claimed_id", q_lst) as q_claimed_id and then q_claimed_id.is_valid_as_string_8 then
|
|
l_claimed_id := q_claimed_id.to_string_8
|
|
elseif attached item_by_name ("openid.identity", q_lst) as l_id and then l_id.is_valid_as_string_8 then
|
|
l_claimed_id := l_id.to_string_8
|
|
end
|
|
identity := l_claimed_id
|
|
tb.force (item_by_name ("openid.assoc_handle", q_lst), "openid.assoc_handle")
|
|
tb.force (item_by_name ("openid.signed", q_lst), "openid.signed")
|
|
tb.force (item_by_name ("openid.sig", q_lst), "openid.sig")
|
|
if attached item_by_name ("openid.ns", q_lst) as q_ns then
|
|
-- We're dealing with an OpenID 2.0 server, so let's set an ns
|
|
-- Even though we should know location of the endpoint,
|
|
-- we still need to verify it by discovery, so $server is not set here
|
|
tb.force ("http://specs.openid.net/auth/2.0", "openid.ns")
|
|
elseif
|
|
attached item_by_name ("openid.claimed_id", q_lst) as q_claimed_id
|
|
and then (not attached item_by_name ("openid.identity", q_lst) as l_identity
|
|
or else not q_claimed_id.same_string (l_identity))
|
|
then
|
|
-- If it's an OpenID 1 provider, and we've got claimed_id,
|
|
-- we have to append it to the returnUrl, like authUrl_v1 does.
|
|
ret.add_query_parameter ("openid.claimed_id", q_claimed_id)
|
|
return_url := ret.string
|
|
else
|
|
end
|
|
|
|
if
|
|
attached item_by_name ("openid.return_to", q_lst) as q_return_to and then
|
|
not return_url.same_string_general (q_return_to)
|
|
then
|
|
-- The return_to url must match the url of current request.
|
|
-- I'm assuing that noone will set the returnUrl to something that doesn't make sense.
|
|
|
|
-- False, FIXME, exception ...
|
|
end
|
|
if l_claimed_id /= Void then
|
|
if
|
|
attached openid.discovering_info (l_claimed_id) as d_info and then
|
|
not openid.has_error and then not d_info.has_error
|
|
then
|
|
if attached item_by_name ("openid.signed", q_lst) as lst_signed then
|
|
across
|
|
lst_signed.split (',') as c
|
|
loop
|
|
tb.force (item_by_name ("openid." + c.item, q_lst), "openid." + c.item)
|
|
end
|
|
end
|
|
|
|
tb.force ("check_authentication", "openid.mode")
|
|
create ctx.make
|
|
across
|
|
tb as c
|
|
loop
|
|
if attached c.item as l_value then
|
|
ctx.add_form_parameter (c.key.to_string_32, l_value)
|
|
end
|
|
end
|
|
sess := openid.new_session (d_info.server_uri)
|
|
if attached sess.post ("", ctx, Void) as res then
|
|
if res.error_occurred then
|
|
elseif attached {STRING} res.body as l_body then
|
|
is_valid := l_body.substring_index ("is_valid:true", 1) > 0
|
|
if is_valid then
|
|
get_attributes (q_lst)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
get_attributes (lst: like values)
|
|
do
|
|
attributes.wipe_out
|
|
|
|
get_sreg_attributes (lst)
|
|
get_ax_attributes (lst)
|
|
end
|
|
|
|
get_sreg_attributes (lst: like values)
|
|
local
|
|
s: READABLE_STRING_32
|
|
sreg_keys: ARRAYED_LIST [READABLE_STRING_32]
|
|
do
|
|
if lst /= Void and then attached item_by_name ("openid.signed", lst) as l_signed then
|
|
-- sreg attributes
|
|
create sreg_keys.make (5)
|
|
across
|
|
l_signed.split (',') as c
|
|
loop
|
|
s := c.item
|
|
if s.starts_with ("sreg.") then
|
|
sreg_keys.force ("openid." + s)
|
|
end
|
|
end
|
|
across
|
|
sreg_keys as c
|
|
loop
|
|
s := c.item
|
|
if attached item_by_name (s, lst) as v then
|
|
attributes.force (v, s.substring (5, s.count))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
get_ax_attributes (lst: like values)
|
|
local
|
|
s: READABLE_STRING_32
|
|
ax_keys: ARRAYED_LIST [READABLE_STRING_32]
|
|
l_alias: detachable READABLE_STRING_8
|
|
k_value, k_type, k_count: READABLE_STRING_8
|
|
k: STRING_8
|
|
i: INTEGER
|
|
do
|
|
if lst /= Void and then attached item_by_name ("openid.signed", lst) as l_signed then
|
|
-- ax attributes
|
|
across
|
|
l_signed.split (',') as c
|
|
loop
|
|
i := i + 1
|
|
s := c.item
|
|
if s.starts_with ({STRING_32} "ns.") then
|
|
if attached item_by_name ({STRING_32} "openid." + s, lst) as v then
|
|
if s.same_string ({STRING_32} "ns.ax") and v.same_string ({STRING_32} "http://openid.net/srv/ax/1.0") then
|
|
l_alias := "ax."
|
|
else
|
|
if v.same_string_general ("http://openid.net/srv/ax/1.0") then
|
|
l_alias := s.substring (("ns.").count + 1, s.count).to_string_8 + "."
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if l_alias /= Void then
|
|
k_value := l_alias + "value."
|
|
k_type := l_alias + "type."
|
|
k_count := l_alias + "count."
|
|
|
|
create ax_keys.make (i)
|
|
across
|
|
l_signed.split (',') as c
|
|
loop
|
|
s := c.item
|
|
if
|
|
s.starts_with_general (k_value)
|
|
or s.starts_with_general (k_type)
|
|
then
|
|
ax_keys.force ("openid." + s)
|
|
end
|
|
end
|
|
|
|
k_value := "openid." + k_value
|
|
k_type := "openid." + k_type
|
|
k_count := "openid." + k_count
|
|
|
|
across
|
|
ax_keys as c
|
|
loop
|
|
s := c.item
|
|
if attached item_by_name (s, lst) as v then
|
|
if s.starts_with_general (k_value) then
|
|
k := s.substring (k_value.count + 1, s.count)
|
|
i := k.index_of ('.', 1)
|
|
if i > 1 then
|
|
k.keep_head (i - 1)
|
|
end
|
|
if attached item_by_name (k_type + k, lst) as l_type then
|
|
if l_type.starts_with_general ("http://axschema.org/") then
|
|
check ("http://axschema.org/").count = 20 end
|
|
attributes.force (v, l_type.substring (21, l_type.count))
|
|
elseif l_type.starts_with_general ("http://schema.openid.net/") then
|
|
check ("http://schema.openid.net/").count = 25 end
|
|
attributes.force (v, l_type.substring (26, l_type.count))
|
|
else
|
|
-- unsupported schema domain.
|
|
end
|
|
else
|
|
-- no alias !!!
|
|
end
|
|
-- attributes.force (v, k)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
item_by_name (a_name: READABLE_STRING_GENERAL; lst: like values): detachable READABLE_STRING_32
|
|
local
|
|
l_found: BOOLEAN
|
|
do
|
|
if lst /= Void then
|
|
across
|
|
lst as c
|
|
until
|
|
l_found
|
|
loop
|
|
if a_name.same_string (c.item.name) then
|
|
Result := c.item.value
|
|
l_found := True
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
is_valid: BOOLEAN
|
|
|
|
|
|
|
|
end
|