Skip to content

Commit cc8c1fb

Browse files
committed
Refactor Share OAuth return web script methods
git-svn-id: https://share-extras.googlecode.com/svn/trunk/Share OAuth@1002 a3f5c567-fd0f-3a89-9b71-a290c5a5f590
1 parent 3621b1b commit cc8c1fb

File tree

1 file changed

+156
-81
lines changed

1 file changed

+156
-81
lines changed

source/java/org/sharextras/webscripts/OAuthReturn.java

Lines changed: 156 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public class OAuthReturn extends AbstractWebScript
5959
ConnectorService connectorService;
6060
String accessTokenUrl;
6161

62+
/**
63+
* Web Script constructor
64+
*/
6265
public OAuthReturn()
6366
{
6467
}
@@ -69,7 +72,8 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
6972
String verifier = req.getParameter(PARAM_OAUTH_VERIFIER),
7073
connectorId = req.getParameter(PARAM_CONNECTOR_ID),
7174
endpointName = req.getParameter(PARAM_ENDPOINT_ID),
72-
providerName = req.getParameter(PARAM_PROVIDER_ID);
75+
providerName = req.getParameter(PARAM_PROVIDER_ID),
76+
reqToken = req.getParameter(HttpOAuthConnector.OAUTH_TOKEN);
7377

7478
if (verifier == null || verifier.length() == 0)
7579
{
@@ -84,7 +88,8 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
8488
throw new WebScriptException("No provider name was specified");
8589
}
8690

87-
String pn = PREFS_BASE + providerName;
91+
// JSON path below which data is stored, using dot notation
92+
String jsonPath = PREFS_BASE + providerName + "." + PREF_DATA;
8893

8994
Map<String, Object> scriptParams = this.getContainer().getScriptParameters();
9095
scriptRemote = (ScriptRemote) scriptParams.get("remote");
@@ -97,45 +102,22 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
97102
String authToken = "", authTokenSecret = "";
98103

99104
// Load the current auth data
100-
Response authDataResp = alfrescoConnector.get(USER_TOKEN_URL + "?filter=" + pn + "." + PREF_DATA);
105+
Response authDataResp = getAccessTokenData(alfrescoConnector, jsonPath);
101106
if (authDataResp.getStatus().getCode() == Status.STATUS_OK)
102107
{
103108
String authData = authDataResp.getResponse();
104-
JSONObject authObj = null;
105109
Map<String, String> authParams = null;
106110
try
107111
{
108112
if (authData.length() > 0)
109113
{
110-
authObj = new JSONObject(authData);
111-
for (String k : pn.split("\\."))
112-
{
113-
if (authObj != null)
114-
{
115-
try
116-
{
117-
authObj = authObj.getJSONObject(k);
118-
}
119-
catch (JSONException e)
120-
{
121-
authObj = null;
122-
}
123-
}
124-
}
125-
if (authObj != null && authObj.length() > 0)
114+
String data = jsonStringByPath(authData, jsonPath);
115+
if (data != null && data.length() > 0)
126116
{
127-
String data = authObj.optString("data", "");
128-
if (data.length() > 0)
129-
{
130-
Map<String, String> dataMap = this.unpackData(data);
131-
// Unpack the existing parameters
132-
authToken = dataMap.get(HttpOAuthConnector.OAUTH_TOKEN);
133-
authTokenSecret = dataMap.get(HttpOAuthConnector.OAUTH_TOKEN_SECRET);
134-
}
135-
else
136-
{
137-
throw new WebScriptException(Status.STATUS_NOT_FOUND, "No OAuth data could be found for provider " + providerName);
138-
}
117+
Map<String, String> dataMap = this.unpackData(data);
118+
// Unpack the existing parameters
119+
authToken = dataMap.get(HttpOAuthConnector.OAUTH_TOKEN);
120+
authTokenSecret = dataMap.get(HttpOAuthConnector.OAUTH_TOKEN_SECRET);
139121
}
140122
else
141123
{
@@ -150,6 +132,10 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
150132
{
151133
throw new WebScriptException(Status.STATUS_NOT_FOUND, "Request token secret could not be found");
152134
}
135+
if (reqToken != null && !reqToken.equals(authToken))
136+
{
137+
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Stored request token and returned token do not match");
138+
}
153139

154140
authParams = requestAccessToken(endpointName, authToken, authTokenSecret, verifier, req, oauthConnector);
155141
}
@@ -162,11 +148,6 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
162148
{
163149
throw new WebScriptException("Could not decode OAuth data JSON response", e);
164150
}
165-
/*
166-
catch (ConnectorServiceException e)
167-
{
168-
throw new WebScriptException("Could not locate OAuth connector", e);
169-
}*/
170151

171152
if (authParams.size() == 0)
172153
{
@@ -182,13 +163,10 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
182163
}
183164

184165
// Persist the data
185-
Response writeAccessTokenResponse = this.storeAccessTokenData(authParams, pn);
166+
Response writeAccessTokenResponse = this.storeAccessTokenData(alfrescoConnector, jsonPath, authParams);
186167
if (writeAccessTokenResponse.getStatus().getCode() == Status.STATUS_OK)
187168
{
188-
String redirectPage = req.getParameter(PARAM_REDIRECT_PAGE).indexOf('/') == 0 ? req.getParameter(PARAM_REDIRECT_PAGE) : "/" + req.getParameter(PARAM_REDIRECT_PAGE),
189-
redirectLocation = req.getServerPath() + req.getContextPath() + (redirectPage != null ? redirectPage : "");
190-
resp.addHeader(WebScriptResponse.HEADER_LOCATION, redirectLocation);
191-
resp.setStatus(Status.STATUS_MOVED_TEMPORARILY);
169+
executeRedirect(req, resp);
192170
}
193171
else
194172
{
@@ -198,8 +176,15 @@ public void execute(WebScriptRequest req, WebScriptResponse resp) throws IOExcep
198176
}
199177
else
200178
{
201-
// TODO if resp is 401 then redirect to original page
202-
throw new WebScriptException(authDataResp.getStatus().getCode(), "A problem occurred while loading the OAuth token data (code " + authDataResp.getStatus().getCode() + ")");
179+
// If resp is 401 then redirect to original page
180+
if (authDataResp.getStatus().getCode() == 401)
181+
{
182+
executeRedirect(req, resp);
183+
}
184+
else
185+
{
186+
throw new WebScriptException(authDataResp.getStatus().getCode(), "A problem occurred while loading the OAuth token data (code " + authDataResp.getStatus().getCode() + ")");
187+
}
203188
}
204189
}
205190

@@ -225,35 +210,69 @@ private Map<String, String> unpackData(String body)
225210
return m;
226211
}
227212

228-
private Map<String, String> requestAccessToken(
229-
String endpointName, String authToken,
230-
String authTokenSecret, String verifier,
231-
WebScriptRequest req,
232-
ScriptRemoteConnector oauthConnector) throws HttpException, IOException
213+
/**
214+
* Pack OAuth parameters into a form suitable for putting into a single string
215+
*
216+
* @param params
217+
* @return
218+
*/
219+
private String packData(Map<String, String> params)
233220
{
234-
Map<String, String> authParams;
235-
// Add the verifier
236-
//Connector oauthConnector = connectorService.getConnector(connectorName);
237-
HttpClient client = new HttpClient();
238-
239-
// TODO Parameterise the access token path
240-
String postUri = req.getServerPath() + req.getContextPath() + URL_PROXY_SERVLET + "/" + endpointName + getAccessTokenUrl(oauthConnector);
241-
HttpMethod method = new PostMethod(postUri);
242-
method.addRequestHeader(HttpOAuthConnector.HEADER_OAUTH_DATA, HttpOAuthConnector.OAUTH_TOKEN + "=\"" + authToken + "\"," +
243-
HttpOAuthConnector.OAUTH_TOKEN_SECRET + "=\"" + authTokenSecret + "\"," + PARAM_OAUTH_VERIFIER + "=\"" + verifier + "\"");
244-
int statusCode = client.executeMethod(method);
245-
if (statusCode == Status.STATUS_OK)
221+
StringBuffer newdata = new StringBuffer();
222+
// add each key,val pair to the string
223+
for (Map.Entry<String, String> p : params.entrySet())
246224
{
247-
// do something with the input stream, which contains the new parameters in the body
248-
byte[] responseBody = method.getResponseBody();
249-
String tokenResp = new String(responseBody, Charset.forName("UTF-8"));
250-
authParams = this.unpackData(tokenResp);
251-
return authParams;
225+
newdata.append(newdata.length() > 0 ? "&" : "");
226+
newdata.append(p.getKey() + "=" + p.getValue());
252227
}
253-
else
228+
return newdata.toString();
229+
}
230+
231+
/**
232+
* Look up a string value in some JSON mark-up, using a path expressed in dot notation
233+
*
234+
* @param jsonSrc
235+
* @param path
236+
* @return
237+
* @throws JSONException
238+
*/
239+
private String jsonStringByPath(String jsonSrc, String path) throws JSONException
240+
{
241+
String str = null,
242+
objPath = path.substring(0, path.lastIndexOf('.')),
243+
strKey = path.substring(path.lastIndexOf('.') + 1);
244+
JSONObject authObj = new JSONObject(jsonSrc);
245+
for (String k : objPath.split("\\."))
254246
{
255-
throw new WebScriptException(statusCode, "A problem occurred while requesting the access token");
247+
if (authObj != null)
248+
{
249+
try
250+
{
251+
authObj = authObj.getJSONObject(k);
252+
}
253+
catch (JSONException e)
254+
{
255+
authObj = null;
256+
}
257+
}
256258
}
259+
if (authObj != null && authObj.length() > 0)
260+
{
261+
str = authObj.optString(strKey, "");
262+
}
263+
return str;
264+
}
265+
266+
/**
267+
* Load OAuth data from the repository
268+
*
269+
* @param connector
270+
* @param path
271+
* @return
272+
*/
273+
private Response getAccessTokenData(ScriptRemoteConnector connector, String path)
274+
{
275+
return connector.get(USER_TOKEN_URL + "?filter=" + path);
257276
}
258277

259278
/**
@@ -263,29 +282,28 @@ private Map<String, String> requestAccessToken(
263282
* @param base
264283
* @return
265284
*/
266-
private Response storeAccessTokenData(Map<String, String> authParams, String base)
285+
private Response storeAccessTokenData(ScriptRemoteConnector connector, String path, Map<String, String> authParams)
267286
{
268-
ScriptRemoteConnector connector = scriptRemote.connect();
269-
String[] baseParts = base.split("\\.");
287+
String basePath = path.substring(0, path.lastIndexOf('.')),
288+
strKey = path.substring(path.lastIndexOf('.') + 1);
289+
String[] baseParts = basePath.split("\\.");
270290
try
271291
{
272-
StringBuffer newdata = new StringBuffer();
292+
// start main object
273293
JSONWriter currJSON = new JSONStringer().object();
274-
for (String k : baseParts)
275-
{
276-
currJSON.key(k).object();
277-
}
278-
// add each auth parameter to currJSON
279-
for (Map.Entry<String, String> p : authParams.entrySet())
294+
// start all outer objects
295+
for (int i = 0; i < baseParts.length; i++)
280296
{
281-
newdata.append(newdata.length() > 0 ? "&" : "");
282-
newdata.append(p.getKey() + "=" + p.getValue());
297+
currJSON.key(baseParts[i]).object();
283298
}
284-
currJSON.key(PREF_DATA).value(newdata.toString());
299+
// add string value
300+
currJSON.key(strKey).value(packData(authParams));
301+
// end each outer object
285302
for (int i = 0; i < baseParts.length; i++)
286303
{
287304
currJSON.endObject();
288305
}
306+
// end main object
289307
currJSON.endObject();
290308
String postBody = currJSON.toString();
291309

@@ -296,6 +314,63 @@ private Response storeAccessTokenData(Map<String, String> authParams, String bas
296314
throw new WebScriptException("Could not encode OAuth data in JSON format", e);
297315
}
298316
}
317+
318+
/**
319+
* Obtain a permanent access token from the OAuth service, utilising the OAuth connector to
320+
* perform the necessary signing of requests.
321+
*
322+
* @param endpointName
323+
* @param authToken
324+
* @param authTokenSecret
325+
* @param verifier
326+
* @param req
327+
* @param oauthConnector
328+
* @return
329+
* @throws HttpException
330+
* @throws IOException
331+
*/
332+
private Map<String, String> requestAccessToken(
333+
String endpointName, String authToken,
334+
String authTokenSecret, String verifier,
335+
WebScriptRequest req,
336+
ScriptRemoteConnector oauthConnector) throws HttpException, IOException
337+
{
338+
Map<String, String> authParams;
339+
HttpClient client = new HttpClient();
340+
341+
String postUri = req.getServerPath() + req.getContextPath() + URL_PROXY_SERVLET + "/" + endpointName + getAccessTokenUrl(oauthConnector);
342+
HttpMethod method = new PostMethod(postUri);
343+
method.addRequestHeader(HttpOAuthConnector.HEADER_OAUTH_DATA, HttpOAuthConnector.OAUTH_TOKEN + "=\"" + authToken + "\"," +
344+
HttpOAuthConnector.OAUTH_TOKEN_SECRET + "=\"" + authTokenSecret + "\"," + PARAM_OAUTH_VERIFIER + "=\"" + verifier + "\"");
345+
int statusCode = client.executeMethod(method);
346+
if (statusCode == Status.STATUS_OK)
347+
{
348+
// do something with the input stream, which contains the new parameters in the body
349+
byte[] responseBody = method.getResponseBody();
350+
String tokenResp = new String(responseBody, Charset.forName("UTF-8"));
351+
authParams = this.unpackData(tokenResp);
352+
return authParams;
353+
}
354+
else
355+
{
356+
throw new WebScriptException(statusCode, "A problem occurred while requesting the access token");
357+
}
358+
}
359+
360+
/**
361+
* Redirect the user to the location that was specified in the request parameter, or
362+
* to the webapp context root if this was not found
363+
*
364+
* @param req
365+
* @param resp
366+
*/
367+
private void executeRedirect(WebScriptRequest req, WebScriptResponse resp)
368+
{
369+
String redirectPage = req.getParameter(PARAM_REDIRECT_PAGE).indexOf('/') == 0 ? req.getParameter(PARAM_REDIRECT_PAGE) : "/" + req.getParameter(PARAM_REDIRECT_PAGE),
370+
redirectLocation = req.getServerPath() + req.getContextPath() + (redirectPage != null ? redirectPage : "");
371+
resp.addHeader(WebScriptResponse.HEADER_LOCATION, redirectLocation);
372+
resp.setStatus(Status.STATUS_MOVED_TEMPORARILY);
373+
}
299374

300375
public ScriptRemote getScriptRemote()
301376
{

0 commit comments

Comments
 (0)