mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Added Commons AccountManager (Authentication Provider!)
Also updated version of java-mwapi to support cookie based auth
This commit is contained in:
parent
d59b1700c8
commit
802e6aa9ed
8 changed files with 227 additions and 38 deletions
|
|
@ -8,6 +8,9 @@
|
||||||
android:targetSdkVersion="15" />
|
android:targetSdkVersion="15" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<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
|
<application
|
||||||
android:name=".CommonsApplication"
|
android:name=".CommonsApplication"
|
||||||
|
|
@ -15,7 +18,7 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.Commons" >
|
android:theme="@style/Theme.Commons" >
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".auth.LoginActivity"
|
||||||
android:label="@string/title_activity_login"
|
android:label="@string/title_activity_login"
|
||||||
android:theme="@style/NoTitle" >
|
android:theme="@style/NoTitle" >
|
||||||
</activity>
|
</activity>
|
||||||
|
|
@ -24,11 +27,27 @@
|
||||||
android:label="@string/title_activity_share" >
|
android:label="@string/title_activity_share" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
<data android:mimeType="image/*" />
|
<data android:mimeType="image/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
Binary file not shown.
|
|
@ -10,11 +10,9 @@ import org.apache.http.params.CoreProtocolPNames;
|
||||||
public class CommonsApplication extends Application {
|
public class CommonsApplication extends Application {
|
||||||
|
|
||||||
private MWApi api;
|
private MWApi api;
|
||||||
|
public static final String API_URL = "http://test.wikipedia.org/w/api.php";
|
||||||
|
|
||||||
@Override
|
public static MWApi createMWApi() {
|
||||||
public void onCreate() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onCreate();
|
|
||||||
DefaultHttpClient client = new DefaultHttpClient();
|
DefaultHttpClient client = new DefaultHttpClient();
|
||||||
// Because WMF servers support only HTTP/1.0. Biggest difference that
|
// Because WMF servers support only HTTP/1.0. Biggest difference that
|
||||||
// this makes is support for Chunked Transfer Encoding.
|
// this makes is support for Chunked Transfer Encoding.
|
||||||
|
|
@ -22,7 +20,14 @@ public class CommonsApplication extends Application {
|
||||||
// throws up.
|
// throws up.
|
||||||
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
|
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
|
||||||
HttpVersion.HTTP_1_0);
|
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() {
|
public MWApi getApi() {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import java.io.*;
|
||||||
|
|
||||||
import org.mediawiki.api.ApiResult;
|
import org.mediawiki.api.ApiResult;
|
||||||
import org.mediawiki.api.MWApi;
|
import org.mediawiki.api.MWApi;
|
||||||
|
import org.wikimedia.commons.auth.LoginActivity;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import android.content.*;
|
||||||
import android.os.*;
|
import android.os.*;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.net.*;
|
import android.net.*;
|
||||||
|
|
@ -83,10 +84,6 @@ public class UploadService extends IntentService {
|
||||||
length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength();
|
length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
throw new RuntimeException(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);
|
notificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,20 @@
|
||||||
package org.wikimedia.commons;
|
package org.wikimedia.commons.auth;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.AsyncTask;
|
||||||
import android.os.Bundle;
|
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.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.view.*;
|
import android.view.*;
|
||||||
|
|
@ -12,7 +23,9 @@ import android.widget.EditText;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.support.v4.app.NavUtils;
|
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;
|
private CommonsApplication app;
|
||||||
|
|
||||||
|
|
@ -24,13 +37,29 @@ public class LoginActivity extends Activity {
|
||||||
|
|
||||||
Activity context;
|
Activity context;
|
||||||
ProgressDialog dialog;
|
ProgressDialog dialog;
|
||||||
|
String username;
|
||||||
|
String password;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(String result) {
|
protected void onPostExecute(String result) {
|
||||||
super.onPostExecute(result);
|
super.onPostExecute(result);
|
||||||
if(result.equals("Success")) {
|
if (result.equals("Success")) {
|
||||||
dialog.cancel();
|
dialog.cancel();
|
||||||
Toast successToast = Toast.makeText(context, R.string.login_success, Toast.LENGTH_SHORT);
|
Toast successToast = Toast.makeText(context, R.string.login_success, Toast.LENGTH_SHORT);
|
||||||
successToast.show();
|
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();
|
context.finish();
|
||||||
} else {
|
} else {
|
||||||
Toast failureToast = Toast.makeText(context, R.string.login_failed, Toast.LENGTH_LONG);
|
Toast failureToast = Toast.makeText(context, R.string.login_failed, Toast.LENGTH_LONG);
|
||||||
|
|
@ -55,8 +84,8 @@ public class LoginActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(String... params) {
|
protected String doInBackground(String... params) {
|
||||||
String username = params[0];
|
username = params[0];
|
||||||
String password = params[1];
|
password = params[1];
|
||||||
try {
|
try {
|
||||||
return app.getApi().login(username, password);
|
return app.getApi().login(username, password);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -70,11 +99,11 @@ public class LoginActivity extends Activity {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
app = (CommonsApplication)this.getApplicationContext();
|
app = (CommonsApplication) this.getApplicationContext();
|
||||||
setContentView(R.layout.activity_login);
|
setContentView(R.layout.activity_login);
|
||||||
loginButton = (Button)findViewById(R.id.loginButton);
|
loginButton = (Button) findViewById(R.id.loginButton);
|
||||||
usernameEdit = (EditText)findViewById(R.id.loginUsername);
|
usernameEdit = (EditText) findViewById(R.id.loginUsername);
|
||||||
passwordEdit = (EditText)findViewById(R.id.loginPassword);
|
passwordEdit = (EditText) findViewById(R.id.loginPassword);
|
||||||
final Activity that = this;
|
final Activity that = this;
|
||||||
loginButton.setOnClickListener(new View.OnClickListener() {
|
loginButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -94,7 +123,6 @@ public class LoginActivity extends Activity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
|
@ -105,7 +133,4 @@ public class LoginActivity extends Activity {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
119
src/org/wikimedia/commons/auth/WikiAccountAuthenticator.java
Normal file
119
src/org/wikimedia/commons/auth/WikiAccountAuthenticator.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue