package com.markupartist.iglaset.provider;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import com.markupartist.iglaset.util.HttpManager;
public class AuthStore {
private static final String TAG = AuthStore.class.getSimpleName();
private static final String AUTH_BASE_URI_V2 = "http://www.iglaset.se/user_session.xml";
private AuthStore() {
}
private static class SingletonHolder {
public static final AuthStore instance = new AuthStore();
}
public static AuthStore getInstance() {
return SingletonHolder.instance;
}
public void authenticateUser(Context context)
throws AuthenticationException, IOException {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(context);
Authentication authResponse = null;
if (sharedPreferences.contains("preference_username")
&& sharedPreferences.contains("preference_password")) {
String username = sharedPreferences.getString("preference_username", "");
String password = sharedPreferences.getString("preference_password", "");
try {
authResponse = authenticateUser(username, password);
} catch (AuthenticationException e) {
removeAuthentication(context);
throw e;
}
storeAuthentication(authResponse, context);
}
}
private Authentication authenticateUser(String username, String password)
throws AuthenticationException, IOException {
Log.d(TAG, "authenticate user...");
Authentication.AuthenticationData v2 = authenticateUserv2(username, password);
Authentication authResponse = new Authentication(v2);
Log.d(TAG, "Got response " + authResponse.v2.userId);
return authResponse;
}
private Authentication.AuthenticationData authenticateUserv2(String username, String password)
throws AuthenticationException, IOException {
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("user_session[username]", username));
nameValuePairs.add(new BasicNameValuePair("user_session[password]", password));
return doAuthentication(AUTH_BASE_URI_V2, nameValuePairs);
}
private Authentication.AuthenticationData doAuthentication(final String url, final ArrayList<NameValuePair> data)
throws AuthenticationException, IOException {
final HttpPost post = new HttpPost(url);
post.setEntity(new UrlEncodedFormEntity(data));
HttpEntity entity = null;
final HttpResponse response = HttpManager.execute(post);
Authentication.AuthenticationData authResponse;
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
entity = response.getEntity();
authResponse = parseResponse(entity.getContent());
if (!authResponse.looksValid()) {
Log.i(TAG, "Failed to authenticate user");
throw new AuthenticationException("Failed to authenticate user");
}
} else {
Log.w(TAG, "Request failed, http status code was not OK.");
throw new IOException();
}
return authResponse;
}
public boolean hasAuthentication(Context context) {
try {
Authentication authentication = getAuthentication(context);
if (authentication.looksValid()) {
return true;
}
} catch (AuthenticationException e) {
; // No auth or failed to request one.
}
return false;
}
public Authentication getAuthentication(Context context)
throws AuthenticationException {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
if (!sharedPreferences.contains("preference_token_v2")) {
throw new AuthenticationException("User not authenticated");
}
Authentication.AuthenticationData v2 = new Authentication.AuthenticationData(
sharedPreferences.getString("preference_token_v2", null),
sharedPreferences.getInt("preference_user_id_v2", 0));
Authentication response = new Authentication(v2);
return response;
}
private boolean removeAuthentication(Context context) {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
Editor editor = sharedPreferences.edit();
editor.remove("preference_token_v2");
editor.remove("preference_user_id_v2");
return editor.commit();
}
public boolean storeAuthentication(Authentication token,
Context context) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(context);
Editor editor = sharedPreferences.edit();
editor.putString("preference_token_v2", token.v2.token);
editor.putInt("preference_user_id_v2", token.v2.userId);
return editor.commit();
}
private Authentication.AuthenticationData parseResponse(InputStream inputStream)
throws IOException {
Authentication.AuthenticationData response = new Authentication.AuthenticationData();
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(inputStream, "UTF-8");
int eventType = xpp.getEventType();
boolean inToken = false;
boolean inUserId = false;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if ("token".equals(xpp.getName())) {
inToken = true;
} else if ("user_id".equals(xpp.getName())) {
inUserId = true;
}
} else if (eventType == XmlPullParser.END_TAG) {
if ("token".equals(xpp.getName())) {
inToken = false;
} else if ("user_id".equals(xpp.getName())) {
inUserId = false;
}
} else if (eventType == XmlPullParser.TEXT) {
if (inToken) {
response.token = xpp.getText();
}
if (inUserId) {
response.userId = Integer.parseInt(xpp.getText());
}
}
eventType = xpp.next();
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Failed to parse response " + e.getMessage());
throw new IOException(e.getMessage());
}
return response;
}
// TODO: Handling of API versions should be dealt with in a cleaner way.
public static class Authentication {
public static class AuthenticationData {
public String token;
public int userId;
public AuthenticationData() {
}
public AuthenticationData(String token, int userId) {
this.token = token;
this.userId = userId;
}
public boolean looksValid() {
return !TextUtils.isEmpty(token) && userId > 0;
}
}
public AuthenticationData v2;
public Authentication(AuthenticationData v2) {
this.v2 = v2;
}
public boolean looksValid() {
return v2.looksValid();
}
}
}