Skip to content

Commit d1ec2bb

Browse files
committed
Initial commit
1 parent b18984a commit d1ec2bb

12 files changed

+494
-0
lines changed

AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.codepath.libraries.oauthhandler"
3+
android:versionCode="1"
4+
android:versionName="1.0" >
5+
6+
<uses-sdk
7+
android:minSdkVersion="8"
8+
android:targetSdkVersion="17" />
9+
10+
</manifest>

libs/android-async-http-1.4.3.jar

28.5 KB
Binary file not shown.

libs/android-support-v4.jar

473 KB
Binary file not shown.

libs/codepath-utils.jar

4.68 KB
Binary file not shown.

libs/scribe.jar

148 KB
Binary file not shown.

res/.gitkeep

Whitespace-only changes.

res/layout/.gitkeep

Whitespace-only changes.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package com.codepath.oauth;
2+
3+
import org.apache.http.client.methods.HttpUriRequest;
4+
import org.apache.http.impl.client.DefaultHttpClient;
5+
import org.apache.http.protocol.HttpContext;
6+
import org.scribe.builder.ServiceBuilder;
7+
import org.scribe.builder.api.Api;
8+
import org.scribe.model.OAuthConstants;
9+
import org.scribe.model.Token;
10+
import org.scribe.model.Verifier;
11+
import org.scribe.oauth.OAuthService;
12+
13+
import android.content.Context;
14+
import android.net.Uri;
15+
16+
import com.codepath.utils.AsyncSimpleTask;
17+
import com.loopj.android.http.AsyncHttpClient;
18+
import com.loopj.android.http.AsyncHttpResponseHandler;
19+
20+
/*
21+
* OAuthAsyncHttpClient is responsible for managing the request and access token exchanges and then
22+
* signing all requests with the OAuth signature after access token has been retrieved and stored.
23+
* The client is based on AsyncHttpClient for async http requests and uses Scribe to manage the OAuth authentication.
24+
*/
25+
public class OAuthAsyncHttpClient extends AsyncHttpClient {
26+
27+
private OAuthTokenHandler handler;
28+
private Token accessToken;
29+
private OAuthService service;
30+
31+
// Requires the ApiClass, consumerKey, consumerSecret and callbackUrl along with the TokenHandler
32+
public OAuthAsyncHttpClient(Class<? extends Api> apiClass, String consumerKey, String consumerSecret, String callbackUrl,
33+
OAuthTokenHandler handler) {
34+
this.handler = handler;
35+
if (callbackUrl == null) { callbackUrl = OAuthConstants.OUT_OF_BAND; };
36+
this.service = new ServiceBuilder()
37+
.provider(apiClass).apiKey(consumerKey)
38+
.apiSecret(consumerSecret).callback(callbackUrl)
39+
.build();
40+
}
41+
42+
// Get a request token and the authorize url
43+
// Once fetched, fire the onReceivedRequestToken for the request token handler
44+
public void fetchRequestToken() {
45+
new AsyncSimpleTask(new AsyncSimpleTask.AsyncSimpleTaskHandler() {
46+
String authorizeUrl = null;
47+
Exception e = null;
48+
Token requestToken;
49+
50+
public void doInBackground() {
51+
try {
52+
requestToken = service.getRequestToken();
53+
authorizeUrl = service.getAuthorizationUrl(requestToken);
54+
} catch (Exception e) {
55+
this.e = e;
56+
}
57+
}
58+
59+
public void onPostExecute() {
60+
if (e != null) {
61+
handler.onFailure(e);
62+
} else {
63+
handler.onReceivedRequestToken(requestToken, authorizeUrl);
64+
}
65+
}
66+
});
67+
}
68+
69+
// Get the access token by exchanging the requestToken to the defined URL
70+
// Once receiving the access token, fires the onReceivedAccessToken method on the handler
71+
public void fetchAccessToken(final Token requestToken, final Uri uri) {
72+
73+
new AsyncSimpleTask(new AsyncSimpleTask.AsyncSimpleTaskHandler() {
74+
Exception e = null;
75+
76+
public void doInBackground() {
77+
Uri authorizedUri = uri;
78+
String oauth_verifier = authorizedUri.getQueryParameter(OAuthConstants.VERIFIER);
79+
try {
80+
accessToken = service.getAccessToken(requestToken, new Verifier(oauth_verifier));
81+
} catch (Exception e) {
82+
this.e = e;
83+
}
84+
}
85+
86+
public void onPostExecute() {
87+
if (e != null)
88+
handler.onFailure(e);
89+
else {
90+
setAccessToken(accessToken);
91+
handler.onReceivedAccessToken(accessToken);
92+
}
93+
}
94+
});
95+
}
96+
97+
// Set the access token used for signing requests
98+
public void setAccessToken(Token accessToken) {
99+
if (accessToken == null) {
100+
this.accessToken = null;
101+
} else {
102+
this.accessToken = accessToken;
103+
}
104+
}
105+
106+
// Send scribe signed request based on the async http client to construct a signed request
107+
// Accepts an HttpEntity which has the underlying entity for the request params
108+
protected void sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest,
109+
String contentType, AsyncHttpResponseHandler responseHandler, Context context) {
110+
if (this.service != null) {
111+
try {
112+
ScribeRequestAdapter adapter = new ScribeRequestAdapter(uriRequest);
113+
this.service.signRequest(accessToken, adapter);
114+
super.sendRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
115+
} catch (Exception e) {
116+
e.printStackTrace();
117+
}
118+
}
119+
120+
}
121+
122+
// Defines the interface handler for different token handlers
123+
public interface OAuthTokenHandler {
124+
public void onReceivedRequestToken(Token requestToken, String authorizeUrl);
125+
public void onReceivedAccessToken(Token accessToken);
126+
public void onFailure(Exception e);
127+
}
128+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.codepath.oauth;
2+
3+
import org.scribe.builder.api.Api;
4+
import org.scribe.model.OAuthConstants;
5+
import org.scribe.model.Token;
6+
7+
import android.content.Context;
8+
import android.content.Intent;
9+
import android.content.SharedPreferences;
10+
import android.net.Uri;
11+
12+
public abstract class OAuthBaseClient {
13+
protected String baseUrl;
14+
protected Context context;
15+
protected OAuthAsyncHttpClient client;
16+
protected SharedPreferences prefs;
17+
protected SharedPreferences.Editor editor;
18+
protected OAuthAccessHandler accessHandler;
19+
20+
public static OAuthBaseClient instance;
21+
22+
public static OAuthBaseClient getInstance(Class<? extends OAuthBaseClient> klass, Context context) {
23+
if (instance == null) {
24+
try {
25+
instance = (OAuthBaseClient) klass.getConstructor(Context.class).newInstance(context);
26+
} catch (Exception e) {
27+
e.printStackTrace();
28+
}
29+
}
30+
return instance;
31+
}
32+
33+
public OAuthBaseClient(Context c, Class<? extends Api> apiClass, String consumerUrl, String consumerKey, String consumerSecret, String callbackUrl) {
34+
this.baseUrl = consumerUrl;
35+
client = new OAuthAsyncHttpClient(apiClass, consumerKey,
36+
consumerSecret, callbackUrl, new OAuthAsyncHttpClient.OAuthTokenHandler() {
37+
@Override
38+
public void onReceivedRequestToken(Token requestToken, String authorizeUrl) {
39+
editor.putString("request_token", requestToken.getToken());
40+
editor.putString("request_token_secret", requestToken.getSecret());
41+
editor.commit();
42+
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(authorizeUrl + "&perms=delete"));
43+
OAuthBaseClient.this.context.startActivity(intent);
44+
}
45+
46+
@Override
47+
public void onReceivedAccessToken(Token accessToken) {
48+
client.setAccessToken(accessToken);
49+
editor.putString(OAuthConstants.TOKEN, accessToken.getToken());
50+
editor.putString(OAuthConstants.TOKEN_SECRET, accessToken.getSecret());
51+
editor.commit();
52+
accessHandler.onLoginSuccess();
53+
}
54+
55+
@Override
56+
public void onFailure(Exception e) {
57+
accessHandler.onLoginFailure(e);
58+
}
59+
});
60+
61+
this.context = c;
62+
this.prefs = this.context.getSharedPreferences("OAuth", 0);
63+
this.editor = this.prefs.edit();
64+
// Set access token if already stored
65+
if (this.checkAccessToken() != null) {
66+
client.setAccessToken(this.checkAccessToken());
67+
}
68+
}
69+
70+
// Fetches a request token and retrieve and authorization url
71+
// Should open a browser in onReceivedRequestToken once the url has been received
72+
public void connect() {
73+
client.fetchRequestToken();
74+
}
75+
76+
// Retrieves access token given authorization url
77+
public void authorize(Uri uri, OAuthAccessHandler handler) {
78+
this.accessHandler = handler;
79+
if (checkAccessToken() == null && uri != null) {
80+
client.fetchAccessToken(getRequestToken(), uri);
81+
} else if (checkAccessToken() != null) { // already have access token
82+
this.accessHandler.onLoginSuccess();
83+
}
84+
}
85+
86+
// Return access token if the token exists in preferences
87+
public Token checkAccessToken() {
88+
if (prefs.contains(OAuthConstants.TOKEN) && prefs.contains(OAuthConstants.TOKEN_SECRET)) {
89+
return new Token(prefs.getString(OAuthConstants.TOKEN, ""),
90+
prefs.getString(OAuthConstants.TOKEN_SECRET, ""));
91+
} else {
92+
return null;
93+
}
94+
}
95+
96+
protected OAuthAsyncHttpClient getClient() {
97+
return client;
98+
}
99+
100+
// Returns the request token stored during the request token phase
101+
protected Token getRequestToken() {
102+
return new Token(prefs.getString("request_token", ""),
103+
prefs.getString("request_token_secret", ""));
104+
}
105+
106+
// Assigns the base url for the API
107+
protected void setBaseUrl(String url) {
108+
this.baseUrl = url;
109+
}
110+
111+
// Returns the full ApiUrl
112+
protected String getApiUrl(String path) {
113+
return this.baseUrl + "/" + path;
114+
}
115+
116+
// Removes the access tokens (for signout)
117+
public void clearAccessToken() {
118+
client.setAccessToken(null);
119+
editor.remove(OAuthConstants.TOKEN);
120+
editor.remove(OAuthConstants.TOKEN_SECRET);
121+
editor.commit();
122+
}
123+
124+
// Defines the handler events for the oauth flow
125+
public static interface OAuthAccessHandler {
126+
public void onLoginSuccess();
127+
public void onLoginFailure(Exception e);
128+
}
129+
130+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.codepath.oauth;
2+
3+
import android.content.Context;
4+
import android.net.Uri;
5+
import android.os.Bundle;
6+
import android.support.v4.app.FragmentActivity;
7+
8+
import com.codepath.utils.GenericsUtil;
9+
10+
public abstract class OAuthLoginActivity<T extends OAuthBaseClient> extends FragmentActivity
11+
implements OAuthBaseClient.OAuthAccessHandler {
12+
13+
private T client;
14+
15+
@Override
16+
protected void onCreate(Bundle saved) {
17+
super.onCreate(saved);
18+
19+
Class<T> clientClass = getClientClass();
20+
Uri uri = getIntent().getData();
21+
22+
try {
23+
client = clientClass.getConstructor(Context.class).newInstance(this);
24+
client.authorize(uri, this); // fetch access token (if needed)
25+
} catch (Exception e) {
26+
e.printStackTrace();
27+
}
28+
}
29+
30+
public T getClient() {
31+
return client;
32+
}
33+
34+
@SuppressWarnings("unchecked")
35+
private Class<T> getClientClass() {
36+
return (Class<T>) GenericsUtil.getTypeArguments(OAuthLoginActivity.class, this.getClass()).get(0);
37+
}
38+
}
39+
40+
/*
41+
*
42+
* 1) Subclass OAuthBaseClient like TwitterClient 2) Subclass
43+
* OAuthLoginActivity<TwitterClient> 3) Invoke .login 4) Optionally override a)
44+
* onLoginSuccess b) onLoginFailure(Exception e) 5) In other activities that
45+
* need the client a) c = TwitterClient.getSharedClient() b) c.getTimeline(...)
46+
* 6) Modify AndroidManifest.xml to add an IntentFilter w/ the callback URL
47+
* defined in the OAuthBaseClient.
48+
*/
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.codepath.oauth;
2+
3+
import android.content.Context;
4+
import android.net.Uri;
5+
import android.os.Bundle;
6+
import android.support.v4.app.Fragment;
7+
8+
import com.codepath.utils.GenericsUtil;
9+
10+
public abstract class OAuthLoginFragment<T extends OAuthBaseClient> extends Fragment implements
11+
OAuthBaseClient.OAuthAccessHandler {
12+
13+
private T client;
14+
15+
@Override
16+
public void onCreate(Bundle saved) {
17+
super.onCreate(saved);
18+
19+
Class<T> clientClass = getClientClass();
20+
Uri uri = getActivity().getIntent().getData();
21+
22+
try {
23+
client = clientClass.getConstructor(Context.class).newInstance(getActivity());
24+
client.authorize(uri, this); // fetch access token (if needed)
25+
} catch (Exception e) {
26+
e.printStackTrace();
27+
}
28+
}
29+
30+
public T getClient() {
31+
return client;
32+
}
33+
34+
@SuppressWarnings("unchecked")
35+
private Class<T> getClientClass() {
36+
return (Class<T>) GenericsUtil.getTypeArguments(OAuthLoginFragment.class, this.getClass()).get(0);
37+
}
38+
}

0 commit comments

Comments
 (0)