1

I Implemented a very simple HTTP Server as described here. I managed to get the authentication working by using the Authentication header but I cannot figure out how to take the credentials from a form and use them to authenticate with the server. How is this usually done?

Code:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.BasicAuthenticator;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class SimpleHttpServer3 {

  public static void main(String[] args) throws Exception {
    HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
    server.createContext("/info", new InfoHandler());
    HttpContext hc1 = server.createContext("/get", new GetHandler());
    hc1.setAuthenticator(new BasicAuthenticator("get") {
        @Override
        public boolean checkCredentials(String user, String pwd) {
            return user.equals("admin") && pwd.equals("password");
        }
    });
    server.setExecutor(null); // creates a default executor
    server.start();
    System.out.println("The server is running");
  }

  // http://localhost:8000/info
  static class InfoHandler implements HttpHandler {
    public void handle(HttpExchange httpExchange) throws IOException {
      String response = "Use /get to authenticate (user:admin pwd:password)";
      SimpleHttpServer3.writeResponse(httpExchange, response.toString());
    }
  }

  static class GetHandler implements HttpHandler {
    public void handle(HttpExchange httpExchange) throws IOException {
      StringBuilder response = new StringBuilder();
      response.append("<html><body>");
      response.append("hello " + httpExchange.getPrincipal().getUsername());
      response.append("</body></html>");
      SimpleHttpServer3.writeResponse(httpExchange, response.toString());
    }
  }

  public static void writeResponse(HttpExchange httpExchange, String response) throws IOException {
    httpExchange.sendResponseHeaders(200, response.length());
    OutputStream os = httpExchange.getResponseBody();
    os.write(response.getBytes());
    os.close();
  }

}
Neuron
  • 5,141
  • 5
  • 38
  • 59
Samantha Catania
  • 5,116
  • 5
  • 39
  • 69

2 Answers2

1

Typically most people would use an authentication framework like Shiro or Spring Security.

These frameworks register a Servlet filter on a pattern, such as /* to enforce authentication on all requests. They store authentication data in the Servlet session to keep users logged in between requests, which is usually done by the HTTP server implicitly via Cookies. They also register a special context to accept form based authentication requests, such as POST requests to /login.

These form based endpoints will read, typically a application/x-www-form-urlencoded, request and pull out the submitted username and password, hash the password the same way that the server stores the password and compare them to verify the authentication principals.

Alex
  • 2,435
  • 17
  • 18
  • I was trying to avoid Spring since it seemed a little over the top for my very simple project but at the end it seems like it's my best choice – Samantha Catania Jan 05 '15 at 09:26
  • @SamanthaCatania, I agree, if you're trying to keep it simple go with Shiro, it's an excellent framework and doesn't need to pull in any extra external dependencies – Alex Jan 05 '15 at 14:10
  • Spring seems to have more client side browser support or did I miss something? – Samantha Catania Jan 05 '15 at 14:45
0

Basic Authentication protocol states the client request should have a header in the form of

Authorization: Basic Base64Encoded(username:password)

where Base64Encoded(username:password) is an actual Base64 encoded string of the username:password. For example, if my username and password are peeskillet:pass, the header should be sent out as

Authorization: Basic cGVlc2tpbGxldDpwYXNz

In the example from your link, it's using Basic authentication. The URL to the protected resource is

http://localhost:8000/get

You can go to your browser to the URL, and you will see a dialog (in Firefox) as seen in this answer. Enter admin (username) and password (password). You will get the hello admin return message.

You don't need to do any authentication yourself (or parsing/decoding at least), as internally (I haven't checked the source code, but it seems to be the case) the BasicAuthenticator decodes and parses the Authorization header and passes the username and password to the checkCredentials method that you implements. Since it simple only allows admin/password, that is the only combination that will authenticate.

Just for completeness, the decoding/parsing (in pseudo-code) might look something like

String authHeader = request.getHeader("Authorization");
String[] split = authHeader.split("\\s");
String credentials = split[1];
String decoded = Base64.decode(credentials);
String[] userPass = decoded.split(":");

String username = userPass[0];
String password = userPass[1];

boolean authenticated = checkCredentials(username, password);

If you want to try and make a request with code, then you would need to set the Authorization header in the request. The value would be a Base64 encoded string of admin:password, which is YWRtaW46cGFzc3dvcmQ=. So the header should be sent out as

Authorization: Basic YWRtaW46cGFzc3dvcmQ=

For other combinations, you can just go here to type in the combinations, or Java 8 has the java.util.Base64 class that you can use to encode the credentials

String cred = "admin:password";
String encoded = Base64.getEncoder().encodeToString(cred.getBytes());
System.out.println(encoded);
// YWRtaW46cGFzc3dvcmQ=
Neuron
  • 5,141
  • 5
  • 38
  • 59
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • The original question states he has basic authentication working and was looking for information on how form based logins work, which implies session usage etc. And this falls under the "don't re-invent the wheel" category, as frameworks like Shiro or Spring Security are well established at maintaining authentication state – Alex Jan 03 '15 at 05:32
  • @Alex true, I may have misread it or misunderstood it, but the OP has also not stated a client. For all we know its a Swing app the OP is playing around with. There are too many possibilities out there. But without knowing the client the OP intends to use, I don't think any answer is just any options thrown against the wall, hoping it sticks :-) But you seem to be correct about my possible misunderstanding of the question. We can wait for clarification from the OP – Paul Samsotha Jan 03 '15 at 05:53