-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBasicAuthWebServer.java
More file actions
351 lines (317 loc) · 12.9 KB
/
BasicAuthWebServer.java
File metadata and controls
351 lines (317 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/* Victor Cervantes
CS361
October 3, 2018
*/
/***********************************************************************
SimpleWebServer.java
This toy web server is used to illustrate security vulnerabilities.
This web server only supports extremely simple HTTP GET requests.
This file is also available at http://www.learnsecurity.com/ntk
***********************************************************************/
import java.io.*;
import java.net.*;
import java.util.*;
//import sun.misc.BASE64Decoder;
/*This will be used to pause between failed requests*/
import java.util.concurrent.TimeUnit;
public class BasicAuthWebServer {
/* Run the HTTP server on this TCP port. */
private static final int PORT = 8887;
/*This is a static number of max allowed failed requests i set it to 5 for testing purposes*/
private static final int MAXREQUESTS = 6;
/*The two arraylists below are to hold the ip number and number of failed requests in parllel*/
private ArrayList<String> reqIP = new ArrayList<>();
private ArrayList<Integer> numReq = new ArrayList<>();
/* The socket used to process incoming connections from web clients */
private static ServerSocket dServerSocket;
public BasicAuthWebServer () throws Exception
{
dServerSocket = new ServerSocket (PORT);
}
public void run() throws Exception
{
while (true)
{
/* wait for a connection from a client */
Socket s = dServerSocket.accept();
/* then process the client's request */
processRequest(s);
}
}
private String checkPath (String pathname) throws Exception
{
File target = new File (pathname);
File cwd = new File (System.getProperty("user.dir"));
String s1 = target.getCanonicalPath();
String s2 = cwd.getCanonicalPath();
if (!s1.startsWith(s2))
throw new Exception();
else
return s1;
}
/* Reads the HTTP request from the client, and
responds with the file the user requested or
a HTTP error code. */
public void processRequest(Socket s) throws Exception
{
/* used to read data from the client */
BufferedReader br = new BufferedReader (new InputStreamReader (s.getInputStream()));
/* used to write data to the client */
OutputStreamWriter osw = new OutputStreamWriter (s.getOutputStream());
/* read the HTTP request from the client */
String request = br.readLine();
String command = null;
String pathname = null;
try
{
/* parse the HTTP request */
StringTokenizer st =
new StringTokenizer (request, " ");
command = st.nextToken();
pathname = st.nextToken();
} catch (Exception e)
{
osw.write ("HTTP/1.0 400 Bad Request\n\n");
osw.close();
return;
}
/*This will register the client's ip address*/
String ipAddress = s.getRemoteSocketAddress().toString().substring(0, s.getRemoteSocketAddress().toString().length()-6);
/*initializing a variable of numRequests*/
int numRequests = 0;
/*if the given ipaddress has already had failed requests the value of numRequests will be upated accordingly*/
if(reqIP.contains(ipAddress))
{
numRequests = numReq.get(reqIP.indexOf(ipAddress));
}
logEntry("FileRequestslog.txt", command + " " + pathname + " " + ipAddress + "\n");
if (command.equals("GET"))
{
Credentials c = getAuthorization(br);
/*added the parameter to ensure the requests will not be met if client has exceeded number of allowable failed requests*/
if ((MAXREQUESTS >= numRequests) && (c != null) && ( MiniPasswordManager.checkPassword(c.getUsername(), c.getPassword())))
{
String lastLogin = "First Time loging in";
try
{
/*sets lastLogin to last entry on login log for each client if there is no log the default is: "First time loging in"*/
BufferedReader bufr = new BufferedReader(new FileReader(c.getUsername() + "login.txt"));
String temp = "";
while(temp != null)
{
lastLogin = temp;
temp = bufr.readLine();
}
}
catch(Exception e)
{
}
/*This lets the client know the last time they logged in*/
osw.write("last login: " + lastLogin + "\n");
serveFile(osw, pathname);
if(reqIP.contains(ipAddress))
{
int idx = reqIP.indexOf(ipAddress);
reqIP.remove(idx);
numReq.remove(idx);
}
logEntry(c.getUsername() + "login.txt", c.getUsername() + "\n");
}
else if(MAXREQUESTS < numRequests)
{
/*If the client exceeds the number of allowable failed requests they will no longer be prompted to login*/
osw.write("You have exceeded the number of failed logins. Please contact the Administrator.");
}
else
{
logEntry("failedLogins.txt", ipAddress + " " + "\n"); //loging ip address of failed login client
osw.write ("HTTP/1.0 401 Unauthorized\n");
int x = 0;
if(reqIP.contains(ipAddress))
{
x =(int)Math.pow(2,numReq.get(reqIP.indexOf(ipAddress)));
}
System.out.println("waiting..." + x + " seconds \nYou have had " + numRequests + " failed login attempts \nYour ip will be locked after " + MAXREQUESTS + " failed login attempts");
TimeUnit.SECONDS.sleep(x);
if(reqIP.contains(ipAddress))
{
int idx = reqIP.indexOf(ipAddress);
numReq.set(idx, numReq.get(idx) + 1);
}
else
{
reqIP.add(ipAddress);
numReq.add(1);
}
osw.write ("WWW-Authenticate: Basic realm=\"BasicAuthWebServer\"\n\n");
}
}
else if(command.equals("PUT"))
{
//if request is PUT use storeFile method
Credentials c = getAuthorization(br);
if ((MAXREQUESTS >= numRequests) && (c != null) && (MiniPasswordManager.checkPassword(c.getUsername(), c.getPassword())))
{
storeFile(br, osw, pathname);
if(reqIP.contains(ipAddress))
{
int idx = reqIP.indexOf(ipAddress);
reqIP.remove(idx);
numReq.remove(idx);
}
}
else if(MAXREQUESTS < numRequests)
{
osw.write("You have exceeded the number of failed login attempts. \nPlease contact the Administrator.");
}
else
{
logEntry("failedLogins.txt", ipAddress + " " + "\n"); //loging ip address of failed login client
osw.write ("HTTP/1.0 401 Unauthorized\n");
int x = 0;
if(reqIP.contains(ipAddress))
{
x = (int)Math.pow(2,numReq.get(reqIP.indexOf(ipAddress)));
}
System.out.println("waiting..." + x + " seconds \nYou have had " + numRequests + " failed login attempts \nYour ip will be locked after " + MAXREQUESTS + " failed login attempts");
TimeUnit.SECONDS.sleep(x);
if(reqIP.contains(ipAddress))
{
int idx = reqIP.indexOf(ipAddress);
numReq.set(idx, numReq.get(idx) + 1);
}
else
{
reqIP.add(ipAddress);
numReq.add(1);
}
osw.write ("WWW-Authenticate: Basic realm=\"BasicAuthWebServer\"\n\n");
}
}
else
{
/* if the request is a NOT a GET,
return an error saying this server
does not implement the requested command */
osw.write ("HTTP/1.0 501 Not Implemented\n\n");
}
/* close the connection to the client */
osw.close();
}
private Credentials getAuthorization (BufferedReader br) {
try {
String header = null;
while (!(header = br.readLine()).equals("")) {
System.err.println (header);
if (header.startsWith("Authorization:")) {
StringTokenizer st = new StringTokenizer(header, " ");
st.nextToken(); // skip "Authorization"
st.nextToken(); // skip "Basic"
// String input = Base64.getDecoder().decode(st.nextToken())
return new Credentials(st.nextToken());
}
}
} catch (Exception e) {
System.out.println(e);
}
return null;
}
public void serveFile (OutputStreamWriter osw, String pathname) throws Exception {
FileReader fr=null;
int c=-1;
StringBuffer sb = new StringBuffer();
/* remove the initial slash at the beginning
of the pathname in the request */
if (pathname.charAt(0)=='/')
pathname=pathname.substring(1);
/* if there was no filename specified by the
client, serve the "index.html" file */
if (pathname.equals(""))
pathname="index.html";
/* try to open file specified by pathname */
try {
fr = new FileReader (checkPath(pathname));
c = fr.read();
}
catch (Exception e) {
/* if the file is not found,return the
appropriate HTTP response code */
osw.write ("HTTP/1.0 404 Not Found\n\n");
return;
}
/* if the requested file can be successfully opened
and read, then return an OK response code and
send the contents of the file */
osw.write ("HTTP/1.0 200 OK\n\n");
while (c != -1) {
sb.append((char)c);
c = fr.read();
}
osw.write (sb.toString());
}
public void storeFile(BufferedReader br, OutputStreamWriter osw, String pathname) throws Exception
{
FileWriter fw = null;
try
{
fw = new FileWriter(checkPath(pathname));
String s = br.readLine();
while(s != null)
{
fw.write(s + "\n");
s = br.readLine();
}
fw.close();
osw.write("HTTP/1.0 201 Created\n");
}
catch(Exception e)
{
osw.write("HTTP/1.0 500 Internal Server Error");
}
}
public void logEntry(String filename, String record)
{
try
{
FileWriter fw = new FileWriter(filename, true);
fw.write(getTimestamp() + " " + record);
fw.close();
}
catch(Exception e)
{
return;
}
}
public String getTimestamp()
{
return(new Date()).toString();
}
/* This method is called when the program is run from
the command line. */
public static void main (String argv[]) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("Enter your pasword file path: ");
String pwdPath = sc.nextLine();
/* Initialize MiniPasswordManager */
MiniPasswordManager.init(pwdPath);
/* Create a BasicAuthWebServer object, and run it */
BasicAuthWebServer baws = new BasicAuthWebServer();
baws.run();
}
}
class Credentials {
private String dUsername;
private String dPassword;
public Credentials(String authString) throws Exception {
authString = new String((Base64.getDecoder().decode(authString)));
StringTokenizer st = new StringTokenizer(authString, ":");
dUsername = st.nextToken();
dPassword = st.nextToken();
}
public String getUsername() {
return dUsername;
}
public String getPassword() {
return dPassword;
}
}