/* * Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved. * * 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.entando.entando.plugins.jpoauthclient.aps.system.services.client; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.MediaType; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import net.oauth.OAuth; import net.oauth.OAuthAccessor; import net.oauth.OAuthConsumer; import net.oauth.OAuthException; import net.oauth.OAuthMessage; import net.oauth.OAuthProblemException; import net.oauth.OAuthServiceProvider; import net.oauth.ParameterStyle; import net.oauth.server.HttpRequestMessage; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.util.URIUtil; import org.entando.entando.aps.system.services.api.model.ApiMethod; import org.entando.entando.aps.system.services.api.model.StringApiResponse; import org.entando.entando.aps.system.services.api.provider.json.JSONProvider; import org.entando.entando.aps.system.services.api.server.ApiRestStatusServer; import org.entando.entando.plugins.jpoauthclient.aps.oauth.client.OAuthClient; import org.entando.entando.plugins.jpoauthclient.aps.servlet.Callback; import org.entando.entando.plugins.jpoauthclient.aps.system.ConsumerSystemConstants; import org.entando.entando.plugins.jpoauthclient.aps.system.CookieMap; import org.entando.entando.plugins.jpoauthclient.aps.system.OAuthClientException; import org.entando.entando.plugins.jpoauthclient.aps.system.RedirectException; import org.entando.entando.plugins.jpoauthclient.aps.system.httpclient.OAuthHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.ServletContextAware; import com.agiletec.aps.system.common.AbstractService; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.baseconfig.ConfigInterface; import org.apache.commons.io.IOUtils; /** * @author E.Santoboni */ public class ProviderConnectionManager extends AbstractService implements IProviderConnectionManager, ServletContextAware { private static final Logger _logger = LoggerFactory.getLogger(ProviderConnectionManager.class); @Override public void init() throws Exception { this.loadDefaultConsumer(); _logger.debug("{} ready", this.getClass().getName()); } @Override protected void release() { this._consumers.clear(); super.release(); } protected void loadDefaultConsumer() throws Exception { InputStream is = null; try { is = this.getServletContext().getResourceAsStream("/WEB-INF/plugins/jpoauthclient/oauth_consumer.properties"); Properties properties = new Properties(); properties.load(is); String base = this.getConfigManager().getParam(ConsumerSystemConstants.ENTANDO_SERVICE_PROVIDER_BASE_URL_PARAM_NAME); URL baseURL = (base == null) ? null : new URL(base); if (null == baseURL) return; String requestTokenURL = this.getURL(baseURL, properties, ConsumerSystemConstants.ENTANDO_SERVICE_PROVIDER_REQ_TOKEN_URL_PARAM_NAME); String userAuthorizationURL = this.getURL(baseURL, properties, ConsumerSystemConstants.ENTANDO_SERVICE_PROVIDER_AUTH_URL_PARAM_NAME); String accessTokenURL = this.getURL(baseURL, properties, ConsumerSystemConstants.ENTANDO_SERVICE_PROVIDER_ACCESS_TOKEN_URL_PARAM_NAME); if (null == requestTokenURL || null == userAuthorizationURL || null == accessTokenURL) return; OAuthServiceProvider serviceProvider = new OAuthServiceProvider(requestTokenURL, userAuthorizationURL, accessTokenURL); OAuthConsumer consumer = new OAuthConsumer(this.getConfigManager().getParam(ConsumerSystemConstants.CONSUMER_CALLBACK_URL_PARAM_NAME), this.getConfigManager().getParam(ConsumerSystemConstants.CONSUMER_KEY_PARAM_NAME), this.getConfigManager().getParam(ConsumerSystemConstants.CONSUMER_SECRET_PARAM_NAME), serviceProvider); consumer.setProperty("name", ConsumerSystemConstants.DEFAULT_CONSUMER_NAME); if (baseURL != null) { consumer.setProperty("serviceProvider.baseURL", baseURL); } this._consumers.put(ConsumerSystemConstants.DEFAULT_CONSUMER_NAME, consumer); } catch (Throwable t) { _logger.error("Error extracting default consumer", t); } finally { if (null != is) { is.close(); } } } private String getURL(URL baseUrl, Properties properties, String pathParamName) throws MalformedURLException { String path = properties.getProperty(pathParamName); if (null == baseUrl || null == path) return null; return (new URL(baseUrl, path)).toExternalForm(); } @Override public InputStream invokeApiMethod(ApiMethodRequestBean bean, HttpServletRequest request, HttpServletResponse response, boolean handleException) throws RedirectException, Exception { return this.invokeApiMethod(bean, request, response, handleException, true); } @Override public InputStream invokeApiMethod(ApiMethodRequestBean bean, HttpServletRequest request, HttpServletResponse response, boolean handleException, boolean redirectOAuthErrorPage) throws RedirectException, Exception { InputStream stream = null; try { this.checkConsumer(bean); Boolean free = this.checkMethod(bean); if (null == free) return null; ApiMethod.HttpMethod method = bean.getHttpMethod(); if (free) { if (method.equals(ApiMethod.HttpMethod.GET) || method.equals(ApiMethod.HttpMethod.DELETE)) { stream = this.invokeFreeGetDeleteApi(bean, handleException); } else { stream = this.invokeFreePostPutApi(bean, handleException); } } else { if (method.equals(ApiMethod.HttpMethod.GET) || method.equals(ApiMethod.HttpMethod.DELETE)) { stream = this.invokeProtectedGetDeleteApi(bean, request, response, handleException, redirectOAuthErrorPage); } else { stream = this.invokeProtectedPostPutApi(bean, request, response, handleException, redirectOAuthErrorPage); } } } catch (OAuthClientException ume) { if (handleException) { throw ume; } } catch (RedirectException re) { if (handleException) { throw re; } } catch (Exception t) { if (handleException) { _logger.error("Error invoking api method", t); throw t; } } return stream; } @Override public Object extractApiMethodResult(ApiMethodRequestBean bean, Class expectedType, HttpServletRequest request, HttpServletResponse response, boolean handleException) throws RedirectException, Exception { return this.extractApiMethodResult(bean, expectedType, request, response, handleException, true); } @Override public Object extractApiMethodResult(ApiMethodRequestBean bean, Class expectedType, HttpServletRequest request, HttpServletResponse response, boolean handleException, boolean redirectOAuthErrorPage) throws RedirectException, Exception { Object bodyObject = null; try { InputStream stream = this.invokeApiMethod(bean, request, response, handleException, redirectOAuthErrorPage); if (null == stream) return null; bodyObject = this.unmarshallResponse(stream, expectedType, bean.getMediaType()); } catch (OAuthClientException ume) { if (handleException) { throw ume; } } catch (RedirectException re) { if (handleException) { throw re; } } catch (Exception t) { if (handleException) { _logger.error("Error extracting result", t); throw t; } } return bodyObject; } private void checkConsumer(ApiMethodRequestBean bean) throws OAuthClientException, ApsSystemException { try { if (null != bean.getConsumerName()) { if (null == this.getConsumer(bean.getConsumerName())) { throw new OAuthClientException("Null consumer : " + bean.getConsumerName(), OAuthClientException.ErrorCode.NULL_CONSUMER); } else return; } else if (null != bean.getRequestUrl()) { Iterator<OAuthConsumer> consumers = this._consumers.values().iterator(); while (consumers.hasNext()) { OAuthConsumer oauthConsumer = consumers.next(); String baseUrl = ((URL) oauthConsumer.getProperty("serviceProvider.baseURL")).toExternalForm(); if (bean.getRequestUrl().startsWith(baseUrl)) { String name = (String) oauthConsumer.getProperty("name"); bean.setConsumerName(name); } } if (null == bean.getConsumerName()) { throw new OAuthClientException("Null consumer for url : " + bean.getRequestUrl(), OAuthClientException.ErrorCode.NULL_CONSUMER); } } else { throw new OAuthClientException("Null consumer", OAuthClientException.ErrorCode.NULL_CONSUMER); } } catch (OAuthClientException t) { throw t; } catch (Throwable t) { _logger.error("Error executing Check consumer", t); String message = "Error executing Check consumer"; throw new ApsSystemException(message, t); } } private Boolean checkMethod(ApiMethodRequestBean bean) throws OAuthClientException, ApsSystemException { Boolean free = null; String url = null; try { OAuthConsumer consumer = this.getConsumer(bean.getConsumerName()); if (null == consumer) { throw new OAuthClientException("Null consumer : " + bean.getConsumerName(), OAuthClientException.ErrorCode.NULL_CONSUMER); } URL baseURL = (URL) consumer.getProperty("serviceProvider.baseURL"); url = baseURL.toString(); if (!url.endsWith("/")) url += "/"; url += "api/apistatus/"; if (bean.getNamespace() != null && bean.getNamespace().trim().length() > 0) { url += bean.getNamespace() + "/"; } url += bean.getResourceName() + "/" + bean.getHttpMethod().toString() + "/.json"; String methodResult = this.invokeGetDeleteMethod(url, true, null); InputStream stream = new ByteArrayInputStream(methodResult.getBytes());//method.getResponseBodyAsStream(); StringApiResponse response = (StringApiResponse) this.unmarshallResponse(stream, StringApiResponse.class, MediaType.APPLICATION_JSON_TYPE); String result = response.getResult(); if (null != result && result.equalsIgnoreCase(ApiRestStatusServer.ApiStatus.INACTIVE.toString())) { throw new OAuthClientException(url, bean.getHttpMethod()); } free = (null != result && result.equalsIgnoreCase(ApiRestStatusServer.ApiStatus.FREE.toString())); } catch (OAuthClientException t) { throw t; } catch (Throwable t) { _logger.error("Error executing Check for method for uri '{}' - method '{}'",url, bean.getHttpMethod(), t); String message = "Error executing Check for method for uri '" + url + "' - method " + bean.getHttpMethod(); throw new ApsSystemException(message, t); } return free; } private Object unmarshallResponse(InputStream stream, Class expectedType, MediaType responseType) { Object bodyObject = null; try { if (responseType.equals(MediaType.APPLICATION_JSON_TYPE)) { JSONProvider jsonProvider = new JSONProvider(); bodyObject = jsonProvider.readFrom(expectedType, expectedType.getGenericSuperclass(), expectedType.getAnnotations(), MediaType.APPLICATION_JSON_TYPE, null, stream); } else { JAXBContext context = JAXBContext.newInstance(expectedType); Unmarshaller unmarshaller = context.createUnmarshaller(); bodyObject = (Object) unmarshaller.unmarshal(stream); } } catch (Throwable t) { _logger.error("Error unmarshalling response result", t); } return bodyObject; } private InputStream invokeFreeGetDeleteApi(ApiMethodRequestBean bean, boolean handleException) throws Exception { InputStream stream = null; try { String url = this.buildApiMethodUri(bean); boolean isGetMethod = ApiMethod.HttpMethod.GET.equals(bean.getHttpMethod()); String methodResult = this.invokeGetDeleteMethod(url, isGetMethod, bean.getRequestParameters()); stream = new ByteArrayInputStream(methodResult.getBytes()); } catch (Throwable t) { _logger.error("Error invoking Free Api", t); if (handleException) { throw new Exception("Error invoking Free Api", t); } } return stream; } private InputStream invokeFreePostPutApi(ApiMethodRequestBean bean, boolean handleException) throws Exception { InputStream stream = null; try { String url = this.buildApiMethodUri(bean); boolean isPostMethod = ApiMethod.HttpMethod.POST.equals(bean.getHttpMethod()); MediaType bodyMediaType = (null != bean.getRequestBodyMediaType()) ? bean.getRequestBodyMediaType() : MediaType.APPLICATION_JSON_TYPE; String methodResult = this.invokePostPutMethod(url, isPostMethod, bean.getRequestBody(), bean.getRequestParameters(), bodyMediaType); stream = new ByteArrayInputStream(methodResult.getBytes()); } catch (Throwable t) { _logger.error("Error invoking Free Api", t); if (handleException) { throw new Exception("Error invoking Free Api", t); } } return stream; } private String buildApiMethodUri(ApiMethodRequestBean bean) throws Throwable { OAuthConsumer consumer = this.getConsumer(bean.getConsumerName()); if (null == consumer) return null; URL baseURL = (URL) consumer.getProperty("serviceProvider.baseURL"); String url = baseURL.toString(); String path = bean.getPath(); if (!url.endsWith("/") && !path.startsWith("/")) url += "/"; url += path; return url; } private String invokeGetDeleteMethod(String url, boolean isGet, Properties parameters) throws Throwable { String result = null; HttpMethodBase method = null; InputStream inputStream = null; try { HttpClient client = new HttpClient(); if (isGet) { method = new GetMethod(url); } else { method = new DeleteMethod(url); } this.addQueryString(method, parameters); client.executeMethod(method); inputStream = method.getResponseBodyAsStream(); result = IOUtils.toString(inputStream, "UTF-8"); //byte[] responseBody = method.getResponseBody(); //result = new String(responseBody); } catch (Throwable t) { _logger.error("Error invoking Get or Delete Method", t); } finally { if (null != inputStream) { inputStream.close(); } if (null != method) { method.releaseConnection(); } } return result; } private String invokePostPutMethod(String url, boolean isPost, String body, Properties parameters, MediaType mediaType) { String result = null; EntityEnclosingMethod method = null; try { HttpClient client = new HttpClient(); if (isPost) { method = new PostMethod(url); } else { method = new PutMethod(url); } this.addQueryString(method, parameters); method.setRequestBody(body); method.setRequestHeader("Content-type", mediaType.toString() + "; charset=UTF-8"); client.executeMethod(method); byte[] responseBody = method.getResponseBody(); result = new String(responseBody); } catch (Throwable t) { _logger.error("Error invoking Post or put Method", t); } finally { if (null != method) { method.releaseConnection(); } } return result; } private void addQueryString(HttpMethodBase method, Properties parameters) throws Throwable { if (null == parameters) return; StringBuilder builder = new StringBuilder(); boolean first = true; Iterator<Object> keyIter = parameters.keySet().iterator(); while (keyIter.hasNext()) { Object key = keyIter.next(); if (!first) builder.append("&"); builder.append(key.toString()).append("=").append(parameters.getProperty(key.toString())); if (first) first = false; } method.setQueryString(URIUtil.encodeQuery(builder.toString())); } private InputStream invokeProtectedGetDeleteApi(ApiMethodRequestBean bean, HttpServletRequest request, HttpServletResponse response, boolean handleException, boolean redirectOAuthErrorPage) throws RedirectException, Exception { InputStream stream = null; OAuthConsumer consumer = null; try { consumer = this.getConsumer(bean.getConsumerName()); OAuthAccessor accessor = this.getAccessor(bean, request, response, consumer); Collection<OAuth.Parameter> parameters = HttpRequestMessage.getParameters(request); if (null != bean.getRequestParameters()) { Iterator<Object> iter = bean.getRequestParameters().keySet().iterator(); while (iter.hasNext()) { String paramKey = iter.next().toString(); parameters.add(new OAuth.Parameter(paramKey, bean.getRequestParameters().getProperty(paramKey))); } } URL baseURL = (URL) accessor.consumer.getProperty("serviceProvider.baseURL"); String url = new URL(baseURL, bean.getPath()).toExternalForm(); OAuthMessage oauthRequest = accessor.newRequestMessage(String.valueOf(bean.getHttpMethod()), url, parameters); OAuthClient client = new OAuthClient(new OAuthHttpClient()); OAuthMessage oauthResponse = client.invoke(oauthRequest, ParameterStyle.AUTHORIZATION_HEADER, redirectOAuthErrorPage); stream = oauthResponse.getBodyAsStream(); } catch (RedirectException re) { if (handleException) { this.handleException(bean, re, request, response, consumer, true); throw re; } } catch (OAuthProblemException oae) { if (handleException) { this.handleException(bean, oae, request, response, consumer, redirectOAuthErrorPage); throw oae; } } catch (Throwable t) { _logger.error("Error invoking api method", t); if (handleException) { throw new Exception("Error invoking api method", t); } } return stream; } private InputStream invokeProtectedPostPutApi(ApiMethodRequestBean bean, HttpServletRequest request, HttpServletResponse response, boolean handleException, boolean redirectOAuthErrorPage) throws RedirectException, Exception { InputStream stream = null; OAuthConsumer consumer = null; try { consumer = this.getConsumer(bean.getConsumerName()); OAuthAccessor accessor = this.getAccessor(bean, request, response, consumer); Collection<OAuth.Parameter> parameters = HttpRequestMessage.getParameters(request); if (null != bean.getRequestParameters()) { Iterator<Object> iter = bean.getRequestParameters().keySet().iterator(); while (iter.hasNext()) { String paramKey = iter.next().toString(); parameters.add(new OAuth.Parameter(paramKey, bean.getRequestParameters().getProperty(paramKey))); } } URL baseURL = (URL) accessor.consumer.getProperty("serviceProvider.baseURL"); String url = new URL(baseURL, bean.getPath()).toExternalForm(); InputStream streamRequest = new ByteArrayInputStream(bean.getRequestBody().getBytes("UTF-8")); OAuthMessage oauthRequest = accessor.newRequestMessage(String.valueOf(bean.getHttpMethod()), url, parameters, streamRequest); OAuthClient client = new OAuthClient(new OAuthHttpClient()); OAuthMessage oauthResponse = client.invoke(oauthRequest, ParameterStyle.AUTHORIZATION_HEADER, redirectOAuthErrorPage); stream = oauthResponse.getBodyAsStream(); } catch (RedirectException re) { if (handleException) { this.handleException(bean, re, request, response, consumer, true); throw re; } } catch (OAuthProblemException oae) { if (handleException) { this.handleException(bean, oae, request, response, consumer, redirectOAuthErrorPage); throw oae; } } catch (Throwable t) { _logger.error("Error invoking api method", t); if (handleException) { throw new Exception("Error invoking api method", t); } } return stream; } @Override public OAuthConsumer getConsumer(String name) throws IOException { return this._consumers.get(name); } /** * Get the access token and token secret for the given consumer. Get them * from cookies if possible; otherwise obtain them from the service * provider. In the latter case, throw RedirectException. * @throws IOException * @throws URISyntaxException */ private OAuthAccessor getAccessor(ApiMethodRequestBean bean, HttpServletRequest request, HttpServletResponse response, OAuthConsumer consumer) throws OAuthException, IOException, URISyntaxException { OAuthAccessor accessor = null; CookieMap cookies = new CookieMap(request, response); accessor = this.newAccessor(consumer, cookies); if (accessor.accessToken == null) { this.getAccessToken(bean, request, cookies, accessor); } return accessor; } /** * Construct an accessor from cookies. The resulting accessor won't * necessarily have any tokens. */ @Override public OAuthAccessor newAccessor(OAuthConsumer consumer, CookieMap cookies) throws OAuthException { OAuthAccessor accessor = new OAuthAccessor(consumer); String consumerName = (String) consumer.getProperty("name"); accessor.requestToken = cookies.get(consumerName + ".requestToken"); accessor.accessToken = cookies.get(consumerName + ".accessToken"); accessor.tokenSecret = cookies.get(consumerName + ".tokenSecret"); return accessor; } /** Remove all the cookies that contain accessors' data. */ @Override public void removeAccessors(CookieMap cookies) { List<String> names = new ArrayList<String>(cookies.keySet()); for (int i = 0; i < names.size(); i++) { String name = names.get(i); if (name.endsWith(".requestToken") || name.endsWith(".accessToken") || name.endsWith(".tokenSecret")) { cookies.remove(name); } } } /** * Get a fresh access token from the service provider. * @throws IOException * @throws URISyntaxException * @throws RedirectException to obtain authorization */ private void getAccessToken(ApiMethodRequestBean bean, HttpServletRequest request, CookieMap cookies, OAuthAccessor accessor) throws OAuthException, IOException, URISyntaxException { final String consumerName = (String) accessor.consumer.getProperty("name"); final String callbackURL = getCallbackURL(bean, request); List<OAuth.Parameter> parameters = OAuth.newList(OAuth.OAUTH_CALLBACK, callbackURL); // Google needs to know what you intend to do with the access token: Object scope = accessor.consumer.getProperty("request.scope"); if (scope != null) { parameters.add(new OAuth.Parameter("scope", scope.toString())); } OAuthClient client = new OAuthClient(new OAuthHttpClient()); OAuthMessage response = client.getRequestTokenResponse(accessor, null, parameters); cookies.put(consumerName + ".requestToken", accessor.requestToken); cookies.put(consumerName + ".tokenSecret", accessor.tokenSecret); String authorizationURL = accessor.consumer.serviceProvider.userAuthorizationURL; if (authorizationURL.startsWith("/")) { authorizationURL = (new URL(new URL(request.getRequestURL().toString()), request.getContextPath() + authorizationURL)).toString(); } authorizationURL = OAuth.addParameters(authorizationURL, OAuth.OAUTH_TOKEN, accessor.requestToken); if (response.getParameter(OAuth.OAUTH_CALLBACK_CONFIRMED) == null) { authorizationURL = OAuth.addParameters(authorizationURL, OAuth.OAUTH_CALLBACK, callbackURL); } throw new RedirectException(authorizationURL); } private String getCallbackURL(ApiMethodRequestBean bean, HttpServletRequest request) throws IOException { URL base = new URL(new URL(request.getRequestURL().toString()), request.getContextPath() + Callback.PATH); String returnTo = (null != bean && null != bean.getRedirectUrl()) ? bean.getRedirectUrl() : this.getRequestPath(request); return OAuth.addParameters(base.toExternalForm(), "consumer", bean.getConsumerName(), "returnTo", returnTo); } /** Reconstruct the requested URL path, complete with query string (if any). */ private String getRequestPath(HttpServletRequest request) throws MalformedURLException { StringBuilder path = new StringBuilder(request.getRequestURL()); String queryString = request.getQueryString();//url.getQuery(); if (queryString != null) { path.append("?").append(queryString); } String pathToReturn = path.toString(); return pathToReturn; } @Override public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response, OAuthConsumer consumer) throws IOException, ServletException { this.handleException(null, e, request, response, consumer, true); } /** * Handle an exception that occurred while processing an HTTP request. * Depending on the exception, either send a response, redirect the client * or propagate an exception. */ public void handleException(ApiMethodRequestBean bean, Exception e, HttpServletRequest request, HttpServletResponse response, OAuthConsumer consumer, boolean redirectOAuthErrorPage) throws IOException, ServletException { if (e instanceof RedirectException) { RedirectException redirect = (RedirectException) e; String targetURL = redirect.getTargetURL(); if (targetURL != null) { response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", targetURL); } } else if (e instanceof OAuthProblemException) { OAuthProblemException p = (OAuthProblemException) e; String problem = p.getProblem(); List<String> recoverableProblems = Arrays.asList(RECOVERABLE_PROBLEMS); if (consumer != null && recoverableProblems.contains(problem)) { try { CookieMap cookies = new CookieMap(request, response); OAuthAccessor accessor = this.newAccessor(consumer, cookies); this.getAccessToken(bean, request, cookies, accessor); } catch (Exception e2) { handleException(bean, e2, request, response, null, redirectOAuthErrorPage); } } else if (redirectOAuthErrorPage) { try { StringWriter s = new StringWriter(); PrintWriter pw = new PrintWriter(s); e.printStackTrace(pw); pw.flush(); p.setParameter("stack trace", s.toString()); } catch (Exception rats) { //nothing to catch } response.setStatus(p.getHttpStatusCode()); response.resetBuffer(); request.setAttribute("OAuthProblemException", p); request.getRequestDispatcher("/WEB-INF/plugins/jpoauthclient/OAuthProblemException.jsp").forward(request, response); } } else if (e instanceof IOException) { throw (IOException) e; } else if (e instanceof ServletException) { throw (ServletException) e; } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new ServletException(e); } } protected ServletContext getServletContext() { return _servletContext; } @Override public void setServletContext(ServletContext servletContext) { this._servletContext = servletContext; } protected ConfigInterface getConfigManager() { return _configManager; } public void setConfigManager(ConfigInterface configManager) { this._configManager = configManager; } private ServletContext _servletContext; private ConfigInterface _configManager; private Map<String, OAuthConsumer> _consumers = new HashMap<String, OAuthConsumer>(); private static final String[] RECOVERABLE_PROBLEMS = new String[]{"token_revoked", "token_expired", "permission_unknown"}; }