/**
* This file is part of ElasticDroid.
*
* ElasticDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* ElasticDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with ElasticDroid. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by Siddhu Warrier on 1 Nov 2010
*/
package org.elasticdroid.model;
import java.util.regex.Pattern;
import org.elasticdroid.db.ElasticDroidDB;
import org.elasticdroid.db.tblinfo.LoginTbl;
import org.elasticdroid.model.tpl.GenericModel;
import org.elasticdroid.tpl.GenericActivity;
import android.content.ContentValues;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient;
import com.amazonaws.services.identitymanagement.model.User;
/**
* This class is the model class for the Login window. It performs the following actions:
* a) Verifies credentials by connecting to AWS.
* b) Stores valid credentials in database.
* c) Notifies observers (presently the Login activity alone) that authentication is valid (or not).
* d) Can be used to retrieve saved credentials from SQLite DB.
* @author Siddhu Warrier
*
* 1 Nov 2010
*/
public class LoginModel extends GenericModel<String, Void, Object> {
/**
* To call super Constructor alone. To read what this constructor
* does, please refer to the superclass documentation.
* @param genericActivity The activity which started this model
*/
public LoginModel(GenericActivity genericActivity) {
super(genericActivity);
}
/**
* Check AWS credentials, and save to DB if valid.
*
* When this method finishes, the
* {@link org.elasticdroid.model.tpl.GenericModel#onPostExecute(Object)} is called, which
* notifies the view.
*
* This method, inherited from Android AsyncTask is automagically run in a separate background
* thread.
*/
@Override
protected Object doInBackground(String... params) {
return performLogin(params);
}
public Object performLogin(String... params) {
//we need username, accessKey, secretAccessKey
if (params.length != 3) {
Log.e(this.getClass().getName(), "Need 3 params."); //TODO do something better.
return null;
}
//create credentials using the BasicAWSCredentials class
BasicAWSCredentials credentials = new BasicAWSCredentials(params[1], params[2]);
//create an IAM client
AmazonIdentityManagementClient idManagementClient = new AmazonIdentityManagementClient
(credentials);
User userData = null;
Log.v(this.getClass().getName(), "Executing performLogin AsyncTask...");
try {
userData = idManagementClient.getUser().getUser();//ensure the user ID is
//matched to the access and secret access keys
}
catch(AmazonServiceException amazonServiceException) {
//if an error response is returned by AmazonIdentityManagement indicating either a
//problem with the data in the request, or a server side issue.
Log.e(this.getClass().getName(), "Exception:" + amazonServiceException.getMessage());
return amazonServiceException;
}
catch(AmazonClientException amazonClientException) {
//If any internal errors are encountered inside the client while attempting to make
//the request or handle the response. For example if a network connection is not available.
Log.e(this.getClass().getName(), "Exception:" + amazonClientException.getMessage());
return amazonClientException;
}
//if we get here, the userData variable has been initialised.
//check if the user name specified by the user corresponds to the
//user name associated with the acess and secret access keys specified
String username = userData.getUserName();
if (username != null) { //this is an IAM username
if (!username.equals(params[0])) {
/*Log.e(this.getClass().getName(), "Username " + params[0] + ", " + userData.
getUserName() + " does not correspond to access and secret access key!");*/
//return *not throw* an illegalArgumentException, because this is a different thread.
return new IllegalArgumentException("Username does not correspond to access and " +
"secret access key!");
}
}
else {
//this is a proper AWS account, and not an IAM username.
//check if the username is a proper email address. Java regexes look +vely awful!
Pattern emailPattern = Pattern.compile("^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$",
Pattern.CASE_INSENSITIVE);
//if this is not an email address
if (!emailPattern.matcher(params[0]).matches()) {
return new IllegalArgumentException("Username is an AWS account. Please enter a" +
" valid email address.");
}
}
/*writing to DB*/
// if we get here, then write the data to the DB
ElasticDroidDB elasticDroidDB = new ElasticDroidDB(activity);
//open the database for writing
SQLiteDatabase db = elasticDroidDB.getWritableDatabase();
ContentValues rowValues = new ContentValues();
//check if the username already exists
//set the data to write
rowValues.put(LoginTbl.COL_USERNAME, params[0]);
rowValues.put(LoginTbl.COL_ACCESSKEY, params[1]);
rowValues.put(LoginTbl.COL_SECRETACCESSKEY, params[2]);
//if data is found, update.
if (db.query(LoginTbl.TBL_NAME, new String[]{}, LoginTbl.COL_USERNAME
+ "=?", new String[]{params[0]}, null, null, null).getCount() != 0) {
try {
db.update(LoginTbl.TBL_NAME, rowValues, LoginTbl.COL_USERNAME + "=?",
new String[]{params[0]});
}
catch(SQLException sqlException) {
Log.e(this.getClass().getName(), "SQLException: " + sqlException.getMessage());
return sqlException; //return the exception for the View to process.
}
finally {
db.close();
}
}
else {
//now write the data in, replacing if necessary!
try {
db.insertOrThrow(LoginTbl.TBL_NAME, null, rowValues);
}
catch(SQLException sqlException) {
Log.e(this.getClass().getName(), "SQLException: " + sqlException.getMessage());
return sqlException; //return the exception for the View to process.
}
finally {
db.close();
}
}
return true;
}
}