Java NET - Basic Authentication with URLConnection

[Updated: Jun 7, 2017, Created: Jun 7, 2017]

HTTP Basic authentication is the technique for enforcing access controls to web resources. The clients who want to access the protected resources, should send Authorization request header with an encoded (Base64) user/password value:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

If above authentication fails, the server will respond back with WWW-Authenticate response header and the status code 401 (Unauthorized):

WWW-Authenticate: Basic realm="Some value"

java.net.URLConnection provides suitable API to send 'Authorization' request header. Let's see an example how to do that.

The Server

In this example, we are going to write a very simple Java Servlet. We will also use Tomcat server (embedded), which provides container managed authorization/authentication.

Servlet

package com.logicbig.example;

import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "appController", urlPatterns = {"/"})
@ServletSecurity(
      value = @HttpConstraint(rolesAllowed = {"employee"}),
      httpMethodConstraints = {
              @HttpMethodConstraint(value = "GET", rolesAllowed = {"employee"})
      })
public class MyServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {

      PrintWriter writer = resp.getWriter();
      writer.println("User authorized= " + req.getUserPrincipal());
  }
}

src/main/webapp/WEB-INF/web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>employee-realm</realm-name>
    </login-config>

</web-app>

src/main/webapp/config/tomcat-users.xml

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
    <role rolename="employee"/>
    <user username="Tom" password="abc" roles="employee"/>
</tomcat-users>

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

URLConnection client

First, we will try to access the resource without 'Authorization' header:

package com.logicbig.example;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

public class URLConnectionClient {
  public static void main(String[] args) throws Exception {
      URL myURL = new URL("http://localhost:8080");
      URLConnection c = myURL.openConnection();
      Map<String, List<String>> headers = c.getHeaderFields();
      System.out.println("-- Response headers --");
      headers.entrySet()
             .forEach(e -> System.out.printf("%s: %s%n", e.getKey(), e.getValue()));

      System.out.println("-- Response body --");
      try (BufferedReader reader = new BufferedReader(
              new InputStreamReader(c.getInputStream()))) {
          reader.lines().forEach(System.out::println);
      }
  }
}

Output

-- Response headers --
null: [HTTP/1.1 401 Unauthorized]
Cache-Control: [private]
Server: [Apache-Coyote/1.1]
WWW-Authenticate: [Basic realm="employee-realm"]
Expires: [Wed, 31 Dec 1969 18:00:00 CST]
Content-Length: [951]
Date: [Thu, 08 Jun 2017 03:07:55 GMT]
Content-Language: [en]
Content-Type: [text/html;charset=utf-8]
-- Response body --
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 401 for URL: http://localhost:8080
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1890)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1885)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1884)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1457)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at com.logicbig.example.URLConnectionClient.main(URLConnectionClient.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.io.IOException: Server returned HTTP response code: 401 for URL: http://localhost:8080
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at sun.net.www.protocol.http.HttpURLConnection.getHeaderFields(HttpURLConnection.java:2966)
at com.logicbig.example.URLConnectionClient.main(URLConnectionClient.java:14)
... 5 more

Let's set 'Authorization' header with appropriate values:

package com.logicbig.example;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
import java.util.List;
import java.util.Map;

public class URLConnectionClient2 {
  public static void main(String[] args) throws Exception {
      URL myURL = new URL("http://localhost:8080");
      URLConnection c = myURL.openConnection();

      String authStr = Base64.getEncoder()
                             .encodeToString("Tom:abc".getBytes());
      //setting Authorization header
      c.setRequestProperty("Authorization", "Basic " + authStr);
      Map<String, List<String>> headers = c.getHeaderFields();
      System.out.println("-- Response headers --");
      headers.entrySet()
             .forEach(e -> System.out.printf("%s: %s%n", e.getKey(), e.getValue()));

      System.out.println("-- Response body --");
      try (BufferedReader reader = new BufferedReader(
              new InputStreamReader(c.getInputStream()))) {
          reader.lines().forEach(System.out::println);
      }
  }
}

Output

-- Response headers --
null: [HTTP/1.1 200 OK]
Cache-Control: [private]
Server: [Apache-Coyote/1.1]
Expires: [Wed, 31 Dec 1969 18:00:00 CST]
Content-Length: [51]
Date: [Thu, 08 Jun 2017 03:07:34 GMT]
-- Response body --
User authorized= GenericPrincipal[Tom(employee,)]

Example Project

Dependencies and Technologies Used :

  • javax.servlet-api 3.0.1 Java Servlet API
  • JDK 1.8
  • Maven 3.3.9

Url Connection Basic Authentication Example Select All Download
  • url-connection-basic-authentication
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • webapp
          • WEB-INF
          • config

See Also