GeekFactory

int128.hatenablog.com

サーブレットフィルタによる署名検証

OpenSocialコンテナは外部サーバにリクエストを発行する機能があります。gadgets.io.makeRequest()を使ってリソースを取得したり、データを送信したりできます。

var xapp = {};
xapp.configuration = {
	endpoint: 'http://example.com/api';
};

xapp.query = function (resourceName, cb)
{
	var params = {};
	params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
	params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;
	params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
	return gadgets.io.makeRequest(xapp.configuration.endpoint+resourceName, cb, params);
};

// 外部からJSONリソースを取得
xapp.query('/count/today');

上記では http://example.com/api/count/today をGETしています。一般的なGETリクエストなので、サーバサイドは普段使っているWebフレームワークで実装できます。JavaであればRESTフレームワークのJerseyが使いやすいと思います。

OpenSocialコンテナからのリクエストには電子署名が付加されており、リクエストの正当性を検証できるようになっています。第三者からのリクエストを許可すると、ユーザIDを偽装されるおそれがあります。リクエストを受け付けるたびに署名検証を行う必要があります。

サーブレットフィルタを使えば簡単に署名検証が可能です。各サーブレットの先頭に署名検証処理を入れる必要はありません。自動的にやってくれます。

ソースコードの抜粋を載せておきます。HTTPリクエストごとにdoFilter()が実行され、OpenSocialコンテナからの署名が検証されます。検証エラーの場合ですが、RESTでは403を返せばよいと思います。

package org.hidetake.util.oauth;

public class MixiOAuthFilter implements Filter
{
	private final MixiOAuthValidator validator = new MixiOAuthValidator();

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
	throws IOException, ServletException
	{
		// ローカルからのアクセスは検証しない
		if(req.getRemoteAddr().equals("127.0.0.1")) {
			log.info("OAuth signature verification was skipped: 127.0.0.1");
		}
		else {
			try {
				validator.validateMessage((HttpServletRequest) req);
			}
			catch (OAuthException e) {
				// 検証エラーの場合は403を返す
				HttpServletResponse httpRes = (HttpServletResponse) res;
				httpRes.sendError(HttpServletResponse.SC_FORBIDDEN);
				
				log.error("OAuth signature verification failed: " + e.getLocalizedMessage());
				return;
			}
			catch (URISyntaxException e) {
				throw new ServletException(e);
			}
		}
		chain.doFilter(req, res);
	}

web.xmlには以下を追記します。

    <filter>
        <filter-name>oauth-filter</filter-name>
        <filter-class>org.hidetake.util.oauth.MixiOAuthFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>oauth-filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>