openid4javaを試すなど
ファイルの配置
EclipseでTomcatプロジェクト作って、以下のように配置します。
OpenIDTest │ index.jsp │ index2.jsp │ ├─src │ LoginWithGoogle.java │ └─WEB-INF │ web.xml │ ├─classes │ LoginWithGoogle.class │ └─lib commons-codec-1.3.jar commons-logging-1.03.jar guice-2.0.jar httpclient-4.0.jar httpcore-4.0.1.jar nekohtml-1.9.14.jar openid4java-0.9.6.jar xercesImpl-2.8.1.jar
web.xml
/openidっていうパスに、LoginWithGoogleっていうクラスのServletを紐付けてるだけの、
超簡単web.xmlです。
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>LoginWithGoogle</servlet-name> <servlet-class>LoginWithGoogle</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginWithGoogle</servlet-name> <url-pattern>/openid</url-pattern> </servlet-mapping> </web-app>
index.jsp
OpenIDでログインするのに、サーブレットを呼び出します。
is_request=trueの意味は後述。
<a href = "/OpenIDTest/openid?is_request=true">login with Google</a>
LoginWithGoogle.java
import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; 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.ParameterList; public class LoginWithGoogle extends HttpServlet { public ConsumerManager manager; private String returnURL = "http://localhost:8080/OpenIDTest/openid"; public void init() { this.manager = new ConsumerManager(); } public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if ("true".equals(req.getParameter("is_request"))) { requestOpenId(req, res); } else { responseOpenId(req, res); } } public void requestOpenId(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { try { // perform discovery on the user-supplied identifier List discoveries = manager.discover("https://www.google.com/accounts/o8/id"); //List discoveries = manager.discover("http://yahoo.co.jp/"); // attempt to associate with the OpenID provider // and retrieve one service endpoint for authentication DiscoveryInformation discovered = manager.associate(discoveries); // store the discovery information in the user's session for later use // leave out for stateless operation / if there is no session HttpSession session = req.getSession(false); session.setAttribute("discovered", discovered); // obtain a AuthRequest message to be sent to the OpenID provider AuthRequest authReq = manager.authenticate(discovered, returnURL); res.sendRedirect(authReq.getDestinationUrl(true)); } catch (Exception e) { throw new ServletException(e); } } public void responseOpenId(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { try { // extract the parameters from the authentication response // (which comes in as a HTTP request from the OpenID provider) ParameterList openidResp = new ParameterList(req.getParameterMap()); // retrieve the previously stored discovery information HttpSession session = req.getSession(false); DiscoveryInformation discovered = (DiscoveryInformation) session .getAttribute("discovered"); // extract the receiving URL from the HTTP request StringBuffer receivingURL = req.getRequestURL(); String queryString = req.getQueryString(); if (queryString != null && queryString.length() > 0) receivingURL.append("?").append(req.getQueryString()); // verify the response VerificationResult verification = manager.verify( receivingURL.toString(), openidResp, discovered); // examine the verification result and extract the verified // identifier Identifier verified = verification.getVerifiedId(); if (verified != null) { // success, use the verified identifier to identify the user req.getRequestDispatcher("/index2.jsp").forward(req, res); } else { // OpenID authentication failed req.getRequestDispatcher("/index.jsp").forward(req, res); } } catch (Exception e) { throw new ServletException(e); } } }
init
ConsumerManagerを初期化しています。
doGet
is_requestパラメータがtrueの場合は、OpenID認証リクエストを行い、
そうでない場合は、OpenIDプロバイダ(GoogleとかYahoo)からの戻りのリクエストを処理します。
これらを同じサーブレットに押し込めたのは、
openid4javaの制約なのか、なんなのか、
ConsumerManagerは1インスタンスにすべきという制約のためです。
(参考)Direct signature verification failed. - OpenID4Java | Google グループ
requestOpenID
SampleConsumer - openid4javaのパクリ。
変えたのは、userSuppliedStringのところ。
ここを変えることで、Googleだったり、Yahoo Japanだったり、その他もろもろの
OpenIDに対応することができるらしい。
ちなみに、http://www.hatena.ne.jp/taka_2/を指定したら、
戻りのところでパラメータが足りないとか怒られて動きませんでした。
OpenID2.0対応じゃないから?
responseOpenId
起動
- http://localhost:8080/OpenIDTest/ にアクセスする
- login with Googleのリンクをクリックする
- (ログイン済みでなければ)ログイン画面が表示されるので、ログインする
- (初回のみ or 今回のみ許可なら次回も)GoogleのOpenID認証の画面になるので許可する
- 認証OKなら、戻りのリクエストが行われ、index2.jspが表示されるはず
課題
- ログインできなかったりする。やり直したらできたりする。
- 例えばGoogleのOpenIDを使った場合、Googleのメールアドレスとかは戻り側で取得できるの?
- Google Appsは、また違う方法でやるようだ。