com.yahoo.yos.YahooFilter.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.yos.YahooFilter.java

Source

// Created by Sumit Shah on 7/02/09.
// Copyright (c) 2010 Yahoo! Inc. All rights reserved.
//
// The copyrights embodied in the content of this file are licensed under the BSD (revised) open source license.
package com.yahoo.yos;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
import net.oauth.OAuthServiceProvider;
import net.oauth.ParameterStyle;
import net.oauth.client.OAuthClient;
import net.oauth.http.HttpClient;
import net.oauth.server.OAuthServlet;
import net.oauth.signature.OAuthSignatureMethod;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * This is a servlet filter that assists in OAuth validation and authorization as well 
 * as some boilerplate when dealing with Yahoo! Open APIs.  Access and request tokens
 * are stored in cookies in a similar manner to the PHP SDK.
 *
 * @author Sam Pullara
 * @author Sumit Shah
 */
public class YahooFilter implements Filter {
    private final static Logger logger = LoggerFactory.getLogger(YahooFilter.class);

    private static enum SESSION_TYPE {
        YAHOO_YAP_SESSION_TYPE, YAHOO_OAUTH_AT_SESSION_TYPE, YAHOO_OAUTH_RT_SESSION_TYPE,
    }

    private Properties oauthConfig;
    private boolean redirect = false;
    private OAuthClient client;
    private OAuthServiceProvider provider;
    private OAuthConsumer consumer;
    private String callbackUrl;

    /**
     * Set the 'oauth' init parameter for this filter to change from the default
     * oauth.properties resource for configuration. The file should define:
     * <p/>
     * yos.consumerKey=...
     * yos.consumerSecret=...
     * oauth.requesttoken.url=https://api.login.yahoo.com/oauth/v2/get_request_token
     * oauth.requestauth.url=https://api.login.yahoo.com/oauth/v2/request_auth
     * oauth.accesstoken.url=https://api.login.yahoo.com/oauth/v2/get_token
     * oauth.callback.url=http://myapplication:8080/
     * <p/>
     * To access production OAuth services from Yahoo.  This filter relies on session
     * information stored by cookies to operate.
     *
     * @param filterConfig see upstream docs
     * @throws ServletException
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        String filename = filterConfig.getInitParameter("oauth");
        if (filename == null) {
            filename = "oauth.properties";
        }
        logger.debug("oauth properties file: {}", filename);
        oauthConfig = new Properties();
        try {
            oauthConfig.load(getClass().getResourceAsStream("/" + filename));
        } catch (IOException e) {
            throw new ServletException("Could not load oauth properties from resource: " + filename, e);
        }
        String redirectString = filterConfig.getInitParameter("redirect");
        // defaults to redirect if null, zero-length
        redirect = redirectString == null || redirectString.trim().length() <= 0
                || "true".equalsIgnoreCase(redirectString.trim());
        logger.debug("redirect if access token not found: {}", redirect);
        String oauthConnectionClass = filterConfig.getInitParameter("oauthConnectionClass");
        if (oauthConnectionClass == null) {
            oauthConnectionClass = "net.oauth.client.URLConnectionClient";
        }
        logger.debug("oauth client connection class: {}", oauthConnectionClass);
        try {
            client = new OAuthClient((HttpClient) Class.forName(oauthConnectionClass).newInstance());
        } catch (Exception cce) {
            throw new ServletException("unable to create OAuthClient from: " + oauthConnectionClass, cce);
        }
        provider = new OAuthServiceProvider(
                oauthConfig.getProperty("oauth.requesttoken.url",
                        "https://api.login.yahoo.com/oauth/v2/get_request_token"),
                oauthConfig.getProperty("oauth.requestauth.url",
                        "https://api.login.yahoo.com/oauth/v2/request_auth"),
                oauthConfig.getProperty("oauth.accesstoken.url", "https://api.login.yahoo.com/oauth/v2/get_token"));
        consumer = new OAuthConsumer(oauthConfig.getProperty("oauth.callback.url"),
                oauthConfig.getProperty("yos.consumerKey"), oauthConfig.getProperty("yos.consumerSecret"),
                provider);
        consumer.setProperty("oauth_signature_method",
                oauthConfig.getProperty("yos.oauth_signature_method", "HMAC-SHA1"));
        callbackUrl = oauthConfig.getProperty("oauth.callback.url", "");
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String yap_appid = getParam(request, "yap_appid");
        SESSION_TYPE sessionType;
        if ("POST".equals(request.getMethod()) && yap_appid != null && yap_appid.length() > 0) {
            sessionType = SESSION_TYPE.YAHOO_YAP_SESSION_TYPE;
        } else if (cookieExists(request.getCookies(), "yosdk_at")) {
            sessionType = SESSION_TYPE.YAHOO_OAUTH_AT_SESSION_TYPE;
        } else if (cookieExists(request.getCookies(), "yosdk_rt")) {
            sessionType = SESSION_TYPE.YAHOO_OAUTH_RT_SESSION_TYPE;
        } else {
            sessionType = null;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("sessionType: {}", sessionType);
        }

        OAuthAccessor accessor = new OAuthAccessor(consumer);

        if (sessionType == null) {
            if (redirect) {
                if (logger.isDebugEnabled()) {
                    logger.debug("redirecting user to yahoo acquire access token");
                }
                redirectForAuthorization(accessor, request, response);
                return;
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("inserting YahooSession suitable for 2-legged oauth calls into request attribute");
                }
                String appId = oauthConfig.getProperty("yos.appid");
                request.setAttribute("yahooSession", new YahooSession(client, consumer, null, appId));
            }
        } else if (sessionType == SESSION_TYPE.YAHOO_YAP_SESSION_TYPE) {
            if (logger.isDebugEnabled()) {
                logger.debug("inserting YahooSession suitable for 2-legged oauth calls into request attribute");
            }
            if (consumer.consumerKey == null
                    || !consumer.consumerKey.equals(getParam(request, "yap_consumer_key"))) {
                logger.error("Consumer key from YAP does not match config.");
                clearSession(request, response);
                if (redirect) {
                    redirectForAuthorization(accessor, request, response);
                    return;
                }
            }
            try {
                OAuthSignatureMethod method = OAuthSignatureMethod.newMethod("HMAC-SHA1", accessor);
                OAuthMessage msg = OAuthServlet.getMessage(request, null);
                method.validate(msg);
            } catch (OAuthProblemException ex) {
                logger.error("Signature from YAP failed.", ex);
                clearSession(request, response);
                if (redirect) {
                    redirectForAuthorization(accessor, request, response);
                    return;
                }
            } catch (Exception ex) {
                throw new ServletException(ex);
            }
            AccessToken at = new AccessToken();
            at.setKey(getParam(request, "yap_viewer_access_token"));
            at.setSecret(getParam(request, "yap_viewer_access_token_secret"));
            at.setGuid(getParam(request, "yap_viewer_guid"));
            at.setOwner(getParam(request, "yap_owner_guid"));
            at.setTokenExpires(-1);
            String appId = getParam(request, "yap_appid");
            YahooSession yahooSession = new YahooSession(client, consumer, at, appId);
            request.setAttribute("yahooSession", yahooSession);
        } else if (sessionType == SESSION_TYPE.YAHOO_OAUTH_AT_SESSION_TYPE) {
            long now = System.currentTimeMillis() / 1000;
            try {
                AccessToken accessToken = new AccessToken(cookie(request.getCookies(), "yosdk_at"));
                if (consumer.consumerKey == null || !consumer.consumerKey.equals(accessToken.getConsumer())) {
                    logger.error(
                            "Consumer key for token does not match the defined Consumer Key.  The Consumer Key has probably changed since the user last authorized the application.");
                    clearSession(request, response);
                    if (redirect) {
                        redirectForAuthorization(accessor, request, response);
                        return;
                    }
                }
                if (accessToken.getTokenExpires() >= 0 && logger.isDebugEnabled()) {
                    logger.debug("AT Expires in: {}", (accessToken.getTokenExpires() - now));
                }
                if (accessToken.getTokenExpires() >= 0 && (accessToken.getTokenExpires() - now) < 30) {
                    try {
                        accessTokenExpired(accessor, request, response, accessToken, filterChain);
                    } catch (OAuthException ex) {
                        if (ex instanceof OAuthProblemException) {
                            OAuthProblemException oape = (OAuthProblemException) ex;
                            String s = oape.getProblem() + oape.getParameters();
                            throw new ServletException(s, ex);
                        }
                        throw new ServletException(ex);
                    } catch (URISyntaxException ex) {
                        throw new ServletException(ex);
                    }
                    return;
                } else {
                    String appId = oauthConfig.getProperty("yos.appid");
                    YahooSession yahooSession = new YahooSession(client, consumer, accessToken, appId);
                    request.setAttribute("yahooSession", yahooSession);
                }
            } catch (JSONException e) {
                throw new ServletException(e);
            }
        } else if (sessionType == SESSION_TYPE.YAHOO_OAUTH_RT_SESSION_TYPE) {
            try {
                RequestToken rt = new RequestToken(cookie(request.getCookies(), "yosdk_rt"));
                accessor.tokenSecret = rt.getSecret();

                String verifier = getParam(request, "oauth_verifier");
                if (logger.isDebugEnabled()) {
                    logger.debug("got oauth_verifier {}", verifier);
                }

                try {
                    if (logger.isDebugEnabled()) {
                        logger.error("request token found, fetching access token for user");
                    }
                    AccessToken at = fetchAccessToken(accessor, rt, verifier);
                    Cookie yosdk_at = at.getCookie();
                    Cookie yosdk_rt = new Cookie("yosdk_rt", "");
                    yosdk_at.setMaxAge(30 * 24 * 60 * 60);
                    yosdk_rt.setMaxAge(0);
                    response.addCookie(yosdk_at);
                    response.addCookie(yosdk_rt);
                    String appId = oauthConfig.getProperty("yos.appid");
                    YahooSession yahooSession = new YahooSession(client, consumer, at, appId);
                    request.setAttribute("yahooSession", yahooSession);
                } catch (URISyntaxException ex) {
                    throw new ServletException(ex);
                } catch (OAuthException ex) {
                    clearSession(request, response);
                    if (redirect) {
                        redirectForAuthorization(accessor, request, response);
                        return;
                    } else {
                        throw new ServletException(ex);
                    }
                }
            } catch (JSONException e) {
                throw new ServletException(e);
            }
        }

        filterChain.doFilter(servletRequest, servletResponse);
    }

    private String getParam(HttpServletRequest request, String key) {
        String param = request.getParameter(key);
        if (param == null) {
            return request.getHeader("x-" + key.replace("_", "-"));
        }
        return param;
    }

    private AccessToken fetchAccessToken(OAuthAccessor accessor, RequestToken requestToken, String verifier)
            throws IOException, URISyntaxException, OAuthException {
        List<OAuth.Parameter> params;
        if (requestToken.getSessionHandle() != null) {
            params = OAuth.newList("oauth_token", requestToken.getKey(), "oauth_session_handle",
                    requestToken.getSessionHandle());
        } else {
            params = OAuth.newList("oauth_token", requestToken.getKey());
        }
        // Add the verifier which is required for OAuth1.0a
        if (verifier != null) {
            params.addAll(OAuth.newList("oauth_verifier", verifier));
        }
        OAuthMessage getTokenMsg = new OAuthMessage("GET", provider.accessTokenURL, params);
        getTokenMsg.addRequiredParameters(accessor);
        OAuthMessage msg = client.invoke(getTokenMsg, ParameterStyle.QUERY_STRING);
        Map<String, String> map = OAuth.newMap(msg.getParameters());
        AccessToken at = new AccessToken();
        at.setKey(map.get("oauth_token"));
        at.setSecret(map.get("oauth_token_secret"));
        at.setGuid(map.get("xoauth_yahoo_guid"));
        at.setConsumer(accessor.consumer.consumerKey);
        at.setSessionHandle(map.get("oauth_session_handle"));
        long now = System.currentTimeMillis() / 1000;
        if (map.containsKey("oauth_expires_in")) {
            at.setTokenExpires(now + Long.parseLong(msg.getParameter("oauth_expires_in")));
        } else {
            at.setTokenExpires(-1);
        }
        if (map.containsKey("oauth_authorization_expires_in")) {
            at.setHandleExpires(now + Long.parseLong(map.get("oauth_authorization_expires_in")));
        } else {
            at.setHandleExpires(-1);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("setting access token expires in: {}", at.getTokenExpires());
            logger.debug("setting access token handle expires in: {}", at.getHandleExpires());
        }
        return at;
    }

    private void accessTokenExpired(OAuthAccessor accessor, HttpServletRequest request,
            HttpServletResponse response, AccessToken accessToken, FilterChain filterChain)
            throws IOException, ServletException, JSONException, OAuthException, URISyntaxException {
        if (logger.isDebugEnabled()) {
            logger.debug("access token expired, attempting to renew");
        }
        long now = System.currentTimeMillis() / 1000;
        if (accessToken.getHandleExpires() == -1 || (now < accessToken.getHandleExpires())) {
            RequestToken requestToken = new RequestToken();
            requestToken.setKey(accessToken.getKey());
            requestToken.setSessionHandle(accessToken.getSessionHandle());
            accessor.tokenSecret = accessToken.getSecret();
            AccessToken at = fetchAccessToken(accessor, requestToken, null);
            Cookie yosdk_at = at.getCookie();
            yosdk_at.setMaxAge(30 * 24 * 60 * 60);
            response.addCookie(yosdk_at);
            String appId = oauthConfig.getProperty("yos.appid");
            YahooSession yahooSession = new YahooSession(client, consumer, at, appId);
            request.setAttribute("yahooSession", yahooSession);
            filterChain.doFilter(request, response);
        } else {
            Cookie at = new Cookie("yosdk_at", "");
            at.setMaxAge(0);
            at.setMaxAge(0);
            response.addCookie(at);
            request.setAttribute("yahooSession", null);
            request.setAttribute("yahooRedirect", null);
            filterChain.doFilter(request, response);
            if (redirect) {
                redirectForAuthorization(accessor, request, response);
            }
        }
    }

    private void redirectForAuthorization(OAuthAccessor accessor, HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {
        try {
            // get the request token
            List<OAuth.Parameter> callback = OAuth.newList(OAuth.OAUTH_CALLBACK, callbackUrl);
            //client.getRequestToken(accessor, null, callback);
            OAuthMessage message = client.getRequestTokenResponse(accessor, null, callback);
        } catch (URISyntaxException ex) {
            throw new ServletException(ex);
        } catch (OAuthException ex) {
            throw new ServletException(ex);
        }
        if (accessor.requestToken != null) {
            try {
                RequestToken rt = new RequestToken();
                rt.setKey(accessor.requestToken);
                rt.setSecret(accessor.tokenSecret);
                Cookie yosdk_rt = rt.getCookie();
                yosdk_rt.setMaxAge(600);
                response.addCookie(yosdk_rt);
            } catch (JSONException ex) {
                throw new ServletException(ex);
            }
        } else {
            throw new ServletException("Failed to create request token");
        }
        String redirectUrl = OAuth.addParameters(provider.userAuthorizationURL, "oauth_token",
                accessor.requestToken, "oauth_callback", callbackUrl);
        request.setAttribute("yahooRedirect", redirectUrl);
        response.sendRedirect(redirectUrl);
    }

    public void clearSession(HttpServletRequest req, HttpServletResponse res) {
        if (logger.isDebugEnabled()) {
            logger.debug("clear session requested");
        }
        Cookie at = new Cookie("yosdk_at", "");
        at.setMaxAge(0);
        Cookie rt = new Cookie("yosdk_rt", "");
        rt.setMaxAge(0);
        res.addCookie(at);
        res.addCookie(rt);
        req.setAttribute("yahooSession", null);
        req.setAttribute("yahooRedirect", null);
    }

    private boolean cookieExists(Cookie[] cookies, String cookieName) {
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName() != null && cookie.getName().equals(cookieName)) {
                    return true;
                }
            }
        }
        return false;
    }

    private Cookie cookie(Cookie[] cookies, String cookieName) {
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName() != null && cookie.getName().equals(cookieName)) {
                    return cookie;
                }
            }
        }
        return null;
    }

    public void destroy() {
        //empty
    }
}