/* * 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.util.Log; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.NTCredentials; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.protocol.ClientContext; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import ca.GabrielCastro.fanshaweconnect.App; import ca.GabrielCastro.fanshaweconnect.util.SupportASyncTask; import ca.GabrielCastro.fanshawelogin.CONSTANTS; import eu.masconsult.android_ntlm.NTLMSchemeFactory; /** * A One Use Request that runs in a Background Thread to Verify a UserName/Password, * or reuseable if #doInThisThread is called directly */ public class CheckCredentials extends SupportASyncTask<Void, Void, CheckCredentials.FolAuthResponse> { private static final String TAG = "checkCred AsyncTask"; protected String userName; protected String password; protected String[] name = {"", ""}; private OnCredentialsChecked cb; /** * Constructs a request to CheckCredentials with a CallBack that will only * be called if the request is ran in a background thread through {@link #execute(Object[])} * @param userName * @param password * @param cb */ public CheckCredentials(String userName, String password, OnCredentialsChecked cb) { this.userName = userName; this.password = password; this.cb = cb; } /** * Used by the ASyncTask implementation to do work in an other thread * @see #doInThisThread() * @param params * @return */ @Override protected FolAuthResponse doInBackground(Void... params) { return doInThisThread(); } /** * Will attempt to authenticate the user on portal.myfanshawec.ca using NTLM * if that is successful the it will attempt to extract the users real name from FOL * using the portal's SSO fol_pass_thru.aspx * @return One of {@link FolAuthResponse} */ public FolAuthResponse doInThisThread() { try { DefaultHttpClient client = new DefaultHttpClient(); client.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.TRUE); client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, App.userAgent); // register ntlm auth scheme client.getAuthSchemes().register("ntlm", new NTLMSchemeFactory()); client.getCredentialsProvider().setCredentials( // Limit the credentials only to the specified domain and port new AuthScope("portal.myfanshawe.ca", -1), // Specify credentials, most of the time only user/pass is needed new NTCredentials(userName, password, "", "") ); HttpPost post = new HttpPost("https://portal.myfanshawe.ca/_layouts/Fanshawe/fol_pass_thru.aspx"); HttpContext localContext = new BasicHttpContext(); // Bind custom cookie store to the local context localContext.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore()); HttpResponse response = client.execute(post, localContext); if (!isLoggedIn(response)) { return FolAuthResponse.RETURN_INVALID; } response = client.execute(new HttpGet(CONSTANTS.SECOND_URL), localContext); Log.d(TAG, "response code " + response.getStatusLine().getStatusCode()); return doParseContent(EntityUtils.toString(response.getEntity())); } catch (Exception e) { e.printStackTrace(); return FolAuthResponse.RETURN_EXCEPTION; } } /** * Checks the response code and returns true if it is {@code 200} * @param response the response to check * @return true is the status code is 200 */ private boolean isLoggedIn(HttpResponse response) { return response.getStatusLine().getStatusCode() == 200; } /** * Extracts the persons name from FOL * @param content the HTML content of the page at {@link CONSTANTS#SECOND_URL} * @return {@link FolAuthResponse#RETURN_OK} if the name was extracted correctly * or {@link FolAuthResponse#RETURN_ERROR} if the name could not be parsed */ private FolAuthResponse doParseContent(String content) { // FirstName:'Gabriel',LastName:'Castro Londono',UserName: String nameStart = "FirstName:'"; String nameSplit = "',LastName:'"; String nameEnd = "',UserName:"; try { int startName = content.indexOf(nameStart) + nameStart.length(); int endName = content.indexOf(nameEnd, startName); name = content.substring(startName, endName).split(nameSplit); } catch (ArrayIndexOutOfBoundsException e) { return FolAuthResponse.RETURN_ERROR; } return FolAuthResponse.RETURN_OK; } /** * Used by the ASyncTask implementation to trigger the callback * @param result */ @Override protected void onPostExecute(FolAuthResponse result) { if (cb != null) { cb.credentialsChecked(result, this.name); } } /** * Gets the persons name parsed from FOL * if the name has not yet been successfully parsed * two empty strings will be returned * * @return */ public String[] getName() { return this.name; } /** * Contains all the possible Authentication Responses */ public static enum FolAuthResponse { RETURN_OK, RETURN_INVALID, RETURN_ERROR, RETURN_EXCEPTION } }