For a deeper look into our World Check One API, look into:

Overview |  Quickstart |  Documentation |  Downloads

question

Upvotes
Accepted
3 1 1 2

Springboot Java AuthorisationHeader error 401 for Linux

Hi, My name is Jorge and I'm trying to connect with World check API. The issue is: we are always getting a 401 authorisation error, but just for linux.

We have our service running in windows and we dont have any issue running it in our local environment (Windows).

When we deploy it to our DEV environment which is in Linux we are getting a 401 error, the same keys, the same code, without any change.

We already tried some different logics. Seems to be a problem with break line - "\n" in the Data to Sign string. We tried "\n" or System.lineSeparator().

//we need to keep System.lineSeparator for linux, we cannot put "\n" directly in the string.
        String breakLine = System.lineSeparator();
        switch (method){
            case GET:
                requestDataToSign = "(request-target): get " + gatewayUrl + path + breakLine +
                        "host: " + gatewayHost + breakLine +
                        "date: " + date;
                break;
            case POST:
                requestDataToSign = "(request-target): post " + gatewayUrl + path + breakLine +
                        "host: " + gatewayHost + breakLine +
                        "date: " + date;
                if(StringUtils.hasLength(bodyString)){
                    requestDataToSign +=
                            breakLine + "content-type: " + MediaType.APPLICATION_JSON_VALUE + breakLine +
                                    "content-length: " + contentLength + breakLine +
                                    bodyString;
                    requestDataHeaders=Constants.REQUEST_HEADERS_WITH_BODY;
                }

        }
        log.debug("Request sign {}", requestDataToSign);
        return signRequestData(requestDataToSign,requestDataHeaders,apiKey,apiSecret);


private String signRequestData(String dataToSign, String requestHeaders, String apiKey, String apiSecret) {
        String hmac = generateAuthHeader(dataToSign, apiSecret);
        return "Signature keyId=\"" + apiKey + "\",algorithm=\"hmac-sha256\",headers=\"(request-target) " + requestHeaders + "\",signature=\"" + hmac + "\"";
    }


private String generateAuthHeader(String dataToSign, String apiSecret)
    {
        String hash = "";
        try {

            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            log.info("Charset.defaultCharset().toString() {}" , Charset.defaultCharset().toString());
            hash = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(dataToSign.getBytes(StandardCharsets.UTF_8)));
        }
        catch (Exception e){
            log.error(e.getMessage(), (Object[]) e.getStackTrace());
        }
        return(hash);
    }


How do you suggest to create this Authorization String? to work in windows and linux.

Would be great if it's possible to have a teams call to be easier to show and communicate this issue. We are struggling with this and we have a data for the deploy.


Thank you

Jorge Medina


javaerrorerror-401linux
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hello @jorgemedina

Thank you for your participation in the forum. Is the reply below satisfactory in resolving your query?


If so please can you click the 'Accept' text next to the appropriate reply? This will guide all community members who have a similar question.

Thanks,


AHS

Upvotes
Accepted
1.4k 5 2 2

Hi @jorgemedina

Thanks for sharing the requested details.

When you get the 401 which means that the request has failed an authorization check. This can happen for a variety of reasons, such as an invalid or expired API key, an invalid HMAC signature or a request timing issue/problem with the Date header value.

Therefore, I have validated your Linux request header and response header and found out that the clock is not synchronized as you can see that there is ~2 minutes difference between the request header and the response header (it shouldn't be more than 30 seconds), hence you are getting the 401 error. You should ensure a correctly synchronized clock is used to generate request timestamps.
1640171881986.png

Thanks
Vivek Kumar Singh


1640171881986.png (50.2 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
1.4k 5 2 2

Hi @jorgemedina

Thanks for reaching out to us!

We are working with our internal team on above reported issue. We will get back to with our findings Shortly.

In the meantime, can you please help us with the "Complete request header and Response header"

Thanks
Vivek Kumar Singh

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
3 1 1 2

Hi Kumar,

Sure,

Windows:

 ---> GET https://api-worldcheck.refinitiv.com/v2/groups HTTP/1.1
Accept: application/json
Authorization: Signature keyId="af0806ab-982c-4b42-bd2a-edd82f17b5d1",algorithm="hmac-sha256",headers="(request-target) host date",signature="XueN09p/CsTFrlDy3cOHFYj7YbuknikE0Vd8amZCdII="
Cache-Control: no-cache
Content-Type: application/json
Date: Wed, 22 Dec 2021 10:45:12 GMT
END HTTP (0-byte body)

<--- HTTP/1.1 200 (578ms)
cache-control: no-cache, no-store, max-age=0, must-revalidate
connection: keep-alive
content-type: application/json;charset=UTF-8
date: Wed, 22 Dec 2021 10:45:17 GMT
expires: 0
pragma: no-cache
strict-transport-security: max-age=15552000, includeSubdomains
transfer-encoding: chunked
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block

[{"id":"XXXXXXXXXXXXXXX","name":"KPMG & Associados - Sociedade de Revisores Oficiais de Contas S.A.- API - (Pilot)","parentId":null,"hasChildren":false,"status":"ACTIVE","children":[]}]

Linux:

---> GET https://api-worldcheck.refinitiv.com/v2/groups HTTP/1.1
Accept: application/json
Authorization: Signature keyId="af0806ab-982c-4b42-bd2a-edd82f17b5d1",algorithm="hmac-sha256",headers="(request-target) host date",signature="UivhRONBMcIZ4EFzxLZe9JfEHc0Urp7rmTtgTpzH1yA="
Cache-Control: no-cache
Content-Type: application/json
Date: Wed, 22 Dec 2021 11:43:44 GMT
---> END HTTP (0-byte body)

<--- HTTP/1.1 401 (246ms)

authorization: WWW-Authenticate: Signature realm="World-Check One API",algorithm="hmac-sha256",headers="(request-target) host date content-type content-length"
connection: keep-alive
date: Wed, 22 Dec 2021 10:45:16 GMT
strict-transport-security: max-age=15552000, includeSubdomains
transfer-encoding: chunked

<--- END HTTP (0-byte body)

The request was made to both machines, as you can see by the Date. (Our linux machine (Dev environment) is 1 hour ahead against our local environment (Windows)).


The following code is the one who trigger the first block of code in my question, where we have "String breakLine = System.lineSeparator(); ":

public void apply(RequestTemplate requestTemplate) {
        //Get the current date
        String date = apiAuthorisationManager.getDateHeader();
        String authorisationSignatureString = "";
        //Check if exist body or not in the request
        String bodyString = null;
        if(requestTemplate.body() != null && requestTemplate.body().length > 0){
            bodyString = new String(requestTemplate.body());
        }
        Collection<String> contentLengthValues = requestTemplate.headers().get(HttpHeaders.CONTENT_LENGTH);
        authorisationSignatureString = apiAuthorisationManager.generateAuthorisationHeader(RequestMethod.valueOf(requestTemplate.method()),
                requestTemplate.path(),
                date,
                bodyString,
                contentLengthValues != null ? contentLengthValues.stream().findFirst().orElse(null):"");

        requestTemplate.header(HttpHeaders.CACHE_CONTROL, "no-cache");
        requestTemplate.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        requestTemplate.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
        requestTemplate.header(HttpHeaders.AUTHORIZATION, authorisationSignatureString);
        requestTemplate.header(HttpHeaders.DATE, date);

    }

The main difference now that we have is:

"String breakLine = "\n";" 

instead of

String breakLine = System.lineSeparator();

Because with "String breakLine = System.lineSeparator(); " wont work using our windows environment and either using our linux environment.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
3 1 1 2

Hi Kumar,


Thank you for your time.

We thought that the Data which we have in the request header was validated against the date inside the signature string.

Yes you are right and we will work according your suggestion.

We already did some tests to confirm it, and it works.


Once again thank you for your time.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hi @jorgemedina


Glad to know that our suggestion resolved your issue.

Thanks
Vivek Kumar Singh

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.