All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.riversun.oauth2.google.OAuthCallbackServlet Maven / Gradle / Ivy

/*
 * 
 * Copyright 2016-2017 Tom Misawa, [email protected]
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in the 
 * Software without restriction, including without limitation the rights to use, 
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
 * Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 *  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 
 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */
package org.riversun.oauth2.google;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

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

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;

/**
 * Callback servlet for Google OAuth2 flow
*
* When you want to revoke permission from your application.
* {@link https://security.google.com/settings/security/permissions}
* * @author Tom Misawa ([email protected]) * */ @SuppressWarnings("serial") public abstract class OAuthCallbackServlet extends OAuthBaseServlet { private static final Logger LOGGER = Logger.getLogger(OAuthCallbackServlet.class.getName()); private final Map mTempRefreshTokenMap = new ConcurrentHashMap(); /** * Returns redirect url * * @return */ protected abstract String getAuthRedirectUrl(); /** * Save refreshToken of user.
*
* RefreshToken is recommended to be persistent rather than on - memory. * Override and implement this method and describe the saving process of * refreshToken.
* * @param userId * @param refreshToken */ protected void saveRefreshTokenFor(String userId, String refreshToken) { LOGGER.fine("userId=" + userId + " refreshToken=" + refreshToken); mTempRefreshTokenMap.put(userId, refreshToken); } /** * Load stored refreshToken of user.
*
*
* RefreshToken is recommended to be persistent rather than on - memory. * Override and implement this method and read refreshToken from the * persisted area.
* * @param userId * @return */ protected String loadRefreshTokenFor(String userId) { final String storedRefreshToken = mTempRefreshTokenMap.get(userId); final String refreshToken; if (storedRefreshToken == null) { refreshToken = "dummy_refresh_token"; } else { refreshToken = storedRefreshToken; } LOGGER.fine("userId=" + userId + " refreshToken=" + refreshToken); return refreshToken; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { LOGGER.fine(""); final String code = asString(req, "code"); final String stateToken = asString(req, "state"); if (code != null && stateToken != null) { // - required parameters( 'code' and 'state) are exist. LOGGER.fine("code=" + code); final String storedStateToken = (String) sessionScope(req, OAuthConst.SESSION_KEY_OAUTH2_STATE_TOKEN); if (storedStateToken != null && stateToken.equals(storedStateToken)) { // - stateToken matched LOGGER.fine("stateToken matched state=" + stateToken); // remove state token sessionScope(req, OAuthConst.SESSION_KEY_OAUTH2_STATE_TOKEN, null); } else { // - stateToken not matched LOGGER.warning("stateToken not matched!"); resp.sendError(HttpServletResponse.SC_FORBIDDEN, "OAuth2 state token is invalid. stateToken=" + stateToken + " storedStateToken=" + storedStateToken); return; } } else { // - required parameters not found LOGGER.warning("The parameter 'code' or 'state' not found!"); resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid parameters code=" + code + " state=" + stateToken); return; } final OAuthHandler oh = new OAuthHandler(getAuthRedirectUrl()); // Retrieve token response from "code" final GoogleTokenResponse tokenResponse = oh.getTokenResponseFromCode(code); LOGGER.fine("Received tokenResponse=" + tokenResponse); LOGGER.fine("Received refresh_token=" + tokenResponse.getRefreshToken()); // Parse idToken from tokenResponse final GoogleIdToken idToken = oh.getIdToken(tokenResponse); if (idToken == null) { throw new ServletException(new Exception("IdToken verification error")); } // idToken contains header,payload,signature. // Each value is stored in the format specified by RFC 7515 (JWS -JSON // Web Signature) final Payload payload = idToken.getPayload(); sessionScope(req, OAuthConst.SESSION_KEY_ID_TOKEN, idToken); // An identifier for the user, unique among all Google accounts and // never reused. final String userId = payload.getSubject(); sessionScope(req, OAuthConst.SESSION_KEY_UNIQUE_USER_ID, userId); LOGGER.fine("TOKEN_INFO subject(unique userId)=" + userId); // Get refresh_token from tokenResponse. // refresh_token can not be retrieved every time. // When accessing authorization code with access_type = "offline" , // refresh_token can be retrieved only at the first access. final String _refreshToken = tokenResponse.getRefreshToken(); if (_refreshToken != null) { // save new refreshToken saveRefreshTokenFor(userId, _refreshToken); } LOGGER.fine("use refresh token refreshToken=" + tokenResponse.getRefreshToken()); final String accessToken = tokenResponse.getAccessToken(); final GoogleCredential credential = new GoogleCredential.Builder() .setTransport(OAuthCommon.HTTP_TRANSPORT) .setJsonFactory(OAuthCommon.JSON_FACTORY) .setClientSecrets(OAuthCommon.getClientSecrets()) .build() .setAccessToken(accessToken) // If refreshToken is set, new access token will be // retrieved(renewed) properly // even if the old access token expires. .setRefreshToken(loadRefreshTokenFor(userId)); sessionScope(req, OAuthConst.SESSION_KEY_CREDENTIAL, credential); sessionScope(req, OAuthConst.SESSION_KEY_OAUTH2_DONE, Boolean.TRUE); String redirectPath = (String) sessionScope(req, OAuthConst.SESSION_KEY_REQUEST_URL); sessionScope(req, OAuthConst.SESSION_KEY_REQUEST_URL, null); if (redirectPath == null || redirectPath.isEmpty()) { redirectPath = req.getContextPath() + "/"; } LOGGER.fine("redirectPath=" + redirectPath); resp.sendRedirect(redirectPath); } @Override protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { sendNotSupportedError(req, resp); } @Override protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { sendNotSupportedError(req, resp); } @Override protected final void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { sendNotSupportedError(req, resp); } private final void sendNotSupportedError(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Not supported"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy