11 February 2014

Server simple Authentication in Java

You may adopt one of two strategies: (1) use the default Basic Authenticator, or (2) implement the authentication by cookies, as explained in Node.js authentication.

1. BasicAuthenticator


For that, it suffices to create a BasicAuthenticator and assign it to the routes (contexts) you want protected.

1
2
3
4
5
6
server.createContext("/", new info()).setAuthenticator(new BasicAuthenticator("get") {
    @Override
    public boolean checkCredentials(String user, String pwd) {
        return user.equals("admin") && pwd.equals("admin");
    }
});

The class BasicAuthenticator exposes the method checkCredentials, in which you need to check if the credentials (usually, username and password) are accepted. If you instantiate the class BasicAuthenticator separately (as shown below), you may assign it to multiple routes (contexts). Moreover, you may instantiate multiple authenticators, each with its own checking of credentials, and subsequently use different authenticators for different routes.

Here is the full example:

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
import java.io.*;
import java.util.*;
import com.sun.net.httpserver.*;

public class httpserver {

  public static void main(String[] args) throws Exception {

    BasicAuthenticator BasicAuth = new BasicAuthenticator("get") {
        @Override
        public boolean checkCredentials(String user, String pwd) {
            return user.equals("admin") && pwd.equals("admin");
        }
    };

    HttpServer server = HttpServer.create(new java.net.InetSocketAddress(8080), 0);
    server.createContext("/", new info()).setAuthenticator(BasicAuth);

    server.setExecutor(null);
    server.start();
    System.out.println("> Server running on PORT: 8080...");
  }

  static class info implements HttpHandler {
    public void handle(HttpExchange t) throws IOException {
      String RES = "<html><body>";
      RES += "<form action='/' method='GET'>";
      RES += "<input type='text' name='issue' value='Check string for tests.'/>";
      RES += "<input type='text' name='answer' value='Another check string.'/>";
      RES += "<input type='submit' value='Submit (get)'/>";
      RES += "</form>";
      RES += "<table style='font:normal 10pt sans-serif;'>";
      RES += "<tr><td bgColor='#ff8'>URI/path:</td><td>" + t.getRequestURI().getPath() + "</td></tr>";
          String q = t.getRequestURI().getQuery();
          if(q != null) {
            String[] arr = q.split("&");
            for(int i=0; i < arr.length; i++) {
              int ix = arr[i].indexOf('=');
              arr[i] = "<b style='color:blue;'>" + arr[i].substring(0, ix) + "</b>: " + java.net.URLDecoder.decode(arr[i].substring(ix+1), "UTF-8");
            }
            RES += "<tr><td bgColor='#ff8' valign='top'>QUERY:</td><td>" + String.join("<br>", arr) + "</td></tr>";
          }
      RES += "<tr><td bgColor='#ff8'>PROTOCOL:</td><td>" + t.getProtocol() + "</td></tr>";
      RES += "<tr><td bgColor='#ff8'>METHOD:</td><td>" + t.getRequestMethod() + "</td></tr>";

      RES += "<tr bgColor='#8f8'><td>HEADERS:</td><td></td></tr>";
      Headers hs = t.getRequestHeaders();
      for(Map.Entry> h : hs.entrySet()) {
        RES += "<tr><td bgColor='#ff8'>"+h.getKey()+"</td><td>" + h.getValue().get(0) + "</td></tr>";;
      }
      RES += "<tr bgColor='#8f8'><td>Content-Type</td><td>"+ hs.get("Content-Type") +"</td></tr>";
      RES += "<tr bgColor='#8f8'><td>Accept</td><td>"+ hs.get("Accept") +"</td></tr>";

      byte[] decoded = Base64.getDecoder().decode(hs.get("Authorization").get(0).substring(6));
      RES += "<tr bgColor='#88f'><td>Authorization</td><td>"+ (new String(decoded)) +"</td></tr>";
      RES += "<tr bgColor='#8f8'><td>Cookie</td><td>"+ hs.get("Cookie") +"</td></tr>";

      RES += "</table></body></html>";
      respond(t, RES, "html");
    }
  }

  static void respond(HttpExchange t, String Res, String type) throws IOException {

    Headers h = t.getResponseHeaders();
    h.set("Content-Type", "text/" + type);
    t.sendResponseHeaders(200, Res.length());
    OutputStream os = t.getResponseBody();
    os.write(Res.getBytes());
    os.close();
  }  
}

2. Authentication by cookies


Here you don't need but normal response code 200, as it was explained here. When the credentials are requested, supplied by the client (usually, by POST method), and verified to be correct, you set the response header cookie, along with its expiry (expiry date/time or Max-Age, in seconds). Just like this:

1
2
Headers h = t.getResponseHeaders();
h.set("Set-Cookie", "user=UserName; Max-Age=60");

Then, in the next requests, you just check if cookie is set and if it contains the right username or token:

1
2
Headers hs = t.getRequestHeaders();
hs.get("Cookie").get(0);

Notice that cookie header returns an array, therefore we use only its first element. When the logout is requested, you just set the cookie Max-Age to zero or negative value, which will remove the cookie, i.e. the access will become unauthorised again. Here is a full code of Authentication based on Cookies.

No comments:

Post a Comment