diff --git a/src/openid.erl b/src/openid.erl index ec3852a..9a70e37 100644 --- a/src/openid.erl +++ b/src/openid.erl @@ -19,44 +19,53 @@ discover(Identifier) -> case yadis:retrieve(Identifier) of {none, Body} -> html_discovery(Body); - XRDS -> extract_identifier(XRDS) + XRDS -> extract_authreq(XRDS) end. -extract_identifier(XRDS) -> - case extract_op_id(XRDS) of - none -> extract_claimed_id(XRDS); - OpID -> OpID +extract_authreq(XRDS) -> + case authreq_by_opid(XRDS) of + none -> authreq_by_claimed_id(XRDS); + Req -> Req end. -extract_op_id(XRDS) -> - case find_service_type(XRDS#xrds.services, "http://specs.openid.net/auth/2.0/server") of +authreq_by_opid(XRDS) -> + case find_service(XRDS#xrds.services, "http://specs.openid.net/auth/2.0/server") of none -> none; - URL -> #authReq{opURL=URL, version={2,0}} - end. - -extract_claimed_id(XRDS) -> - extract_claimed_id(XRDS, [{"http://specs.openid.net/auth/2.0/signon", {2,0}}, - {"http://openid.net/signon/1.1", {1,1}}, - {"http://openid.net/signon/1.0", {1,0}}]). - -extract_claimed_id(_, []) -> - none; -extract_claimed_id(XRDS, [{Type,Version}|Rest]) -> - case find_service_type(XRDS#xrds.services, Type) of - none -> extract_claimed_id(XRDS, Rest); - URL -> #authReq{opURL=URL, version=Version} + Service -> build_authReq(XRDS, Service, {2,0}) end. -find_service_type([], _) -> none; -find_service_type([{Types, []}|Rest], Type) -> find_service_type(Rest, Type); -find_service_type([{Types, [URL|_]}|Rest], Type) -> +find_service([], _) -> none; +find_service([#xrdService{uris=[]}|Rest], Type) -> find_service(Rest, Type); +find_service([#xrdService{types=Types}=Service|Rest], Type) -> case lists:any(fun(X) -> X == Type end, Types) of - true -> URL; - false -> find_service_type(Rest, Type) + true -> Service; + false -> find_service(Rest, Type) + end. + + +authreq_by_claimed_id(XRDS) -> + authreq_by_claimed_id(XRDS, [{"http://specs.openid.net/auth/2.0/signon", {2,0}}, + {"http://openid.net/signon/1.1", {1,1}}, + {"http://openid.net/signon/1.0", {1,0}}]). + +authreq_by_claimed_id(_, []) -> + none; +authreq_by_claimed_id(XRDS, [{Type,Version}|Rest]) -> + case find_service(XRDS#xrds.services, Type) of + none -> authreq_by_claimed_id(XRDS, Rest); + Service -> build_authReq(XRDS, Service, Version) end. + +build_authReq(XRDS, Service, Version) -> + [URL|_] = Service#xrdService.uris, + #authReq{opURL=URL, version={2,0}, + claimedID=XRDS#xrds.claimedID, + localID=Service#xrdService.localID}. + + html_discovery(Body) -> html_discovery(Body, [{"openid2.provider", "openid2.local_id", {2,0}}, {"openid.server", "openid.delegate", {1,1}}]). @@ -88,11 +97,12 @@ html_local_id(Body, RelName) -> test() -> + ?DBG({"Someone:", discover("blog.paulbonser.com")}), ?DBG({"Google:", discover("https://www.google.com/accounts/o8/id")}), ?DBG({"AOL:", discover("http://openid.aol.com/brend")}), ?DBG({"Flickr:", discover("http://flickr.com/exbrend")}), ?DBG({"Myspace:", discover("www.myspace.com")}), ?DBG({"LiveJournal:", discover("http://exbrend.livejournal.com")}), - ?DBG({"XRI Brend:", discover("=brendonh")}), + ?DBG({"XRI Brend:", discover("=brendonh")}), application:stop(inets). % Avoid error spam from held-open connections diff --git a/src/openid.hrl b/src/openid.hrl index 4c19e77..956733c 100644 --- a/src/openid.hrl +++ b/src/openid.hrl @@ -6,6 +6,12 @@ %%% Created : 18 Sep 2009 by Brendon Hogger %%%------------------------------------------------------------------- +-record(xrdService, { + types, + uris, + localID +}). + -record(xrds, { origID, claimedID, @@ -17,6 +23,6 @@ -record(authReq, { opURL, version, - claimedID, - localID + claimedID=none, + localID=none }). diff --git a/src/yadis.erl b/src/yadis.erl index 1c7f9b5..6fe8bed 100644 --- a/src/yadis.erl +++ b/src/yadis.erl @@ -137,19 +137,20 @@ get_descriptor_url(Body) -> munge_xrds(String) -> {Doc, _} = xmerl_scan:string(String), CanonicalID = get_canonical_id(Doc), - Services = [{Ts, Us} || {_P, Ts, Us} <- lists:sort( - fun({P1,_,_},{P2,_,_}) -> P1 < P2 end, + Services = [S || {_P, S} <- lists:sort( + fun({P1,_},{P2,_}) -> P1 < P2 end, [munge_service(S) || S <- xmerl_xpath:string("XRD/Service", Doc)])], #xrds{canonicalID=CanonicalID, services=Services}. munge_service(Service) -> Priority = get_priority(Service#xmlElement.attributes), Types = [get_text(T) || T <- xmerl_xpath:string("Type", Service)], + LocalID = get_local_id(Service), URIs = [U || {_P, U} <- lists:sort( fun({P1,_},{P2,_}) -> P1 < P2 end, [{get_priority(U#xmlElement.attributes), get_text(U)} || U <- xmerl_xpath:string("URI", Service)])], - {Priority, Types, URIs}. + {Priority, #xrdService{types=Types, uris=URIs, localID=LocalID}}. get_text(#xmlElement{content=[]}) -> ""; get_text(#xmlElement{content=[Value|_]}) -> Value#xmlText.value. @@ -163,7 +164,19 @@ get_canonical_id(Doc) -> [] -> none; [#xmlElement{content=[Value|_]}|_] -> Value#xmlText.value end. - + + +get_local_id(Service) -> + get_local_id(Service, ["LocalID", "Delegate"]). + +get_local_id(_, []) -> + none; +get_local_id(Service, [Tag|Rest]) -> + case xmerl_xpath:string(Tag, Service) of + [] -> get_local_id(Service, Rest); + [#xmlElement{content=[Value|_]}|_] -> Value#xmlText.value + end. + %% ------------------------------------------------------------ %% Tests