/**
Copyright 2012 Fahad Al-Khameesi, Madeleine Appert, Niklas Logren, Arild Matsson and Jonathan Orr�.
This file is part of Bibbla.
Bibbla 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.
Bibbla 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 Bibbla. If not, see <http://www.gnu.org/licenses/>.
**/
package dat255.grupp06.bibbla.backend.tasks;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import dat255.grupp06.bibbla.backend.Backend;
import dat255.grupp06.bibbla.model.Credentials;
import dat255.grupp06.bibbla.utils.Error;
import dat255.grupp06.bibbla.utils.Message;
import dat255.grupp06.bibbla.utils.Session;
/**
* Logs the user into gotlib.
*
* Contains the actual implementation of network/parsing.
* Is in separate class to simplify testing (no android dependencies).
*
* @author Niklas Logren
*/
public class LoginJob {
// Global throughout the whole program. In Session-class later on.
Map<String, String> sessionCookies;
// Needed only in LoginJob.
Map<String, String> sessionVariables;
Message message;
private final Credentials credentials;
private Session session;
public LoginJob(Credentials credentials, Session session) {
this.credentials = credentials;
message = new Message();
this.session = session;
// Initialise maps.
sessionVariables = new HashMap<String, String>();
sessionCookies = new HashMap<String, String>();
}
/**
* Starts logging in.
* @returns the success of the operation.
*/
public Message run() {
// Retry login job a specified number of times.
int failureCounter = 0;
while(failureCounter < Backend.MAX_CONNECTION_ATTEMPTS) {
try {
System.out.print("\n****** LoginJob \n");
System.out.print("* getLoginForm(): ");
getLoginForm();
System.out.print("succeeded! *\n");
System.out.print("* postLoginForm(): ");
Response response = postLoginForm();
System.out.print("succeeded! *\n");
System.out.print("* loginTest(): ");
String url = parseUserUrl(response);
session.setUserUrl(url);
String name = parseUserName(response);
session.setUserName(name);
System.out.print("succeeded! *\n");
System.out.print("****** LoginJob done \n");
// We made it through.
session.setCookies(sessionCookies);
message.obj = session;
break; // Break if we succeed.
} catch (Exception e) {
failureCounter++;
System.out.print("failed. retrying... ");
}
}
// Did we fail?
if (failureCounter >= Backend.MAX_CONNECTION_ATTEMPTS) {
message.error = (message.error!=null) ? message.error : Error.LOGIN_FAILED;
System.out.print("\n****** LoginJob failed.\n");
}
else { // Nope!
System.out.print("\n****** LoginJob done.\n");
}
return message;
}
/**
* Step 1: Gets login form.
* Saves the initial session cookies, and retrieves three values.
*/
private void getLoginForm() throws Exception {
String url = "https://www.gotlib.goteborg.se/iii/cas/login?service=" +
"http%3A%2F%2Fencore.gotlib.goteborg.se%3A80%2Fiii%2Fencore" +
"%2Fj_acegi_cas_security_check&lang=swe";
// Create a request, and retrieve the response.
Response response = Jsoup.connect(url)
.method(Method.GET)
.timeout(Backend.CONNECTION_TIMEOUT)
.execute();
// Get the cookies from the response.
sessionCookies = response.cookies();
// Prepare for parsing.
Document html = response.parse();
// Get the value of <input type="hidden" name="lt" value="" />.
String lt = html.select("input[name=lt]").first().val();
sessionVariables.put("lt", lt);
// Tests.
if ((sessionVariables.get("lt") == null) ||
(sessionCookies.get("JSESSIONID") == null) ||
(sessionCookies.get("org.springframework.web.servlet." +
"i18n.CookieLocaleResolver.LOCALE") == null)) {
throw new Exception("missing cookies/variables.");
}
}
/**
* Step 2: POSTs login credentials.
* Saves new session cookies, which will be used in all requests hereafter.
*/
private Response postLoginForm() throws Exception {
// Prepare POST url (spoiler: contains variables!)
String url = "https://www.gotlib.goteborg.se/iii/cas/login;jsessionid="
+sessionVariables.get("JSESSIONID")+"?service=http%3A%2F%2Fencore.got" +
"lib.goteborg.se%3A80%2Fiii%2Fencore%2Fj_acegi_cas_security_c" +
"heck&lang="+sessionVariables.get("org.springframework.web.se" +
"rvlet.i18n.CookieLocaleResolver.LOCALE");
// Prepare POST data.
@SuppressWarnings("serial")
Map<String,String> postData = new HashMap<String,String>() {{
put("name", credentials.name);
put("code", credentials.card);
put("pin", credentials.pin);
put("lt", sessionVariables.get("lt"));
put("_eventId", "submit");
}};
// Send POST request and save response.
Response response = Jsoup.connect(url)
.method(Method.POST)
.timeout(Backend.CONNECTION_TIMEOUT)
.data(postData)
.cookies(sessionCookies)
.execute();
// These new cookies are all we'll need.
sessionCookies = response.cookies();
// Tests.
if ((sessionVariables.get("lt") == null) ||
(sessionCookies.get("JSESSIONID") == null) ||
(sessionCookies.get("III_SESSION_ID") == null)) {
throw new Exception("missing cookies/variables.");
}
return response;
}
/**
* Parse the user's "profile" URL in Session for later use.
* @param response Response from postLoginForm()
* @return URL for the user's personal page
* @throws IOException if parsing failed or the URL could't be found (for
* any reason)
*/
private static String parseUserUrl(Response response) throws IOException {
Document html = response.parse();
String url = html.select(".myAccountLink").attr("href");
if (url.equals("")) throw new IOException("no link found");
// Replace http://...:80/... by https://.../...
return "https://www.gotlib.goteborg.se" +
url.split(":80")[1] + "/";
}
/**
*
* @param response
* @return
* @throws IOException if parsing went wrong
*/
private String parseUserName(Response response) throws IOException {
Document html = response.parse();
// Find name on form "Family-name, First-name"
try {
String accountInfo = html.select(".myAccountInfo").first().text();
String[] splitGreeting = accountInfo.split(" \\|")[0].split(", ");
String wholeName = splitGreeting[2]+" "+splitGreeting[1];
return wholeName;
} catch (NullPointerException e) {
return "";
}
}
}