/** * Get the URL to which to redirect the user for authorization of protected resources. * * @param details The resource for which to get the authorization url. * @param requestToken The request token. * @param callbackURL The callback URL. * @return The URL. */ protected String getUserAuthorizationRedirectURL( ProtectedResourceDetails details, OAuthConsumerToken requestToken, String callbackURL) { try { String baseURL = details.getUserAuthorizationURL(); StringBuilder builder = new StringBuilder(baseURL); char appendChar = baseURL.indexOf('?') < 0 ? '?' : '&'; builder.append(appendChar).append("oauth_token="); builder.append(URLEncoder.encode(requestToken.getValue(), "UTF-8")); if (!details.isUse10a()) { builder.append('&').append("oauth_callback="); builder.append(URLEncoder.encode(callbackURL, "UTF-8")); } return builder.toString(); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } }
public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; OAuthSecurityContextImpl context = new OAuthSecurityContextImpl(); context.setDetails(request); Map<String, OAuthConsumerToken> rememberedTokens = getRememberMeServices().loadRememberedTokens(request, response); Map<String, OAuthConsumerToken> accessTokens = new TreeMap<String, OAuthConsumerToken>(); Map<String, OAuthConsumerToken> requestTokens = new TreeMap<String, OAuthConsumerToken>(); if (rememberedTokens != null) { for (Map.Entry<String, OAuthConsumerToken> tokenEntry : rememberedTokens.entrySet()) { OAuthConsumerToken token = tokenEntry.getValue(); if (token != null) { if (token.isAccessToken()) { accessTokens.put(tokenEntry.getKey(), token); } else { requestTokens.put(tokenEntry.getKey(), token); } } } } context.setAccessTokens(accessTokens); OAuthSecurityContextHolder.setContext(context); if (LOG.isDebugEnabled()) { LOG.debug( "Storing access tokens in request attribute '" + getAccessTokensRequestAttribute() + "'."); } try { try { request.setAttribute( getAccessTokensRequestAttribute(), new ArrayList<OAuthConsumerToken>(accessTokens.values())); chain.doFilter(request, response); } catch (Exception e) { try { ProtectedResourceDetails resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e); String neededResourceId = resourceThatNeedsAuthorization.getId(); while (!accessTokens.containsKey(neededResourceId)) { OAuthConsumerToken token = requestTokens.remove(neededResourceId); if (token == null) { token = getTokenServices().getToken(neededResourceId); } String verifier = request.getParameter(OAuthProviderParameter.oauth_verifier.toString()); // if the token is null OR // if there is NO access token and (we're not using 1.0a or the verifier is not null) if (token == null || (!token.isAccessToken() && (!resourceThatNeedsAuthorization.isUse10a() || verifier == null))) { // no token associated with the resource, start the oauth flow. // if there's a request token, but no verifier, we'll assume that a previous oauth // request failed and we need to get a new request token. if (LOG.isDebugEnabled()) { LOG.debug("Obtaining request token for resource: " + neededResourceId); } // obtain authorization. String callbackURL = response.encodeRedirectURL(getCallbackURL(request)); token = getConsumerSupport().getUnauthorizedRequestToken(neededResourceId, callbackURL); if (LOG.isDebugEnabled()) { LOG.debug("Request token obtained for resource " + neededResourceId + ": " + token); } // okay, we've got a request token, now we need to authorize it. requestTokens.put(neededResourceId, token); getTokenServices().storeToken(neededResourceId, token); String redirect = getUserAuthorizationRedirectURL( resourceThatNeedsAuthorization, token, callbackURL); if (LOG.isDebugEnabled()) { LOG.debug( "Redirecting request to " + redirect + " for user authorization of the request token for resource " + neededResourceId + "."); } request.setAttribute( "org.springframework.security.oauth.consumer.AccessTokenRequiredException", e); this.redirectStrategy.sendRedirect(request, response, redirect); return; } else if (!token.isAccessToken()) { // we have a presumably authorized request token, let's try to get an access token // with it. if (LOG.isDebugEnabled()) { LOG.debug("Obtaining access token for resource: " + neededResourceId); } // authorize the request token and store it. try { token = getConsumerSupport().getAccessToken(token, verifier); } finally { getTokenServices().removeToken(neededResourceId); } if (LOG.isDebugEnabled()) { LOG.debug( "Access token " + token + " obtained for resource " + neededResourceId + ". Now storing and using."); } getTokenServices().storeToken(neededResourceId, token); } accessTokens.put(neededResourceId, token); try { // try again if (!response.isCommitted()) { request.setAttribute( getAccessTokensRequestAttribute(), new ArrayList<OAuthConsumerToken>(accessTokens.values())); chain.doFilter(request, response); } else { // dang. what do we do now? throw new IllegalStateException( "Unable to reprocess filter chain with needed OAuth2 resources because the response is already committed."); } } catch (Exception e1) { resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e1); neededResourceId = resourceThatNeedsAuthorization.getId(); } } } catch (OAuthRequestFailedException eo) { fail(request, response, eo); } catch (Exception ex) { Throwable[] causeChain = getThrowableAnalyzer().determineCauseChain(ex); OAuthRequestFailedException rfe = (OAuthRequestFailedException) getThrowableAnalyzer() .getFirstThrowableOfType(OAuthRequestFailedException.class, causeChain); if (rfe != null) { fail(request, response, rfe); } else { // Rethrow ServletExceptions and RuntimeExceptions as-is if (ex instanceof ServletException) { throw (ServletException) ex; } else if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } // Wrap other Exceptions. These are not expected to happen throw new RuntimeException(ex); } } } } finally { OAuthSecurityContextHolder.setContext(null); HashMap<String, OAuthConsumerToken> tokensToRemember = new HashMap<String, OAuthConsumerToken>(); tokensToRemember.putAll(requestTokens); tokensToRemember.putAll(accessTokens); getRememberMeServices().rememberTokens(tokensToRemember, request, response); } }