0

I am the sole developer for the tiny company I work for. I inherited a lot of legacy code. The code relevant to this issue is in Java 8 with SpringBoot.

An entity we get important data from recently updated how it serves data to use a REST API. The REST API can only be accessed over HTTPS and requires a valid username and password. The entity provided example code in several coding languages on how to use their new API. They recommend curl as the default method of downloading their data, but offer examples in Java 8. I can successfully download a file using my credentials with the curl command in *NIX. I cannot get the file to download using Java. I am reasonably sure the code is failing at the authentication level. I found this StackOverflow post suggesting it might be a problem with the TLS version, but I haven't been able to get that to work.

My boss has forbidden me from posting the entity's documentation for "security reasons" even though the documentation is publicly available. Similarly, I have to mask my code a bit. I will do everything I can to make the changes minimal.

Here is the two-part curl command that works:

First get the Token:

 curl --request POST --header "X-OpenAM-Username: username" --header "X-OpenAM-password: password" --header "Content-Type:application/json" --data "{}" https://sso.entityname.com/access/authenticate

I get a JSON back that includes a Token. Following the entity's example code, I pass the token in the next curl command, then I successfully get the file:

curl --request GET --header "Cookie: entityauth=longgibberishstringofencryptioncharaters" --header Content-Type:text/csv "https://entityname.com/rest/secure/download/reports?shortName=awesomereport&version=L&format=C&start=01/01/2018&stop=01/15/2018"

Now this is my Java code. This is copied almost directly from the Entity's provided documention. The code compiles and runs without issue, but every single time it just creates and empty file named, "testOuput.txt".

   public static void downloadReport() throws IOException {
        String webUrl = "https://entityname.com/rest/secure/download/reports?shortName=awesomereport&version=L&format=C&start=01/01/2018&stop=01/15/2018";
        URL url = new URL(webUrl);
        String username = "username";
        String password = "password";
        String authString = username + ":" + password;
        String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(authString.getBytes());
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setRequestProperty("Authorization", basicAuth);
        InputStream inputStream = urlConnection.getInputStream();
        try {
            OutputStream out = new FileOutputStream("testOutput.txt");
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

I have also tried simply wrapping Java around a shell curl command using the Process class, but to no avail. Below is my attempt to do that. Once again, it compiles and runs successfully but creates an empty file named "testOuput.txt" every time.

    public static void downloadReportWithCurl() throws IOException {
        String authentication = "curl --request POST --header X-OpenAM-Username: username --header X-OpenAM-password: password --header Content-Type:application/json --data {} https://sso.entityname.com/access/authenticate";
        ProcessBuilder processBuilder = new ProcessBuilder(authentication.split(" "));
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jsonMap = objectMapper.readValue(inputStream, Map.class);
        String authToken = jsonMap.get("authId").toString().replace(".", ".*") + ".*";
        String authHeader = "Cookie: entityauth=" + authToken;
        System.out.println(authHeader);
        String downloadCommand = "curl --request GET --header "Cookie: entityauth=longgibberishstringofencryptioncharaters" --header Content-Type:text/csv "https://entityname.com/rest/secure/download/reports?shortName=awesomereport&version=L&format=C&start=01/01/2018&stop=01/15/2018"
        System.out.println(downloadCommand);
        ProcessBuilder processBuilder2 = new ProcessBuilder(downloadCommand.split(" "));
        Process process2 = processBuilder2.start();
        InputStream dataStream = process2.getInputStream();
        try {
            OutputStream out = new FileOutputStream("testOutput.txt");
            byte[] buf = new byte[1024];
            int len;
            while ((len = dataStream.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.close();
            dataStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

If anyone can help me resolve this issue, I'd be very grateful.

OnlyDean
  • 1,025
  • 1
  • 13
  • 25
  • You don't actually say what IS happening. Did you try `urlConnection.setDoOutput(true)` Making it [like this](http://stackoverflow.com/questions/2026260/ddg#2026299) – g00se Jul 29 '21 at 15:28
  • 1
    is there an Exception? you have a fairly detailed and good question, but need to explain what is actually broken – Eugene Jul 29 '21 at 15:30
  • Oh, sorry! Every time I run the Java code regardless of method, I it creates an empty file named "testOutput.txt." I will update my post with that and try the `setDoOutput(true)` and see what happens. – OnlyDean Jul 29 '21 at 15:30
  • Yes, but you probably need to do more than that. See the example i linked to – g00se Jul 29 '21 at 15:33
  • @g00se Adding the `urlConnection.setDoOutput(true)` line did not change the results. I still download an empty file. – OnlyDean Jul 29 '21 at 15:36
  • ^^See above - you probably need to do more. Also it must be said that, for anything other than really trivial ops, you should probably be using a proper HTTP api – g00se Jul 29 '21 at 15:48
  • @g00se -- I'm a bit inexperienced in this area. Can you give me an example of what a proper HTTP api might be? – OnlyDean Jul 29 '21 at 15:50
  • There's actually [an API in the JDK](https://openjdk.java.net/groups/net/httpclient/intro.html) now, though I haven't used it myself yet – g00se Jul 29 '21 at 15:53
  • @g00se Unfortunately the OP is using Java 8 and that API was added (standardized) in Java 11. Though there are obviously third-party HTTP libraries (e.g. from Apache). – Slaw Jul 29 '21 at 16:18
  • @OnlyDean If you're using SpringBoot, why not leverage Spring to make the HTTP call and download the file? – Slaw Jul 29 '21 at 16:19
  • @Slaw I do not know how to use SpringBoot to make an HTTP call, but I'll look into it. I'm basically a Jr Developer who accidentally found himself as the sole dev after my boss left. It's been rough, there is so much I don't know. – OnlyDean Jul 29 '21 at 16:28
  • 1
    I'm not familiar with Spring other than a broad understanding that a major feature is working with HTTP. Otherwise I'd provide more help. – Slaw Jul 29 '21 at 16:45

0 Answers0