T2サンプルでOpenIDを使ったサンプルを追加しました


OpenIDの仕組みに興味が会ったので、T2でOpenIDを使った認証のサンプルを作りました。
OpenIDのリクエスト部分としては、openid4javaを使いました。


今のところ一番簡易な認証だけなので、本当はもう少しやり取りが必要かもしれませんが
少なくともWebフレームワークなんだし、OpenIDとのインテグレーション入れてみようと思った次第です。


サンプルを一番下にはります。
authenticateRequestメソッドがユーザから呼び出されるメソッドです。
わたってくるパラメータはOpenIDの認証先です。例えば、myname.openid.ne.jpみたいな感じ。
authenticateRequestメソッドの中ではOpenId認証局に行ったあとのコールバックする先を指定します。
ttp://localhost:8080/t2-samples/openid/acceptのようなURLにコールバックして欲しいので
下記のようにします。
それがauthenticateRequestメソッドの下記の部分です。

		String returnToUrl = request.getRequestURL().append("/accept")
				.toString();


ttp://localhost:8080/t2-samples/openid/acceptに対応するPageクラスのアクションメソッドを作ります。
メソッドはURLにそのままひもづかせたいので、acceptメソッドとして、以下のような感じになります。

OpenIDからのコールバックの結果をverifyResponseメソッドで検査してます。

	@GET
	@ActionPath
	public Navigation accept(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		Identifier identifier = null;
		try {
			identifier = this.verifyResponse(req);
		} catch (OpenIDException ex) {
			logger.debug(ex.getMessage());
		}
		logger.debug("identifier: " + identifier);
		if (identifier == null) {
			return Forward.to("/jsp/openid.jsp");
		} else {
			req.setAttribute("identifier", identifier.getIdentifier());
			return Forward.to("/jsp/openidResult.jsp");
		}
	}


重要なのは、verifyResponseメソッドで呼び出しているConsumerManager#verify(String receivingUrl, ParameterList response, DiscoveryInformation discovered)です。
こいつで実際にOpenIDで接続許可がとれたかどうか、その認証は期限内かどうかなどを見ています。
もっと突き詰めていけば色々出来そうですが、T2のリリースも迫っているのでこの辺にしておきます。
また今度見直してみます。



ソース全文は下記からどうぞ。

package examples.page;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openid4java.OpenIDException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.AuthSuccess;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.t2framework.commons.annotation.composite.RequestScope;
import org.t2framework.commons.util.Logger;
import org.t2framework.t2.annotation.composite.GET;
import org.t2framework.t2.annotation.composite.POST;
import org.t2framework.t2.annotation.core.ActionParam;
import org.t2framework.t2.annotation.core.ActionPath;
import org.t2framework.t2.annotation.core.Default;
import org.t2framework.t2.annotation.core.Page;
import org.t2framework.t2.annotation.core.RequestParam;
import org.t2framework.t2.contexts.WebContext;
import org.t2framework.t2.navigation.Forward;
import org.t2framework.t2.navigation.NoOperation;
import org.t2framework.t2.navigation.Redirect;
import org.t2framework.t2.spi.Navigation;

/**
 * OpenID verification with T2 using openid4java.
 * 
 * @author shot
 * 
 */
@RequestScope
@Page("/openid")
public class OpenIdPage {

	protected static Logger logger = Logger.getLogger(OpenIdPage.class);

	@Default
	public Navigation index(WebContext context) throws ConsumerException {
		try {
			ConsumerManager manager = new ConsumerManager();
			context.getSession().setAttribute("manager", manager);
			return Forward.to("/jsp/openid.jsp");
		} catch (ConsumerException ex) {
			throw ex;
		}
	}

	@POST
	@ActionParam("login")
	@SuppressWarnings("unchecked")
	public Navigation authenticateRequest(WebContext context,
			HttpServletRequest request, HttpServletResponse response,
			@RequestParam("identifier") String identifier)
			throws OpenIDException, IOException {
		logger.debug("identifier:" + identifier);
		ConsumerManager manager = context.getSession().getAttribute("manager");
		String returnToUrl = request.getRequestURL().append("/accept")
				.toString();

		List discoveries = manager.discover(identifier);

		DiscoveryInformation discovered = manager.associate(discoveries);

		request.getSession().setAttribute("openid-disc", discovered);

		AuthRequest authReq = manager.authenticate(discovered, returnToUrl);

		FetchRequest fetch = setupFetchRequest(request);
		authReq.addExtension(fetch);

		if (discovered.isVersion2() == false) {
			final String path = authReq.getDestinationUrl(true);
			return Redirect.toOuterUrl(path);
		} else {
			return NoOperation.noOp();
		}
	}

	protected FetchRequest setupFetchRequest(final HttpServletRequest request) {
		FetchRequest fetch = FetchRequest.createFetchRequest();
		if ("1".equals(request.getParameter("nickname"))) {
			fetch.addAttribute("nickname",
					"http://schema.openid.net/contact/nickname", true);
		}
		return fetch;
	}

	@GET
	@ActionPath
	public Navigation accept(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		logger.debug("------------------------");
		Identifier identifier = null;
		try {
			identifier = this.verifyResponse(req);
		} catch (OpenIDException ex) {
			logger.debug(ex.getMessage());
		}
		logger.debug("identifier: " + identifier);
		if (identifier == null) {
			return Forward.to("/jsp/openid.jsp");
		} else {
			req.setAttribute("identifier", identifier.getIdentifier());
			return Forward.to("/jsp/openidResult.jsp");
		}
	}

	@SuppressWarnings("unchecked")
	protected Identifier verifyResponse(HttpServletRequest request)
			throws OpenIDException {
		ConsumerManager manager = (ConsumerManager) request.getSession()
				.getAttribute("manager");
		ParameterList response = new ParameterList(request.getParameterMap());

		DiscoveryInformation discovered = (DiscoveryInformation) request
				.getSession().getAttribute("openid-disc");

		StringBuffer buf = request.getRequestURL();
		String queryString = request.getQueryString();
		if (queryString != null && queryString.length() > 0) {
			buf.append("?").append(request.getQueryString());
		}
		String receivingUrl = new String(buf);
		VerificationResult verification = manager.verify(receivingUrl,
				response, discovered);

		Identifier verified = verification.getVerifiedId();
		if (verified == null) {
			logger.debug("verified is null(url:{}, verification:{}).",
					new Object[] { receivingUrl, verification });
			return null;
		} else {
			AuthSuccess authSuccess = (AuthSuccess) verification
					.getAuthResponse();
			if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
				FetchResponse fetchResp = (FetchResponse) authSuccess
						.getExtension(AxMessage.OPENID_NS_AX);
				List<String> emails = fetchResp.getAttributeValues("email");
				String email = emails.get(0);
				logger.debug("email:" + email);
				List<String> aliases = fetchResp.getAttributeAliases();
				for (Iterator<String> iter = aliases.iterator(); iter.hasNext();) {
					String alias = iter.next();
					List values = fetchResp.getAttributeValues(alias);
					if (values.size() > 0) {
						logger.debug(alias + " : " + values.get(0));
						request.setAttribute(alias, values.get(0));
					}
				}
			}
			return verified;
		}
	}
}