package org.qrone.login; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.openid4java.OpenIDException; 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.qrone.kvs.KeyValueStore; import org.qrone.kvs.KeyValueStoreService; import org.qrone.r7.handler.URIHandler; import org.qrone.r7.script.browser.User; import org.qrone.util.QrONEUtils; import org.qrone.util.QueryString; import org.qrone.util.Serialization; public class LoginHandler implements URIHandler, LoginService{ private ConsumerManager manager; private KeyValueStore store; public LoginHandler(KeyValueStoreService service) { this.store = service.getKeyValueStore("qrone.openid"); } @Override public boolean handle(HttpServletRequest request, HttpServletResponse response, String uri, String path, String pathArg, List<String> arg) { if(path.equals("/system/openid/login")){ handleOpenIDLogin(request, response); }else if(path.equals("/system/openid/verify")){ handleOpenIDVerify(request, response); }else if(path.equals("/system/logout")){ handleLogout(request, response); } return false; } public String getOpenIDLoginURL(String url, Map attrMap, String doneURL){ LoginPack pack = new LoginPack(); pack.url = url; pack.attributes = attrMap; return "/system/openid/login?pack=" + QrONEUtils.packEQ64(pack) + "&.done=" + QrONEUtils.escape(doneURL); } public String getLoginURL(String doneURL){ return "/system/login?.done=" + QrONEUtils.escape(doneURL); } public String getLogoutURL(String doneURL){ return "/system/logout?.done=" + QrONEUtils.escape(doneURL); } private boolean handleLogout(HttpServletRequest req, HttpServletResponse res){ User user = (User)req.getAttribute("User"); user.logout(); return false; } /* public String openid_login_url(String url, Scriptable attributes, String doneURL){ Map<String, String> attrMap = new HashMap<String, String>(); if(attributes != null){ Object[] ids = attributes.getIds(); for (int i = 0; i < ids.length; i++) { if(ids[i] instanceof String){ Object v = attributes.get((String)ids[i], attributes); if(v instanceof String){ attrMap.put((String)ids[i], (String)v); } } } } return loginURL(url, attrMap, doneURL); } */ /* private String getBaseURL(HttpServletRequest req){ int port = req.getServerPort(); if(port == 80) return "http://" + req.getServerName() + "/openid"; else return "http://" + req.getServerName() + ":" + port + "/openid"; } */ private boolean handleOpenIDLogin(HttpServletRequest req, HttpServletResponse res){ try{ User user = (User)req.getAttribute("User"); LoginPack pack = (LoginPack)QrONEUtils.unpackEQ64(LoginPack.class, req.getParameter("pack")); String url = pack.url; Map<String, String> attributes = pack.attributes; if(manager == null){ manager = new ConsumerManager(); } URI reqURL = new URI(req.getRequestURL().toString()).resolve("/system/openid"); List discoveries = manager.discover(url); DiscoveryInformation discovered = manager.associate(discoveries); AuthRequest authReq = manager.authenticate(discovered, reqURL.toString() + "/verify?.done=" + QrONEUtils.escape(req.getParameter(".done"))); FetchRequest fetch = FetchRequest.createFetchRequest(); store.set("openid-discover:" + user.getBrowserId(), Serialization.serialize(discovered), true); for (Iterator<Entry<String, String>> i = attributes.entrySet().iterator(); i .hasNext();) { Entry<String, String> e = i.next(); fetch.addAttribute(e.getKey(), e.getValue(), true); } authReq.addExtension(fetch); res.sendRedirect(authReq.getDestinationUrl(true)); return true; }catch (OpenIDException e){ e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (URISyntaxException e) { e.printStackTrace(); } return false; } // --- processing the authentication response --- private boolean handleOpenIDVerify(HttpServletRequest req, HttpServletResponse res) { try{ User user = (User)req.getAttribute("User"); ParameterList response = new ParameterList(req.getParameterMap()); DiscoveryInformation discovered = (DiscoveryInformation)Serialization.unserialize((byte[])store.get("openid-discover:" + user.getBrowserId())); StringBuffer receivingURL = req.getRequestURL(); String queryString = req.getQueryString(); if (queryString != null && queryString.length() > 0) receivingURL.append("?").append(req.getQueryString()); VerificationResult verification = manager.verify( receivingURL.toString(), response, discovered); Identifier verified = verification.getVerifiedId(); if (verified != null) { AuthSuccess authSuccess = (AuthSuccess) verification.getAuthResponse(); String name = null; if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) { FetchResponse fetchResp = (FetchResponse) authSuccess .getExtension(AxMessage.OPENID_NS_AX); if(name == null) name = fetchResp.getAttributeValue("login"); } user.openidLogin(verified, authSuccess); res.sendRedirect(req.getParameter(".done")); return true; } }catch (OpenIDException e){ e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } public static class LoginPack implements Serializable, Externalizable{ private static final long serialVersionUID = 7001446077656573040L; public String url; public Map<String, String> attributes; @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { url = in.readUTF(); attributes = new HashMap<String, String>(); int c = in.readInt(); for (int i = 0; i < c; i++) { String k = in.readUTF(); String v = in.readUTF(); attributes.put(k, v); } } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(url); out.writeInt(attributes.size()); for (Iterator<Entry<String, String>> i = attributes.entrySet().iterator(); i .hasNext();) { Entry<String, String> e = i.next(); out.writeUTF(e.getKey()); out.writeUTF(e.getValue()); } } } }