package org.verisign.joid.consumer;
import org.verisign.joid.OpenIdException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.GetMethod;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
/**
* User: treeder
* Date: Jul 17, 2007
* Time: 5:05:52 PM
*/
public class Discoverer
{
public ServerAndDelegate findIdServer(String identityUrl)
throws Exception
{
ServerAndDelegate serverAndDelegate = new ServerAndDelegate();
// OpenID 2.0, we first try to check with YADIS protocol
findWithYadis(identityUrl, serverAndDelegate);
if (serverAndDelegate.getServer() == null) {
throw new OpenIdException("No openid.server found on identity page.");
}
return serverAndDelegate;
}
public void findWithYadis(String identityUrl, ServerAndDelegate serverAndDelegate) throws Exception
{
BufferedReader in = null;
HttpClient httpClient = new HttpClient();
httpClient.getParams().setSoTimeout(15000);
httpClient.getParams().setConnectionManagerTimeout(15000);
GetMethod get = null;
try {
System.out.println("identityUrl=" + identityUrl);
get = new GetMethod(identityUrl);
// test
int status = httpClient.executeMethod(get);
System.out.println("status="+status);
dumpHeaders(get.getResponseHeaders());
// System.out.println("body=" + get.getResponseBodyAsString());
Header contentType = get.getResponseHeader("Content-Type");
if(contentType != null && contentType.getValue().contains("application/xrds+xml")){
// then we're looking at the xrds service doc already
XRDSDocument xrdsDocument = buildXrdsDocument(get);
handleXrdsDocument(serverAndDelegate, xrdsDocument);
return;
}
Header locationHeader = get.getResponseHeader("X-XRDS-Location");
if (locationHeader != null) {
// then we go to this URL
get.releaseConnection();
System.out.println("found yadis header: " + locationHeader.getValue());
XRDSDocument xrdsDocument = fetchYadisDocument(httpClient, locationHeader.getValue());
handleXrdsDocument(serverAndDelegate, xrdsDocument);
return;
} else {
// try to find it in the HTML, OpenID 1.0 style
// todo: should also look for X-XRDS-Location in a meta tag here
in = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream()));
findServerAndDelegate(serverAndDelegate, in);
return;
}
/*
This is the last try for YADIS:
get = new GetMethod(identityUrl);
get.setRequestHeader("Accept", " application/xrds+xml");
httpClient.executeMethod(get);
Header contentType = get.getResponseHeader("content-type");
System.out.println("content-type=" + contentType);
get.releaseConnection();
*/
} finally {
if (in != null) in.close();
if (get != null) get.releaseConnection();
}
}
private void handleXrdsDocument(ServerAndDelegate serverAndDelegate, XRDSDocument xrdsDocument)
{
List services = xrdsDocument.getServiceList();
Iterator it = services.iterator();
while (it.hasNext()) {
XRDSService service = (XRDSService) it.next();
System.out.println("service=" + service.getUri());
serverAndDelegate.setServer(service.getUri());
// todo: also set delegate after we get it
}
}
private void dumpHeaders(Header[] responseHeaders)
{
for (int i = 0; i < responseHeaders.length; i++) {
Header responseHeader = responseHeaders[i];
System.out.println(responseHeader.getName() + "=" + responseHeader.getValue());
}
}
private void findServerAndDelegate(ServerAndDelegate serverAndDelegate, BufferedReader in)
throws IOException
{
String str;
while ((str = in.readLine()) != null) {
if (serverAndDelegate.getServer() == null) {
serverAndDelegate.setServer(findLinkTag(str, "openid.server", in));
}
if (serverAndDelegate.getDelegate() == null) {
serverAndDelegate.setDelegate(findLinkTag(str, "openid.delegate", in));
}
if (str.indexOf("</head>") >= 0) {
break;
}
}
}
private XRDSDocument fetchYadisDocument(HttpClient httpClient, String location) throws IOException, ParserConfigurationException, SAXException
{
GetMethod get = new GetMethod(location);
httpClient.executeMethod(get);
// System.out.println("got: " + get.getResponseBodyAsString());
XRDSDocument doc = buildXrdsDocument(get);
return doc;
}
private XRDSDocument buildXrdsDocument(GetMethod get)
throws ParserConfigurationException, SAXException, IOException
{
XRDSDocument doc = new XRDSDocument();
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
javax.xml.parsers.DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(get.getResponseBodyAsStream());
get.releaseConnection();
NodeList list = document.getElementsByTagName("Service");
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
System.out.println("servicenode=" + node);
NodeList childNodes = node.getChildNodes();
XRDSService service = new XRDSService();
for (int j = 0; j < childNodes.getLength(); j++) {
// todo: ensure <Type> is http://openid.net/signon/1.0 - http://yadis.org/wiki/Yadis_1.0_(HTML)#7._The_Yadis_document
// todo: get delegate <openid:Delegate>
Node node2 = childNodes.item(j);
System.out.println(node2.getNodeName());
if (node2.getNodeName().equalsIgnoreCase("URI")) {
service.setUri(node2.getTextContent());
}
}
doc.addService(service);
}
return doc;
}
private String findLinkTag(String str, String rel, BufferedReader in)
throws IOException
{
int index = str.indexOf(rel);
if (index != -1) {
// todo: ensure it's a proper link tag
// todo: allow multiple line tag
// todo: allow reverse ordering
String href = findHref(str, index);
if (href == null) {
// no href found, check next line
str = in.readLine();
if (str != null) {
href = findHref(str, 0);
}
}
return href;
}
return null;
}
private String findHref(String str, int index)
{
String href = null;
int indexOfHref = str.indexOf("href=", index);
if (indexOfHref != -1) {
href = str.substring(indexOfHref + 6, str.indexOf("\"", indexOfHref + 8));
}
return href;
}
}