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; } }