/* * This file is part of FanshaweConnect. * * Copyright 2013 Gabriel Castro (c) * * FanshaweConnect 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 2 of the License, or * (at your option) any later version. * * FanshaweConnect 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 FanshaweConnect. If not, see <http://www.gnu.org/licenses/>. */ package ca.GabrielCastro.fanshawelogin.util; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.util.Log; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import ca.GabrielCastro.fanshawelogin.CONSTANTS; /** * A One Use Request that runs in a Background Thread to Logon to the wireless network, * or reuseable if #doInThisThread is called directly */ public class LogOnRequest extends AsyncTask<String, Integer, LogOnRequest.Status> { /** * Contains the possible responses from trying to login */ public static enum Status { RETURN_OK, RETURN_NOT_AT_FANSHAWE, RETURN_AT_FANSHAWE_OK, RETURN_UNABLE_TO_LOGIN, RETURN_CONNECTION_ERROR, RETURN_USPECIFIED_ERROR, RETURN_INVALID_CRED, RETURN_NO_WIFI } public static final String TAG = "LogOnRequest"; /** * *** begin return codes for test uri ***** */ private static enum TestUriStatus { testUri_CONNECTION_OK, testUri_FANSHAWE_REDIRECT, testUri_OTHER_REDIRECT, testUri_NULL_ENTITY; } /** * *** begin return codes for do Logon ***** */ private static enum LogOnResult { OK, LOGGED_ON, INVALID_USER_PASS, OTHER_ERROR } private static final String SSID_REGEX = "^\"Fanshawe (Students|Employees)\"$"; private static final URI TEST_URI; private static final URI LOGON_URL; private LoggedOnListener cb; private Context context; private String userName = ""; private String password = ""; static { URI test = null; URI logon = null; try { test = new URI("http://www.apple.com/library/test/success.html"); logon = new URI("https://virtualwireless.fanshawec.ca/login.html"); } catch (URISyntaxException e) { // WONT HAPPEN, THE VALUES ARE HARD CODED } TEST_URI = test; LOGON_URL = logon; } /** * Constructs a Request Object using a listener that will only be called if Logon * is done in a background thread * * @param listener Where to notify after the logon is complete * @param userName The User name to authenticate with * @param password The Password to authenticate with * @param context Application Context */ public LogOnRequest(LoggedOnListener listener, String userName, String password, Context context) { this.userName = userName; this.password = password; this.cb = listener; this.context = context.getApplicationContext(); } /** * Checks Apples Test Web site to see if our web traffic is being redirected * * @return One of {@link TestUriStatus} * @throws IOException */ private static TestUriStatus checkTestURI() throws IOException { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(TEST_URI); HttpResponse response = client.execute(get); // check if the server response is NULL if (response.getEntity() != null) { String sResponse = EntityUtils.toString(response.getEntity()); // check if we got a redirect if (sResponse.contains("<TITLE>Success</TITLE>")) { return TestUriStatus.testUri_CONNECTION_OK; } else if (sResponse.contains("<TITLE> Web Authentication Redirect</TITLE>") && sResponse.contains("URL=https://virtualwireless.fanshawec.ca/login.html?")) { // DETECT // FANSHAWE return TestUriStatus.testUri_FANSHAWE_REDIRECT; } return TestUriStatus.testUri_OTHER_REDIRECT; } return TestUriStatus.testUri_NULL_ENTITY; } /** * For AsyncTask behaviour * @see #doInThisThread() */ @Override protected Status doInBackground(String... args) { return doInThisThread(); } /** * The main login logic : <br/> * <p> * <ul> * <li> Checks that the device is connected to an SSID matched by {@link #SSID_REGEX}</li> * <li> TODO : Check the MAC adress against some list</li> * <li> Checks if The user is logged in by calling {@link #checkTestURI()}</li> * <li> Attempts to Authenticate the user</li> * <li> Verifies that Authentication worked</li> * </ul> * </p> * * * @return one of {@link Status} */ public Status doInThisThread() { if (Tools.isDebugLevelSet(CONSTANTS.DEBUG_THREAD_LONGER)) { try { Thread.sleep(5000); } catch (InterruptedException e) { } } WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); if (wifiInfo == null || wifiInfo.getSSID() == null) { return Status.RETURN_NO_WIFI; } String ssid = wifiInfo.getSSID(); // Check the ssid if (!ssid.matches(SSID_REGEX)) { Log.d(TAG, "ssid: |" + ssid + "| regex: |" + SSID_REGEX + "|"); return Status.RETURN_NOT_AT_FANSHAWE; } if (false) { // TODO if checking MAC byte[] macConnected = new byte[6]; String[] macString = wifiInfo.getBSSID().split(":"); for (int i = 0; i < macString.length; i++) { macConnected[i] = Tools.hexStringToByteArray(macString[i])[0]; } // TODO acctually chack the mac } try { if (checkTestURI() != TestUriStatus.testUri_CONNECTION_OK) { switch (doLogon()) { case OK: break; case LOGGED_ON: case OTHER_ERROR: return Status.RETURN_UNABLE_TO_LOGIN; case INVALID_USER_PASS: return Status.RETURN_INVALID_CRED; } switch (checkTestURI()) { case testUri_CONNECTION_OK: return Status.RETURN_OK; case testUri_FANSHAWE_REDIRECT: case testUri_OTHER_REDIRECT: case testUri_NULL_ENTITY: return Status.RETURN_UNABLE_TO_LOGIN; } } return Status.RETURN_UNABLE_TO_LOGIN; } catch (IOException e) { return Status.RETURN_CONNECTION_ERROR; } catch (Exception e) { return Status.RETURN_USPECIFIED_ERROR; } } /** * Sends a logon request to https://virtualwireless.fanshawec.ca/login.html * should only be called AFTER it is confirmed that is was absolutely necessary * @return One of {@link LogOnResult} * @throws IOException */ private LogOnResult doLogon() throws IOException { List<NameValuePair> pairs = new ArrayList<NameValuePair>(8); { pairs.add(new BasicNameValuePair("buttonClicked", "4")); pairs.add(new BasicNameValuePair("err_flag", "0")); pairs.add(new BasicNameValuePair("err_mas", "")); pairs.add(new BasicNameValuePair("info_flag", "0")); pairs.add(new BasicNameValuePair("info_msg", "")); pairs.add(new BasicNameValuePair("redirect_url", "")); pairs.add(new BasicNameValuePair("username", this.userName)); pairs.add(new BasicNameValuePair("password", this.password)); } HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(LOGON_URL); post.setEntity(new UrlEncodedFormEntity(pairs)); HttpEntity entity = client.execute(post).getEntity(); String response = EntityUtils.toString(entity); if (response.contains("You are already logged in. No further action is required on your part.")) { return LogOnResult.LOGGED_ON; } if (response.contains("<input type=\"hidden\" name=\"err_flag\" size=\"16\" maxlength=\"15\" value=\"1\">")) { return LogOnResult.INVALID_USER_PASS; } if (response.contains("<title>Logged In</title>")) { return LogOnResult.OK; } return LogOnResult.OTHER_ERROR; } /** * Used by the ASyncTask Implementation to notify the caller of The Result */ @Override protected void onPostExecute(Status result) { if (cb != null) cb.loggedOn(result); } }