package org.apache.wicket.security.yahoo;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.wicket.security.authentication.LoginException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Yahoo! Web Services Example: Browser Based Authentication (BBAuth) This example shows
* how to generate the URL used for Yahoo! Brower Based Authentication. This example
* should be run before YahooBBAuthRequest to obtain the auth token via the callback URL
* specified when you obtained your application ID and secret. If you do not have an
* Application ID and Secret, go to the Yahoo! BBAuth Registration page:
* https://developer.yahoo.com/wsregapp/index.php
*
* @author Daniel Jones www.danieljones.org Copyright 2007
* @author marrink, slightly modified
*/
public class YahooBBAuth
{
/**
* For standalone use.
*
* @param args
*/
public static void main(String[] args)
{
/**
* Use the appId and secret provided when you registered your application
* https://developer.yahoo.com/wsregapp/index.php
*/
String appId = "";
String secret = "";
String authURL;
try
{
authURL = generateYahooAuthenticationUrl(appId, secret);
System.out.println(authURL);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
/**
* Use the appId and secret provided when you registered your application
* https://developer.yahoo.com/wsregapp/index.php
*
* @param appId
* @param secret
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static String generateYahooAuthenticationUrl(String appId, String secret)
throws UnsupportedEncodingException, NoSuchAlgorithmException
{
// Get the current time. Needed to sign the request.
long time = System.currentTimeMillis() / 1000;
/**
* Generate the Yahoo! authentication URL that you will send users to to verify
* their Yahoo! identity More information can be found here:
* http://developer.yahoo.com/auth/user.html
*/
String appData = "foobar";
String authWS = "/WSLogin/V1/wslogin";
String sig =
authWS + "?appid=" + encode(appId) + "&appdata=" + encode(appData) + "&ts=" + time
+ secret;
String signature = MD5(sig);
String authURL =
"https://api.login.yahoo.com" + authWS + "?appid=" + appId + "&appdata=" + appData
+ "&ts=" + time + "&sig=" + signature;
/**
* The end user will browse to this URL and allow access to your web application.
* After authenticating, the user will be forwarded to the callback URL specified
* when you obtained your application ID and secret.
*/
return authURL;
}
/**
* This method returns the MD5 hash of a text string
*
* @throws NoSuchAlgorithmException
*/
public static String MD5(String text) throws NoSuchAlgorithmException
{
String md5Text = "";
MessageDigest digest = MessageDigest.getInstance("MD5");
md5Text = new BigInteger(1, digest.digest((text).getBytes())).toString(16);
if (md5Text.length() == 31)
{
md5Text = "0" + md5Text;
}
return md5Text;
}
/**
* URL encode a text string
*
* @throws UnsupportedEncodingException
*/
public static String encode(String text) throws UnsupportedEncodingException
{
return URLEncoder.encode(text, "UTF-8");
}
/**
* Returns a session id and cookie if the user was succesfully authenticated. The web
* service session id (wssid) and Yahoo! cookie can then be used for calls to the SOAP
* or JSON-RPC endpoints. http://developer.yahoo.com/mail/docs/html/index.html
*/
public static YahooResponse authenticateUser(String appId, String secret, String uri,
String appdata, String ts, String requestsig, String token) throws LoginException
{
try
{
String calcsig =
uri + "?appid=" + appId + "&token=" + token + "&appdata=" + appdata + "&ts=" + ts
+ secret;
// log.info(calcsig);
// MessageDigest digest = MessageDigest.getInstance("MD5");
// calcsig = new BigInteger(1,
// digest.digest((calcsig).getBytes())).toString(16);
calcsig = MD5(calcsig);
// Verify that the signature sent by Yahoo! matches the calculated
// signture
if (!calcsig.equals(requestsig))
throw new YahooLoginException("Signature mismatch:" + requestsig + " vs " + calcsig);
// Get the current time. Needed to sign the request.
long time = System.currentTimeMillis() / 1000;
long requesttime = Long.parseLong(ts);
long clockSkew = Math.abs(time - requesttime);
// Make sure the server time is within 10 minutes (600 seconds) of
// Yahoo!'s servers
if (clockSkew >= 600)
throw new YahooLoginException("Invalid timestamp - clockSkew is " + clockSkew
+ " seconds, current time = " + time + ", ts =" + requesttime);
/**
* Generate the portion of the URL that's used for signing. More information
* on BBAuth can be found here: http://developer.yahoo.com/auth/
*/
String authWS = "/WSLogin/V1/wspwtoken_login";
String sig =
authWS + "?appid=" + encode(appId) + "&token=" + encode(token) + "&ts=" + time
+ secret;
// String signature = new BigInteger(1,
// digest.digest((sig).getBytes())).toString(16);
String signature = MD5(sig);
String authURL =
"https://api.login.yahoo.com" + authWS + "?appid=" + appId + "&token=" + token
+ "&ts=" + time + "&sig=" + signature;
// log.info(authURL);
// out.println(authURL);
// out.println("<br>");
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(authURL);
InputStream rstream = null;
client.executeMethod(method);
// Get the response body
rstream = method.getResponseBodyAsStream();
if (rstream == null)
{
Header[] headers = method.getResponseHeaders();
if (headers != null)
{
for (int i = 0; i < headers.length; i++)
{
Header h = headers[i];
// log.info(h.getName() + "=" + h.getValue());
}
}
throw new YahooLoginException("No response from Yahoo.");
}
/*
* Retrieve the XML response to the auth request and get the wssid and cookie
* values.
*/
Document xmlresponse =
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(rstream);
StringWriter writer = new StringWriter(5000);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(xmlresponse),
new StreamResult(writer));
// log.info("\n" + writer.toString());
// Check if token is in the response
NodeList wssidResponse = xmlresponse.getElementsByTagName("WSSID");
NodeList cookieResponse = xmlresponse.getElementsByTagName("Cookie");
NodeList timeoutResponse = xmlresponse.getElementsByTagName("Timeout");
Node wssidNode = wssidResponse.item(0);
Node cookieNode = cookieResponse.item(0);
Node timeoutNode = timeoutResponse.item(0);
if (wssidNode != null)
{
YahooResponse response =
new YahooResponse(wssidNode.getFirstChild().getNodeValue(), Long.valueOf(
timeoutNode.getFirstChild().getNodeValue()).longValue(), cookieNode
.getFirstChild().getNodeValue());
return response;
}
else
{
/*
* Print the response error code and message <?xml version="1.0"
* encoding="UTF-8" standalone="no"?> <wspwtoken_login_response> <Error>
* <ErrorCode>3000</ErrorCode> <ErrorDescription>Invalid (missing)
* appid</ErrorDescription> </Error> </wspwtoken_login_response>
*/
String code =
xmlresponse.getElementsByTagName("ErrorCode").item(0).getFirstChild()
.getNodeValue();
String msg =
xmlresponse.getElementsByTagName("ErrorDescription").item(0).getFirstChild()
.getNodeValue();
throw new YahooLoginException(code, msg);
}
}
catch (Exception e)
{
throw new YahooLoginException("Authentication failed.", e);
}
}
}