package com.technicalrex.springsecurityjwt.auth.google;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.common.collect.Sets;
import com.technicalrex.springsecurityjwt.auth.XsrfUtils;
import com.technicalrex.springsecurityjwt.auth.jwt.TokenAuthenticationService;
import com.technicalrex.springsecurityjwt.auth.jwt.UserAuthentication;
import com.technicalrex.springsecurityjwt.auth.jwt.UserService;
import com.technicalrex.springsecurityjwt.config.AppConfig;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
import static org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext;
public class GoogleAuthorizationResponseServlet extends HttpServlet {
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String ERROR_URL_PARAM_NAME = "error";
private static final String CODE_URL_PARAM_NAME = "code";
public static final String URL_MAPPING = "/auth/google/response";
private AppConfig appConfig;
private XsrfUtils xsrfUtils;
private UserService userService;
private TokenAuthenticationService tokenAuthenticationService;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContext applicationContext = getRequiredWebApplicationContext(getServletContext());
appConfig = applicationContext.getBean(AppConfig.class);
xsrfUtils = applicationContext.getBean(XsrfUtils.class);
userService = applicationContext.getBean(UserService.class);
tokenAuthenticationService = applicationContext.getBean(TokenAuthenticationService.class);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Check for a valid XSRF token
String expectedToken = (String) request.getSession().getAttribute(XsrfUtils.XSRF_KEY);
String actualToken = request.getParameter("state");
if (!xsrfUtils.isValid(expectedToken, actualToken)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// Check for no errors in the OAuth process
String[] error = request.getParameterValues(ERROR_URL_PARAM_NAME);
if (error != null && error.length > 0) {
response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
return;
}
// Check for the presence of the response code
String[] code = request.getParameterValues(CODE_URL_PARAM_NAME);
if (code == null || code.length == 0) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// Get the email address
String requestUrl = getOAuthCodeCallbackHandlerUrl(request);
GoogleTokenResponse tokenResponse = exchangeCodeForAccessAndRefreshTokens(code[0], requestUrl);
String email = tokenResponse.parseIdToken().getPayload().getEmail();
String token = establishUserAndLogin(response, email);
request.setAttribute("email", email);
request.setAttribute("authToken", token);
getServletConfig().getServletContext().getRequestDispatcher("/home.jsp").forward(request,response);
}
private GoogleTokenResponse exchangeCodeForAccessAndRefreshTokens(String code, String currentUrl) throws IOException {
return new GoogleAuthorizationCodeTokenRequest(HTTP_TRANSPORT, JSON_FACTORY, appConfig.getGoogleClientId(),
appConfig.getGoogleClientSecret(), code, currentUrl).execute();
}
private static String getOAuthCodeCallbackHandlerUrl(HttpServletRequest request) {
String scheme = request.getScheme() + "://";
String serverName = request.getServerName();
String serverPort = request.getServerPort() == 80 ? "" : ":" + request.getServerPort();
String contextPath = request.getContextPath();
String servletPath = URL_MAPPING;
String pathInfo = request.getPathInfo() == null ? "" : request.getPathInfo();
return scheme + serverName + serverPort + contextPath + servletPath + pathInfo;
}
private String establishUserAndLogin(HttpServletResponse response, String email) {
// Find user, create if necessary
User user;
try {
user = userService.loadUserByUsername(email);
} catch (UsernameNotFoundException e) {
user = new User(email, UUID.randomUUID().toString(), Sets.<GrantedAuthority>newHashSet());
userService.addUser(user);
}
// Login that user
UserAuthentication authentication = new UserAuthentication(user);
return tokenAuthenticationService.addAuthentication(response, authentication);
}
}