Added Commons AccountManager (Authentication Provider!)

Also updated version of java-mwapi to support cookie based auth
This commit is contained in:
YuviPanda 2012-10-15 00:41:14 +05:30
parent d59b1700c8
commit 802e6aa9ed
8 changed files with 227 additions and 38 deletions

View file

@ -8,6 +8,9 @@
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.ACCOUNT_MANAGER"/>
<application
android:name=".CommonsApplication"
@ -15,7 +18,7 @@
android:label="@string/app_name"
android:theme="@style/Theme.Commons" >
<activity
android:name=".LoginActivity"
android:name=".auth.LoginActivity"
android:label="@string/title_activity_login"
android:theme="@style/NoTitle" >
</activity>
@ -24,11 +27,27 @@
android:label="@string/title_activity_share" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<service android:name="UploadService"></service>
<service android:name="UploadService" >
</service>
<service
android:name=".auth.WikiAccountAuthenticatorService"
android:exported="true"
android:process=":auth" >
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
</application>
</manifest>

Binary file not shown.

View file

@ -10,11 +10,9 @@ import org.apache.http.params.CoreProtocolPNames;
public class CommonsApplication extends Application {
private MWApi api;
public static final String API_URL = "http://test.wikipedia.org/w/api.php";
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
public static MWApi createMWApi() {
DefaultHttpClient client = new DefaultHttpClient();
// Because WMF servers support only HTTP/1.0. Biggest difference that
// this makes is support for Chunked Transfer Encoding.
@ -22,7 +20,14 @@ public class CommonsApplication extends Application {
// throws up.
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_0);
api = new MWApi("http://test.wikipedia.org/w/api.php", client);
return new MWApi(API_URL, client);
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
api = createMWApi();
}
public MWApi getApi() {

View file

@ -4,6 +4,7 @@ import java.io.*;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
import org.wikimedia.commons.auth.LoginActivity;
import android.net.Uri;
import android.os.AsyncTask;

View file

@ -11,6 +11,7 @@ import android.content.*;
import android.os.*;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.Toast;
import android.net.*;
@ -83,10 +84,6 @@ public class UploadService extends IntentService {
length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
//I'm hoping there are no streams that can be opened and read only once.
e.printStackTrace();
throw new RuntimeException(e);
}
notificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress);

View file

@ -1,9 +1,20 @@
package org.wikimedia.commons;
package org.wikimedia.commons.auth;
import java.io.IOException;
import org.wikimedia.commons.CommonsApplication;
import org.wikimedia.commons.R;
import org.wikimedia.commons.R.id;
import org.wikimedia.commons.R.layout;
import org.wikimedia.commons.R.menu;
import org.wikimedia.commons.R.string;
import android.os.AsyncTask;
import android.os.Bundle;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorActivity;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ProgressDialog;
import android.view.*;
@ -12,7 +23,9 @@ import android.widget.EditText;
import android.widget.Toast;
import android.support.v4.app.NavUtils;
public class LoginActivity extends Activity {
public class LoginActivity extends AccountAuthenticatorActivity {
public static final String PARAM_USERNAME = "org.wikimedia.commons.login.username";
private CommonsApplication app;
@ -24,6 +37,9 @@ public class LoginActivity extends Activity {
Activity context;
ProgressDialog dialog;
String username;
String password;
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
@ -31,6 +47,19 @@ public class LoginActivity extends Activity {
dialog.cancel();
Toast successToast = Toast.makeText(context, R.string.login_success, Toast.LENGTH_SHORT);
successToast.show();
Account account = new Account(username, WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
boolean accountCreated = AccountManager.get(context).addAccountExplicitly(account, password, null);
Bundle extras = context.getIntent().getExtras();
if (extras != null) {
if (accountCreated) { // Pass the new account back to the account manager
AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
Bundle authResult = new Bundle();
authResult.putString(AccountManager.KEY_ACCOUNT_NAME, username);
authResult.putString(AccountManager.KEY_ACCOUNT_TYPE, WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
response.onResult(authResult);
}
}
context.finish();
} else {
Toast failureToast = Toast.makeText(context, R.string.login_failed, Toast.LENGTH_LONG);
@ -55,8 +84,8 @@ public class LoginActivity extends Activity {
@Override
protected String doInBackground(String... params) {
String username = params[0];
String password = params[1];
username = params[0];
password = params[1];
try {
return app.getApi().login(username, password);
} catch (IOException e) {
@ -94,7 +123,6 @@ public class LoginActivity extends Activity {
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -105,7 +133,4 @@ public class LoginActivity extends Activity {
return super.onOptionsItemSelected(item);
}
}

View file

@ -0,0 +1,119 @@
package org.wikimedia.commons.auth;
import java.io.IOException;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
import org.wikimedia.commons.CommonsApplication;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
public static final String COMMONS_ACCOUNT_TYPE = "org.wikimedia.commons";
private Context context;
public WikiAccountAuthenticator(Context context) {
super(context);
this.context = context;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
// TODO Auto-generated method stub
final Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
// TODO Auto-generated method stub
return null;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
// TODO Auto-generated method stub
return null;
}
private String getAuthCookie(String username, String password) throws IOException {
MWApi api = ((CommonsApplication)context.getApplicationContext()).createMWApi();
String result = api.login(username, password);
if(result.equals("Success")) {
return api.getAuthCookie();
} else {
return null;
}
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
// If the caller requested an authToken type we don't support, then
// return an error
if (!authTokenType.equals(COMMONS_ACCOUNT_TYPE)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
return result;
}
// Extract the username and password from the Account Manager, and ask
// the server for an appropriate AuthToken.
final AccountManager am = AccountManager.get(context);
final String password = am.getPassword(account);
if (password != null) {
String authCookie;
try {
authCookie = getAuthCookie(account.name, password);
} catch (IOException e) {
// Network error!
throw new NetworkErrorException(e);
}
if (authCookie != null) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, COMMONS_ACCOUNT_TYPE);
result.putString(AccountManager.KEY_AUTHTOKEN, authCookie);
return result;
}
}
// If we get here, then we couldn't access the user's password - so we
// need to re-prompt them for their credentials. We do that by creating
// an intent to display our AuthenticatorActivity panel.
final Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(LoginActivity.PARAM_USERNAME, account.name);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
// TODO Auto-generated method stub
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
final Bundle result = new Bundle();
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
return result;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -0,0 +1,23 @@
package org.wikimedia.commons.auth;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class WikiAccountAuthenticatorService extends Service{
private static WikiAccountAuthenticator wikiAccountAuthenticator = null;
@Override
public IBinder onBind(Intent intent) {
if (!intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
return null;
}
if(wikiAccountAuthenticator == null) {
wikiAccountAuthenticator = new WikiAccountAuthenticator(this);
}
return wikiAccountAuthenticator.getIBinder();
}
}