Added README.txt and GPL Header to Source Files
[DHBWCampusApp.git] / app / src / main / java / de / dhbwloe / campusapp / wifi / SecureLoginManager.java
1 /* SecureLoginManager.java
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 package de.dhbwloe.campusapp.wifi;
17
18 import android.app.DownloadManager;
19 import android.net.NetworkInfo;
20 import android.net.SSLCertificateSocketFactory;
21 import android.net.SSLSessionCache;
22 import android.net.wifi.WifiInfo;
23 import android.os.AsyncTask;
24 import android.util.Log;
25
26 import java.io.BufferedReader;
27 import java.io.BufferedWriter;
28 import java.io.IOException;
29 import java.io.InputStreamReader;
30 import java.io.OutputStream;
31 import java.io.OutputStreamWriter;
32 import java.io.UnsupportedEncodingException;
33 import java.net.HttpURLConnection;
34 import java.net.URL;
35 import java.net.URLConnection;
36 import java.net.URLEncoder;
37 import java.security.KeyManagementException;
38 import java.security.NoSuchAlgorithmException;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.regex.Matcher;
42 import java.util.regex.Pattern;
43
44 import javax.net.ssl.HttpsURLConnection;
45 import javax.net.ssl.KeyManager;
46 import javax.net.ssl.SSLContext;
47 import javax.net.ssl.SSLSocket;
48 import javax.net.ssl.SSLSocketFactory;
49 import javax.net.ssl.TrustManager;
50
51 import cz.msebera.android.httpclient.HttpVersion;
52 import cz.msebera.android.httpclient.NameValuePair;
53 import cz.msebera.android.httpclient.client.HttpClient;
54 import cz.msebera.android.httpclient.client.methods.HttpPost;
55 import cz.msebera.android.httpclient.conn.ClientConnectionManager;
56 import cz.msebera.android.httpclient.conn.scheme.PlainSocketFactory;
57 import cz.msebera.android.httpclient.conn.scheme.Scheme;
58 import cz.msebera.android.httpclient.conn.scheme.SchemeRegistry;
59 import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
60 import cz.msebera.android.httpclient.impl.conn.tsccm.ThreadSafeClientConnManager;
61 import cz.msebera.android.httpclient.message.BasicNameValuePair;
62 import cz.msebera.android.httpclient.params.BasicHttpParams;
63 import cz.msebera.android.httpclient.params.HttpParams;
64 import cz.msebera.android.httpclient.params.HttpProtocolParams;
65 import cz.msebera.android.httpclient.protocol.HTTP;
66 import de.dhbwloe.campusapp.CampusAppContext;
67
68 /**
69  * Created by pk910 on 08.02.2016.
70  */
71 public class SecureLoginManager extends AsyncTask<SecureLoginTask, Void, SecureLoginTask> {
72     private static final String SECURELOGIN_URL = "https://securelogin1.dhbw-loerrach.de/cgi-bin/login";
73     private static final int SECURELOGIN_TIMEOUT = 20000;
74     private static final int SECURELOGIN_HANDSHAKE_TIMEOUT = 10000;
75     private static String SECURELOGIN_FAILED_REGEX = "Authentication failed";
76     private static String SECURELOGIN_SUCCESS_REGEX = "User Authenticated";
77
78     public interface SecureLoginResult {
79         void onSecureLoginFailed(String errMsg);
80         void onSecureLoginSuccess();
81     }
82
83     private CampusAppContext AppContext;
84     private SecureLoginTask task;
85     private String responseString;
86
87     @Override
88     protected SecureLoginTask doInBackground(SecureLoginTask... params) {
89         task = params[0];
90         if (AppContext == null)
91             AppContext = CampusAppContext.getInstance();
92
93         task.responseReceived = false;
94         task.responseString = null;
95
96         //build login post request:
97         //https://securelogin1.dhbw-loerrach.de/cgi-bin/login
98         // user=***censored***
99         // password=***censored***
100         // cmd=authenticate
101         // Login=Log+In
102
103         /* Dear DHBW Tech Guys
104         * Go and replace these fucking outdated and insecure SSL implementation for your "secure"login page!
105         * 3DES_EDE_CBC
106         *
107         * Ok,  after ~3 days android ssl library analysis, i've finnaly made it communicating with an 3DES Endpoint.
108         * Dear DHBW Tech Guys, gu fuck yourself! If you don't know why, continue (^.^)
109         */
110
111         //SSLSocket socket = null;
112         StringBuilder responseString = new StringBuilder();
113         try {
114             SSLContext sslContext = SSLContext.getInstance("TLS");
115             SecureLoginTrustManager loginTrustManager = new SecureLoginTrustManager();
116             sslContext.init(null, new TrustManager[]{loginTrustManager}, null);
117             SSLSocketFactory innerSslSocketPactory = SSLCertificateSocketFactory.getInsecure(SECURELOGIN_HANDSHAKE_TIMEOUT, new SSLSessionCache(AppContext.getMainActivity()));
118             SSLSocketFactory sslSocketFactory = new SecureLoginSocketFactory(sslContext, innerSslSocketPactory);
119
120             //SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket("securelogin1.dhbw-loerrach.de", 443);
121             //socket.startHandshake();
122
123             Log.i("SecureLogin", "HTTPS INITIALIZED");
124
125             URL url = new URL(SECURELOGIN_URL);
126             URLConnection conn = url.openConnection();
127
128             if (conn instanceof HttpsURLConnection) {
129                 ((HttpsURLConnection)conn).setSSLSocketFactory(sslSocketFactory);
130                 ((HttpsURLConnection )conn).setRequestMethod("POST");
131                 ((HttpsURLConnection)conn).setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
132             } else {
133                 ((HttpURLConnection) conn).setRequestMethod("POST");
134             }
135             conn.setConnectTimeout(SECURELOGIN_TIMEOUT);
136             conn.setReadTimeout(SECURELOGIN_TIMEOUT);
137
138             conn.setDoInput(true);
139             conn.setDoOutput(true);
140
141             List<NameValuePair> postData = new ArrayList<NameValuePair>();
142             postData.add(new BasicNameValuePair("cmd", "authenticate"));
143             postData.add(new BasicNameValuePair("Login", "Log+In"));
144             postData.add(new BasicNameValuePair("user", task.settings.username));
145             postData.add(new BasicNameValuePair("password", task.settings.password));
146
147             OutputStream os = conn.getOutputStream();
148             BufferedWriter writer = new BufferedWriter(
149                     new OutputStreamWriter(os, "UTF-8"));
150             String postString = encodePostData(postData);
151             writer.write(postString);
152             writer.flush();
153             writer.close();
154             os.close();
155
156             conn.connect();
157
158             int responseCode;
159             if (conn instanceof HttpsURLConnection)
160                 responseCode = ((HttpsURLConnection)conn).getResponseCode();
161             else
162                 responseCode = ((HttpURLConnection)conn).getResponseCode();
163
164             if (responseCode == HttpsURLConnection.HTTP_OK) {
165                 task.responseReceived = true;
166                 String line;
167                 BufferedReader br=new BufferedReader(new InputStreamReader(conn.getInputStream()));
168                 while ((line=br.readLine()) != null) {
169                     responseString.append(line);
170                 }
171             } else {
172                 task.responseError = "HTTP " + Integer.toString(responseCode);
173             }
174
175         } catch (Exception e) {
176             task.responseError = e.getMessage();
177             Log.i("SecureLogin", e.toString() + ":" + e.getMessage());
178         }
179
180         task.responseString = responseString.toString();
181
182         return task;
183     }
184
185     @Override
186     protected void onPreExecute() {
187         super.onPreExecute();
188
189     }
190
191     @Override
192     protected void onPostExecute(SecureLoginTask task) {
193         super.onPostExecute(task);
194
195         boolean success = false;
196         String error = null;
197
198         if(task.responseReceived) {
199             Pattern p1 = Pattern.compile(SECURELOGIN_SUCCESS_REGEX);
200             Pattern p2 = Pattern.compile(SECURELOGIN_FAILED_REGEX);
201
202             Matcher m1 = p1.matcher(task.responseString);
203             Matcher m2 = p2.matcher(task.responseString);
204
205             if(m1.find())
206                 success = true;
207             else if(m2.find())
208                 error = "Incorrect username or password code entered. Please try again.";
209             else
210                 error = "An unknown error occured!";
211         } else if(task.responseError != null) {
212             error = task.responseError;
213         }
214         if(success)
215             task.loginCallback.onSecureLoginSuccess();
216         else
217             task.loginCallback.onSecureLoginFailed(error);
218     }
219
220     private String encodePostData(List<NameValuePair> params) throws UnsupportedEncodingException {
221         StringBuilder result = new StringBuilder();
222         boolean first = true;
223
224         for (NameValuePair pair : params) {
225             if (first)
226                 first = false;
227             else
228                 result.append("&");
229
230             result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
231             result.append("=");
232             result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
233         }
234
235         return result.toString();
236     }
237 }