Shopify API connection via Spring framework - spring

Has anyone performed a sucessfull Shopify authentication (and used their APIs) via Spring ?
I have been trying by using the RestTemplate , but can't login :
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("https://apikey:password#shopname.myshopify.com/admin/shop.json",String.class);
logger.info(result);
Unfortunately, I keep getting this :
org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
Whereas it works fine with the browser!
Do i need to locally import the shopify certificate ? if yes, it has been already done via the keytool.
Is it possible to authenticate via RestTemplate as I am doing, or should I need to go with Auth0 ?
Feel free to post a working snippet if any of you suceeded :)
Thanks a lot!

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("X-Shopify-Access-Token", "xxxxx");
//headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String result = restTemplate.exchange("https://apikey:password#shopname.myshopify.com/admin/shop.json", HttpMethod.GET, entity, String.class).getBody();

Related

Kerberos client - kerberoRestTemplate not working

Im trying to consume an api which is authenticating with Kerberos. I have referred the below spring documentation related to KerberosRestTemplate.reference link, im passing the correct keytab file and the userPrincipal values as mentioned in the reference doc. But still im receiving 401 from the server.
But when I execute the kinit command in the terminal it receives a ticket from KDC and with that, im able to execute the curl command and get a working response.
KerberosRestTemplate kerberosRestTemplate = new KerberosRestTemplate("svc_dfsd.keytab", "svc_dfsd#sswe.AD");
String url="https://wexample.com:20550/aggr_subscriber_summary_hbase/03434809824";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_XML));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = kerberosRestTemplate.exchange(url, HttpMethod.GET, entity, String.class);
Can you suggest any other better approach to do this or fix this. All your comments are highly appreciated!!!
Troubleshooting Kerberos might be tricky since the errors are often misleading and Java implementation does a lot if implicit actions (canonicalization of URLs, etc.).
I suggest trying Kerb4J library which allows you to generate the kerberos token explicitly:
SpnegoClient spnegoClient = SpnegoClient.loginWithKeyTab("svc_dfsd#sswe.AD", "svc_dfsd.keytab");
SpnegoContext context = spnegoClient.createContext("https://wexample.com"); // Will result in HTTP/wexample.com SPN
RestTemplate restTemplate = new RestTemplate();
String url="https://wexample.com:20550/aggr_subscriber_summary_hbase/03434809824";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_XML));
headers.add("Authorization", context.createTokenAsAuthroizationHeader());
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate .exchange(url, HttpMethod.GET, entity, String.class);
If default SPN resolution works for you, you can also use SpnegoRestTemplate from this Kerb4J:
SpnegoClient spnegoClient = SpnegoClient.loginWithKeyTab("svc_dfsd#sswe.AD", "svc_dfsd.keytab");
SpnegoRestTemplate spnegoRestTemplate = new SpnegoRestTemplate(spnegoClient);
String url="https://wexample.com:20550/aggr_subscriber_summary_hbase/03434809824";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_XML));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = spnegoRestTemplate.exchange(url, HttpMethod.GET, entity, String.class);
Disclaimer: I'm the author of Kerb4J

How to authorize against an OpenId Connect secured REST-API programmatically?

I have implement a REST-API based on Spring Boot secured by Spring Security 5.2 OpenID Connect resource server. The authorization server is an IdentityServer4. So far so good, the authentication using Bearer Token (the token is determined via a dummy web page) works well.
The challenge now is to call the REST API from a client that does not require user interaction (web page).
I would like to provide the API users with an unsecured endpoint (/authorization) which can be used to receive the Bearer Token for any further secured service. Username and password should be passed as request parameters.
I have search the web and studied the docs from Spring but I did not have found something which addresses my use case.
I implemented a relatively simple solution
#GetMapping
public ResponseEntity<GetTokenResponse> getToken(#RequestBody GetTokenRequest getTokenRequest) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("client_id", clientId);
formData.add("client_secret", clientSecret);
formData.add("grant_type", "password");
formData.add("scope", scopes);
formData.add("username", getTokenRequest.getUsername());
formData.add("password", getTokenRequest.getPassword());
RestTemplate restTemplate = new RestTemplate();
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formData, headers);
ResponseEntity<GetTokenResponse> response = restTemplate.postForEntity( tokenEndPoint, request , GetTokenResponse.class );
String accessToken = response.getBody().getAccessToken();
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
Jwt jwt = decoder.decode(accessToken);
logger.debug("Headers:\n{}", jwt.getHeaders());
logger.debug("Claims:\n{}", jwt.getClaims());
logger.info("User {}, {} '{}' authorised.", jwt.getClaimAsString("given_name"), jwt.getClaimAsString("family_name"), jwt.getClaimAsString("sub"));
return response;
}
The response contains the bearer token and can therefore be used for the API calls.

RestTemplate Exchange return Url Rejected

I'm facing a weird issue with an Api Call inside my spring boot application. When I use restTemplate to call an API :
ResponseEntity<String> response;
HttpHeaders headers = new HttpHeaders();
headers.set("X-Api-Key", "blablabla");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity entity = new HttpEntity(headers);
try {
response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
} catch (HttpClientErrorException e) {
throw new HttpClientErrorException(e.getStatusCode());
}
I can't have any response of the called API. It always returns a 200 Http Status but the following body :
<200 OK,<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.<br><br>Your support ID is: 6140245264157490471</body></html>,{Connection=[close], Cache-Control=[no-cache], Content-Type=[text/html; charset=utf-8], Pragma=[no-cache], Content-Length=[188]}>
I tried to call the API with the uri and headers used in my app in Postman and it works :/
I've already search for a similar issue in SOF and Google but can't find any response.
I hope someone will help me :D
Thx
I found the solution of the issue. It seems to be a bug of the company's firewall which catch this call as a threat ;)

301 ResponseCode in RestTemplate Client

I am trying to consume a service using RestTemplate in Spring. I tried around and each time getting 301 as response code. However, I am good to get a json response from the same uri while using POSTMAN.
Here is the code to get the statelist:
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
String baseUri = "http://www.whizapi.com/api/v2/util/ui/in/indian-states-list";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUri)
.queryParam("project-app-key","my-key");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> stats = restTemplate.exchange(builder.build().toUri(),
HttpMethod.GET,entity ,String.class);
Please suggest if I am missing anything.
HTTP 301 is a permanent redirect. You are accessing an outmoded url.
Having checked this url http://www.whizapi.com/api/v2/util/ui/in/indian-states-list redirected to https://www.whizapi.com/api/v2/util/ui/in/indian-states-list.ashx.
The same can be seen in Location response header as shown in the below image.
So, you should directly request https://www.whizapi.com/api/v2/util/ui/in/indian-states-list.ashx from your restTemplate object.
More details could be found here
Hope this helps!

Spring RestTemplate receives "401 Unauthorized"

I am using the following to retrieve JSON via RestTemplate in Spring 4:
protected DocInfoResponse retrieveData(String urlWithAuth) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + auth.getSig());
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<DocInfoResponse> response = restTemplate.exchange(urlWithAuth, HttpMethod.GET, request, DocInfoResponse.class);
return response.getBody();
}
I used the same code (with different response class) to successfully get a JSON doc from the same site (with different parameters to get a different doc).
When I execute the above code I receive the following stack trace (in part):
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at
org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
Can anyone point me to why this might be receiving the exception?
I found that my issue originally posted above was due to double encryption happening on the auth params. I resolved it by using UriComponentsBuilder and explicitly calling encode() on the the exchange().
SyncResponse retrieveData(UriComponentsBuilder builder) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<SyncResponse> response = restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET, request, SyncResponse.class);
return response.getBody();
}
My UriComponentsBuilder was built using:
UriComponentsBuilder buildUrl(String urlString) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(urlString);
return auth.appendAuth(builder);
}
(The auth.appendAuth() adds additional .queryParams() needed by the target service in urlString.)
The call to execute this was retrieveData(buildUrl(urlString));.
After investigating on my own problem, I realized that FireFox RESTClient was successful because I was connected to the target URL. The Basic Auth I thought I was using, was not so basic after all.
Eventually, I read the doc of the app i was trying to connect to and realized they propose a connection token mechanism. Now it works.
After reading your code, I say it looks quite OK, although I'm not sure what is your object auth on which you call getSig.
First things first: try to access your service from any client, like a web browser, a PostMan or RESTClient. Make sure you successfully retrieve your infos WITHOUT being connected to your app!!!
Depending on the result, I say you should, either try to encrypt manually your Authorization token (you'll easilly find posts on this site to show you how to) or try another connection mechanism.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
HttpHeaders createHeaders(String username, String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
set( "Authorization", authHeader );
}};
}
Then, sending a request becomes just as simple:
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange
(uri, HttpMethod.POST, new HttpEntity<T>(createHeaders(username, password)), clazz);
https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring#manual_auth

Resources