401 unauthorized : [no body] with root cause in JAVA Spring - java

I'm creating my first REST API using JAVA Spring and when I'm making a rest call to an external API, I get
401 Unauthorized: [no body]
I think my problem is here:
requestParams.add("Grant_type", "client_credentials");
I saw some questions related to this but none well able to solve my problem.
Spring REST template - 401 Unauthorized error
Spring Boot Callable - 401 Unauthorized: [no body]
JAVA code:
public String getAuth(String client_id, String app_secret) {
String auth = client_id + ":" + app_secret;
return Base64.getEncoder().encodeToString(auth.getBytes());
}
#GetMapping(value = "/token")
public Object generateAccessToken() {
String auth = this.getAuth(
"CLIENT_ID",
"APP_SECRET"
);
RestTemplate restTemplate = new RestTemplate();
String base = "https://external-api.com";
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + auth);
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("Grant_type", "client_credentials");
ResponseEntity<Object> response = restTemplate.postForEntity(
base + "/v1/oauth2/token",
requestParams,
Object.class,
headers
);
return response.getBody();
}

Here's the solution to my own question.
This is what I had to change;
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("grant_type", "client_credentials");
HttpEntity<?> request = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(
base +"/v1/oauth2/token",
request,
String.class
);
Here's the final solution:
public String generateAccessToken() {
String base = "example-api.com";
String auth = this.getAuth(
"client id",
"app_id"
);
// create an instance of RestTemplate
RestTemplate restTemplate = new RestTemplate();
// create headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Authorization", "Basic " + auth);
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("grant_type", "client_credentials");
HttpEntity<?> request = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(
base +"/v1/oauth2/token",
request,
String.class
);
// check response
if (response.getStatusCode() == HttpStatus.OK) {
System.out.println("Request Successful");
System.out.println(response.getBody());
} else {
System.out.println("Request Failed");
System.out.println(response.getStatusCode());
}
JSONObject object = new JSONObject(response.getBody());
return object.getString("access_token");
}

Related

Proper way to get Oath2 access token and call another service in Java Spring Boot

I want to get the oath2 access token and using this I want to call an another service.
Below code does the same it gets the access token and call an another API using that. Using the below code I am able to do what ever I want with the below code.
But I am new to Spring Security I just want to know if there is a better way to do this. Like rather than making a separate call to get the token and then call the service can i do it in a single call? Or Using any other class provided by Spring can I write this in a better way ?
public class TestAPIToken{
#RequestMapping(value = "/showEmployees", method = RequestMethod.GET)
public ModelAndView showEmployees(#RequestParam("code") String code) throws JsonProcessingException, IOException {
String accessToken = getAccessToken();
System.out.println("API Token ---------" + accessToken);
HttpEntity<String> response = getResponseByCallingWithToken(accessToken);
System.out.println("API Response ---------" + response.getBody());
return null;
}
private HttpEntity<String> getResponseByCallingWithToken(String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.add("Authorization", "Bearer " + accessToken);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("msisdn", msisdn)
.queryParam("email", email);
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
String.class);
reponse.getBody();
return response;
}
private String getAccessToken() {
ResponseEntity<String> response = null;
System.out.println("Authorization Code------" + code);
RestTemplate restTemplate = new RestTemplate();
// According OAuth documentation we need to send the client id and secret key in the header for authentication
String encodedCredentials = new String(Base64.encodeBase64(credentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.add("Authorization", "Basic " + encodedCredentials);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("scope","scope,value");
body.add("grant_type","scope,value");
HttpEntity<String> request = new HttpEntity<String>(body, headers);
String access_token_url = "http://localhost:8080/oauth2/token";
ResponseEntity<TokenModel> response = restTemplate.exchange(access_token_url, HttpMethod.POST, request, TokenModel.class);
String accessToken = response.getBody().access_token;
return accessToken;
}
}
class TokenModel{
String access_token;
String scope;
String token_type;
String expires_in;
}
I am new to Spring security. Please help even if this seems simple to you
NB: This question does not have an exact duplicate

Mockito Restemplate Verify not invoked

I a trying to mock restetmplate but don't why I am getting the below error. I am using doreturn to verify the invocation of the resttemplate.Is there by other way to mock the rest template and mock the HTTP request
class ToTest{
public ResponseEntity<String> getValue(){
if (StringUtils.isNotEmpty(token)) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
headers.setContentType(MediaType.APPLICATION_JSON);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(etsServiceResourceDetails.getAccessTokenUri())
.queryParam("test","tsetValue");
builder.queryParam("some","someValue");
HttpEntity<?> entity = new HttpEntity<>(headers);
try {
response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, entity, String.class);
}
catch (RestClientResponseException ex ) {
log.error(ex);
if ( ex.getRawStatusCode() == HttpStatus.NOT_FOUND.value()) {
return ResponseEntity.notFound().build();
}
}
}
}
}
Unit Test for the rest Temaplate
#Test
public void testExchange() {
String token="abbjabxkcbkscksckbckbkcbksckckkcb";
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("query", "star");
queryParams.add("test", "star2");
UriComponents uriComponents = UriComponentsBuilder.newInstance().scheme("http").host("localhost:8080/some/add").path("/").queryParams(queryParams).buildAndExpand();
RestTemplate r = new RestTemplate();
RestTemplate r1 = spy(r);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> entity = new HttpEntity<>(headers);
// ResponseEntity responserm=
//r1.exchange(uriComponents.toUriString(),HttpMethod.GET,entity,String.class); //I am getting error org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8080
doReturn(new ResponseEntity("", HttpStatus.OK)).when(r1).exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), any(Class.class));
verify(r1, times(1)).exchange(eq(uriComponents.toUriString()), any(), any(), eq(String.class));
assertEquals("check", "http://localhost:8080/some/add/?query=s1&test=s2", uriComponents.toUriString());
}
Errors
-> at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:581)
Actually, there were zero interactions with this mock.
Wanted but not invoked:

How to Spring Retryable with http status code

I'm currently using spring 2 with restTemplate and I would like to have a retry sending a post request only with a certain status codes or any of code 500.
How do I do this?
Here is my code
#Retryable(value = RestClientException.class, exclude = {UnknownHostException.class},
backoff=#Backoff(delayExpression = 10000,
multiplierExpression = 2,
maxDelayExpression = 50000))
public HttpStatus postRequest(final File file) throws RestClientException {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", new FileSystemResource(file));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("Token", mytoken);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> response = restTemplate.exchange(URI, HttpMethod.POST,requestEntity, String.class);
return response.getStatusCode();
}

Consuming HTTP POST method which is secured with Basic Auth in spring

I want to consume a post method which is secured using basicAuth. I am using springBoot, Spring RestTemplate to consume it.
I've tried like this:
#CrossOrigin(origins = "*", maxAge = 3600)
#RequestMapping(value = "/ValidateAnswers", method = RequestMethod.POST)
public ResponseEntity<String> ValidateAnswers(#RequestBody Object requestIbject,
HttpServletRequest request, HttpServletResponse response) {
final String uri = "foo:8080//validateAnswers";
// hiding full path here,
RestTemplate restTemplate = new RestTemplate();
String plainClientCredentials = "user:pass";
String base64ClientCredentials = new String(
Base64.encodeBase64(plainClientCredentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64ClientCredentials);
HttpEntity<String> entity = new HttpEntity<String>("parameters",
headers);
ResponseEntity<String> respEntity = restTemplate.postForObject(uri, requestIbject, String.class);
// .exchange(uri,
// HttpMethod.POST, entity, String.class);
System.err.println("=------------Response--------------");
System.err.println("----" + respEntity);
return respEntity;
}
How do I pass the headers with basicAuth and post request body ?
if you using spring > 4.3.1
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user", "password"));
From your code snippets I don't think you should use post method, try get first. And refer to my previous test:
public class Test {
private HttpHeaders getHeaders(){
String plainCredentials="admin:admin";
String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
return headers;
}
#Test
public void testLogin() {
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> request = new HttpEntity<String>(getHeaders());
ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/login", HttpMethod.GET,
request, String.class);
System.out.println(response.getBody());
}
}

Rest Api call gives error 400 using Spring Oauth2

I'm building a rest API using Spring security Oauth2 to secure it.
The following curl command runs succesfully and I get the token:
curl -X POST -vu clientapp:123456 http://localhost:8080/dms-application-0.0.1-SNAPSHOT/oauth/token -H "Accept: application/json" -d "password=spring&username=roy&grant_type=password&scope=read%20write&client_secret=123456&client_id=clientapp"
The following test to get the token also runs succesfully:
#Test
public void getAccessToken() throws Exception {
String authorization = "Basic " + new String(Base64Utils.encode("clientapp:123456".getBytes()));
String contentType = MediaType.APPLICATION_JSON + ";charset=UTF-8";
// #formatter:off
String content = mvc
.perform(
post("/oauth/token")
.header("Authorization", authorization)
.contentType(
MediaType.APPLICATION_FORM_URLENCODED)
.param("username", "roy")
.param("password", "spring")
.param("grant_type", "password")
.param("scope", "read write")
.param("client_id", "clientapp")
.param("client_secret", "123456"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.access_token", is(notNullValue())))
.andExpect(jsonPath("$.token_type", is(equalTo("bearer"))))
.andExpect(jsonPath("$.refresh_token", is(notNullValue())))
.andExpect(jsonPath("$.expires_in", is(greaterThan(4000))))
.andExpect(jsonPath("$.scope", is(equalTo("read write"))))
.andReturn().getResponse().getContentAsString();
// #formatter:on
String token= content.substring(17, 53);
}
However, when calling the rest end point externally from a webapp using Spring RestTemplate gives me a http error 400.
Below the code:
#RequestMapping(value = "/authentication", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity authenticate(#RequestBody CredentialsDto credentials) {
try {
String email = credentials.getEmail();
String password = credentials.getPassword();
String tokenUrl = "http://" + env.getProperty("server.host") + ":8080" + "/dms-application-0.0.1-SNAPSHOT" + "/oauth/token";
// create request body
JSONObject request = new JSONObject();
request.put("username", "roy");
request.put("password", "spring");
request.put("grant_type","password");
request.put("scope","read write");
request.put("client_secret","123456");
request.put("client_id","clientapp");
// set headers
HttpHeaders headers = new HttpHeaders();
String authorization = "Basic " + new String(Base64Utils.encode("clientapp:123456".getBytes()));
String contentType = MediaType.APPLICATION_FORM_URLENCODED.toString();
headers.set("Authorization",authorization);
headers.set("Accept","application/json");
headers.set("Content-Type",contentType);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restClient.exchange(tokenUrl, HttpMethod.POST, entity, String.class);
// restClient.postForEntity(tokenUrl,entity,String.class,)
if (loginResponse.getStatusCode() == HttpStatus.OK) {
//JSONObject userJson = new JSONObject(loginResponse.getBody());
String response = loginResponse.getBody();
return ResponseEntity.ok(response);
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
return null;
}
And the error I get:
"Missing grant type"
Any ideas of what can be wrong or any other ways to do it? Because I'm completely stuck on this.
Thank you
Try to do it like this:
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("username", "roy");
map.add("password", "spring");
map.add("grant_type", "password");
map.add("scope", "read write");
map.add("client_secret","123456");
map.add("client_id","clientapp");
HttpEntity request = new HttpEntity(map, headers);
One more thing, when you ask for a token make sure not to send a json request, but with this header:
headers.add("Content-Type", "application/x-www-form-urlencoded");

Categories