/* * Juick * Copyright (C) 2008-2013, Ugnich Anton * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package com.juick.www; import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.server.UserQueries; import com.juick.www.facebook.Graph; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.UUID; /** * * @author Ugnich Anton */ public class FacebookLogin { private static final Logger logger = LoggerFactory.getLogger(FacebookLogin.class); private final String FACEBOOK_APPID; private final String FACEBOOK_SECRET; private final String FACEBOOK_REDIRECT = "http://juick.com/_fblogin"; private final ObjectMapper mapper; public FacebookLogin(String ApplicationID, String secret) { this.FACEBOOK_APPID = ApplicationID; this.FACEBOOK_SECRET = secret; mapper = new ObjectMapper(); } protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fbstate; String code = request.getParameter("code"); if (code == null || code.equals("")) { fbstate = UUID.randomUUID().toString(); Cookie c = new Cookie("fbstate", fbstate); response.addCookie(c); response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", "https://www.facebook.com/dialog/oauth?scope=publish_stream&client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, "utf-8") + "&state=" + fbstate); return; } fbstate = Utils.getCookie(request, "fbstate"); if (fbstate == null || fbstate.isEmpty() || !fbstate.equals(request.getParameter("state"))) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return; } else { Cookie c = new Cookie("fbstate", "-"); c.setMaxAge(0); response.addCookie(c); } String token = Utils.fetchURL("https://graph.facebook.com/oauth/access_token?client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, "utf-8") + "&client_secret=" + FACEBOOK_SECRET + "&code=" + URLEncoder.encode(code, "utf-8")); if (token == null || token.isEmpty() || !token.startsWith("access_token=")) { logger.error("FACEBOOK TOKEN ERROR: " + token); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } token = token.substring(13); // access_token=... int tokenamp = token.indexOf('&'); // &expires= if (tokenamp > 0) { token = token.substring(0, tokenamp); } String graph = Utils.fetchURL("https://graph.facebook.com/me?access_token=" + token); if (graph == null || graph.isEmpty()) { logger.error("FACEBOOK GRAPH ERROR"); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } try { Graph fb = mapper.readValue(graph, Graph.class); long fbID = NumberUtils.toLong(fb.getId(), 0); if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) { throw new Exception(); } int uid = getUIDbyFBID(sql, fbID); if (uid > 0) { if (!updateDB(sql, fbID, token, fb.getName(), fb.getLink())) { throw new Exception(); } Cookie c = new Cookie("hash", UserQueries.getHashByUID(sql, uid)); c.setMaxAge(50 * 24 * 60 * 60); response.addCookie(c); response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", "/"); } else if (fb.getVerified()) { String loginhash = UUID.randomUUID().toString(); if (!insertDB(sql, fbID, loginhash, token, fb.getName(), fb.getLink())) { throw new Exception(); } response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", "/signup?type=fb&hash=" + loginhash); } else { throw new Exception(); } } catch (Exception e) { logger.error("fb error", e); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } private int getUIDbyFBID(JdbcTemplate sql, long fbID) { try { return sql.queryForObject("SELECT user_id FROM facebook WHERE fb_id=? AND user_id IS NOT NULL", Integer.class, fbID); } catch (EmptyResultDataAccessException e) { return 0; } } private boolean insertDB(JdbcTemplate sql, long fbID, String loginhash, String token, String fbName, String fbLink) { return sql.update("INSERT INTO facebook(fb_id,loginhash,access_token,fb_name,fb_link) VALUES (?,?,?,?,?)", fbID, loginhash, token, fbName, fbLink) > 0; } private boolean updateDB(JdbcTemplate sql, long fbID, String token, String fbName, String fbLink) { return sql.update("UPDATE facebook SET access_token=?,fb_name=?,fb_link=? WHERE fb_id=?", token, fbName, fbLink, fbID) > 0; } }