package fi.bitrite.android.ws.auth.http;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.util.Log;
import fi.bitrite.android.ws.api.RestClient;
import fi.bitrite.android.ws.auth.AuthenticationHelper;
import fi.bitrite.android.ws.auth.NoAccountException;
import fi.bitrite.android.ws.model.Host;
import fi.bitrite.android.ws.util.GlobalInfo;
import fi.bitrite.android.ws.util.MemberInfo;
import fi.bitrite.android.ws.util.http.HttpException;
import org.apache.http.NameValuePair;
import org.apache.http.client.CircularRedirectException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Responsible for authenticating the user against the WarmShowers web service.
*/
public class HttpAuthenticator {
private final String wsUserAuthUrl = GlobalInfo.warmshowersBaseUrl + "/services/rest/user/login";
private final String wsUserLogoutUrl = GlobalInfo.warmshowersBaseUrl + "/services/rest/user/logout";
private static final String TAG = "HttpAuthenticator";
private List<NameValuePair> getCredentialsFromAccount() throws OperationCanceledException, AuthenticatorException, IOException, NoAccountException {
List<NameValuePair> credentials = new ArrayList<NameValuePair>();
String username = AuthenticationHelper.getAccountUsername();
String password = AuthenticationHelper.getAccountPassword();
credentials.add(new BasicNameValuePair("username", username));
credentials.add(new BasicNameValuePair("password", password));
return credentials;
}
/**
* Hits the logout service and then the login.
*
* Returns
* - userid
* - 0 if already logged in
*/
public int authenticate() throws HttpAuthenticationFailedException, IOException, JSONException, NoAccountException {
RestClient authClient = new RestClient();
int userId = 0;
try {
// Log.i(TAG, "Routine logout attempt");
authClient.authpost(wsUserLogoutUrl);
} catch (Exception e) {
Log.i(TAG, "Exception on logout - not to worry: " + e.toString());
// We don't care a lot about this, as we were just trying to ensure clean login.
}
try {
List<NameValuePair> credentials = getCredentialsFromAccount();
// Log.i(TAG, "Normal login attempt after logout credentials=" + credentials.toString());
JSONObject authResult = authClient.authpost(wsUserAuthUrl, credentials);
userId = authResult.getJSONObject("user").getInt("uid");
Host profileInfo = Host.CREATOR.parse(authResult.getJSONObject("user"));
MemberInfo.initInstance(profileInfo);
String cookieSessionName = authResult.getString("session_name");
String cookieSessionId = authResult.getString("sessid");
AuthenticationHelper.addCookieInfo(cookieSessionName, cookieSessionId, userId);
String filePath = MemberInfo.getMemberPhotoFilePath();
// Get the member photo if it doesn't exist already
File profileImageFile = new File(filePath);
// If the file doesn't exist or is tiny, download it, otherwise use the one we have
if (!profileImageFile.exists() || profileImageFile.length() < 1000) {
// Download it
downloadMemberPhoto(profileInfo, filePath);
}
} catch (ClientProtocolException e) {
if (e.getCause() instanceof CircularRedirectException) {
// If we get this authentication has still been successful, so ignore it
} else {
throw new HttpAuthenticationFailedException(e);
}
} catch (IOException e) {
// Rethrow, prevent the catch below from getting to it. we want to know this was IO exception
throw e;
} catch (HttpAuthenticationFailedException e) { // Attempting to do auth with wrong credentials
throw e;
} catch (NoAccountException e) {
throw e;
} catch (HttpException e) {
if (e.getMessage().equals("406")) {
Log.i(TAG, "Got error 406 attempting to log in, so ignoring");
// This is the case where we hit auth and were already authenticated... but shouldn't have happened.
} else {
throw e;
}
} catch (Exception e) {
// We might have had a json parsing or access exception - for example, if the "user" was not there,
// Could also have AuthenticatorException or OperationCancelledException here
// or if there was something wrong with what the server returned
throw new HttpAuthenticationFailedException(e);
}
return userId;
}
private File downloadMemberPhoto(Host profileInfo, String targetFilePath) {
File targetFile = new File(targetFilePath);
if (targetFile.exists()) {
targetFile.delete();
}
HttpURLConnection c = null;
FileOutputStream fos = null;
BufferedOutputStream out = null;
try {
c = (HttpURLConnection) new URL(profileInfo.getProfilePictureLarge()).openConnection();
fos = new FileOutputStream(targetFilePath);
out = new BufferedOutputStream(fos);
InputStream in = c.getInputStream();
byte[] buffer = new byte[16384];
int len = 0;
while (( len = in.read( buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.flush();
} catch (Exception e) {
Log.i(TAG, "Error: " + e);
}
finally {
try {
fos.getFD().sync();
out.close();
c.disconnect();
} catch (Exception e) {
// Don't worry about these?
}
}
return targetFile;
}
}