Uploaded image for project: 'Apache Drill'
  1. Apache Drill
  2. DRILL-5726

Support Impersonation without authentication for REST API

    Details

    • Type: Improvement
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.11.0
    • Fix Version/s: 1.12.0
    • Component/s: None
    • Labels:

      Description

      Today if a user is not authenticated via REST API then there is no way to provide a user name for executing queries. It will by default be executed as "anonymous" user. This doesn't work when impersonation without authentication is enabled on Drill server side, since anonymous user doesn't exist the query will fail. We need a way to provide a user name when impersonation is enabled on Drill side and query is executed from REST API.

      There are two approaches to achieve that:
      1. Use form-based authentication
      On Web UI user will be prompted to enter only login, then session for that user will be created, user will be treated as admin. Form-based authentication will cache user information, so user won't need to set user name each time he / she wants to execute the query. Log in / out options will be also available. Example screenshot of login page is attached (login_page.JPG).
      From the programmatic perspective, user would need first to authenticate and use cookie to get query result.

      2. Use User-Name header in request
      On Web UI on Query page additional input field will appear. User would need to enter user name before issuing the query. Example screenshot of query page is attached (query_page_with_user_name.JPG). Under the hood with user name would be added to client request as request header. On server side this header would be used to create user session principal. From the programmatic perspective, user would need to add header when issuing the request.

      From the two above options second was chosen as it would ease REST API usage from the programmatic perspective, plus using form-based authentication may lead to false assumption that user is authenticated which is in reality is not true.

      Implementation details of the second approach:
      Note: the below implementation will take affect only if authentication is disabled and impersonation is enabled. By means of freemarker page won't include js lib and script if condition is not met.
      On the client side additional input field was added to the query page. When client is submitting the query, request would be changed using ajax to add User-Name header which would be taken from the new input field. On the server side, this header would be used to create session principal with provided user name and admin rights. If user name header was not provided (null or empty), the default anonymous principal will be used only in case when it is not POST request to /query or /query.json. If it is POST request to /query or /query.json User-Name header is required, so error will be thrown. Also adding User Name input parameter is required from Web UI. User won't be able to send request until field is filled in.

      Adding user name header approaches:
      Web UI
      enter user name in the User Name input field on Query page before submiiting the query (query_page_with_user_name.JPG), this step is required.
      sqlline

      ./drill-localhost -n user1

      curl

       curl -v -H "Content-Type: application/json" -H "User-Name: user1" -d '{"queryType":"SQL", "query": "select * from sys.version"}' http://localhost:8047/query.json 

      Java way

          String url = "http://localhost:8047/query.json";
          URLConnection connection = new URL(url).openConnection();
          connection.setDoOutput(true); // Triggers POST.
          connection.addRequestProperty("User-Name", "user1");
          connection.setRequestProperty("Content-Type", "application/json");
      
          String data = "{\"queryType\":\"SQL\", \"query\": \"select * from sys.version\"}";
          try (OutputStream output = connection.getOutputStream()) {
            output.write(data.getBytes(StandardCharsets.UTF_8.name()));
          }
      
          try (InputStream response = connection.getInputStream()) {
            String result = IOUtils.toString(response);
            System.out.println(result);
          }
      

      Note: Apache HttpClient can be used as well.

        Attachments

        1. query_page_with_user_name.JPG
          40 kB
          Arina Ielchiieva
        2. login_page.JPG
          19 kB
          Arina Ielchiieva

          Issue Links

            Activity

              People

              • Assignee:
                arina Arina Ielchiieva
                Reporter:
                arina Arina Ielchiieva
                Reviewer:
                Sorabh Hamirwasia
              • Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: