Java Exception: Unauthorized: 401 - java

I'm getting the error: Exception: org.springframework.web.client.HttpClientErrorException$Unauthorized: 401, when trying to connect to Jira through HttpHeader, and the credentials are configured in a configserver file, which would be this:
#Component
public class JiraHttpHeadersHelper {
#Value("${first.jira.auth.user}")
private String firstJiraAuthUser;
#Value("${first.jira.auth.psw}")
private String firstJiraAuthPsw;
public HttpHeaders jiraHeadersWithAuthentication() {
String plainCreds = firstJiraAuthUser + ":" + firstJiraAuthPsw;
System.out.println("Credenciales JiraServices: "+plainCreds);
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCreds.getBytes());
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic" + base64Creds);
headers.setContentType(MediaType.APPLICATION_JSON);
System.out.println("Authorization JiraServices: "+headers);
return headers;
}
}
And the method where I command to call the file above and where I get the error on the line ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET,this.requestEnt, String.class);, would be this:
public ResponseEntity<String> getPriorityJira() {
//Request entity created
this.requestEnt = new HttpEntity(this.jiraHttpHeadersHelper.jiraHeadersWithAuthentication());
String jql = "priority";
String url = jiraBaseURL + jql;
try {
ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET,this.requestEnt, String.class);
System.out.println("HttpStatus"+HttpStatus.OK);
if (result.getStatusCode() == HttpStatus.OK) {
return result;
} else {
logger.error("Jira Generic User maybe blocked, status from API: " +result.getStatusCode() + ". Body: "+ result.getBody());
return new ResponseEntity<>(result.getBody(), result.getStatusCode());
}
} catch(HttpClientErrorException e) {
logger.error("Error getting priorityJira. Exception: "+ e);
return new ResponseEntity<>(e.getStatusCode());
}
}
In fact, when I run the debug and check the credentials, it brings them up without a problem. I've already searched, tried most of the links on this page and I can't find the solution.
Any help would be appreciated in this case, thanks in advance.

When you define your authorization header you concat your key with « Basic » without adding a white space.
headers.add("Authorization", "Basic" + base64Creds);
Instead of :
headers.add("Authorization", "Basic " + base64Creds);
Maybe it’s just that.
Edit :
The answer was to add StandardCharsets.UTF-8 to the String constructor.

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

Changing a 404 response for REST API to a 200 empty response

I have a Spring Boot application written in Java that is a REST API. This service (Svc A) calls a REST API service (Svc B) with is also a Spring Boot Application written in Java. Svc B returns a 404 status code when no data was found. I need to change this response to a 200 status code and return an empty response object. I am not sure if or how to do this.
I can catch the error and determine if the 404 is this no data found error. However, I don't know how to change the response to a 200 empty response.
I am using a FeignClient to call the service. This is the error code that catches the 404:
#Component
public class FeignErrorDecoder implements ErrorDecoder {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public Exception decode(String methodKey, Response response) {
Reader reader = null;
String messageText = null;
switch (response.status()){
case 400:
logger.error("Status code " + response.status() + ", methodKey = " + methodKey);
case 404:
{
logger.error("Error took place when using Feign client to send HTTP Request. Status code " + response.status() + ", methodKey = " + methodKey);
try {
reader = response.body().asReader();
//Easy way to read the stream and get a String object
String result = CharStreams.toString(reader);
logger.error("RESPONSE BODY: " + result);
ObjectMapper mapper = new ObjectMapper();
//just in case you missed an attribute in the Pojo
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//init the Pojo
ExceptionMessage exceptionMessage = mapper.readValue(result,
ExceptionMessage.class);
messageText = exceptionMessage.getMessage();
logger.info("message: " + messageText);
} catch(IOException ex) {
logger.error(ex.getMessage());
}
finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return new ResponseStatusException(HttpStatus.valueOf(200), messageText);
}
default:
return new Exception(response.reason());
}
}
}
I can change the status code to a 200 and it returns a 200 but I need to the response to have an empty response object.
The above code will return this response body of an error response object:
{
"statusCd" : "200",
"message" : "The Location not found for given Location Number and Facility Type Code",
"detailDesc" : "The Location not found for given Location Number and Facility Type Code. Error Timestamp : 2020-01-31 18:19:13"
}
I need it to return a response body like this:
200 - Empty Response
{
"facilityNumber": "923",
"facilityTimeZone": null,
"facilityAbbr": null,
"scheduledOperations": []
}
In case 404 just try
return new ResponseStatusException(HttpStatus.valueOf(200));
For anyone that has to do something this crazy...here is my solution:
Removed the FeignErrorCode file.
Added an exception to ControllerAdvice class like this:
#ExceptionHandler(FeignException.class)
public ResponseEntity<?> handleFeignException(FeignException fe, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), HttpStatus.valueOf(fe.status()), fe.getMessage(), request.getDescription(false));
String response = fe.contentUTF8();
if(response != null) {
ScheduledOperationsViewResponse scheduledOperationsViewResponse = new ScheduledOperationsViewResponse();
if (response.contains("Scheduled") || response.contains("Location")) {
HttpHeaders headers = new HttpHeaders();
scheduledOperationsViewResponse.setFacilityNumber(request.getParameter("facilityNumber"));
return new ResponseEntity<ScheduledOperationsViewResponse>(scheduledOperationsViewResponse, headers, HttpStatus.OK);
}
}
return new ResponseEntity<>(errorDetails, errorDetails.getStatus());
}

Auth0 : how to retrieve app_metadata and user_metadata in token?

I try to authenticate a user with its username and password. I want to retrieve the JWT in response and find in it his permissions (stored in app_metadata).
But the id_token returned does not contain the user_metadata or app_metadata.
I tried with the Java driver and HTTP call.
Java :
AuthAPI auth = new AuthAPI("my-domain.auth0.com", "my_client_id", "my_secret_id");
AuthRequest request = auth.login(username, password)
.setScope("openid app_metadata user_metadata");
try {
TokenHolder holder = request.execute();
return holder;
} catch (Auth0Exception e) {
throw new AuthentException("Error authenticating " + username, e);
}
HTTP :
final String req = "{"
+ "\"username\":\"test#domain.com\","
+ "\"password\":\"test\","
+ "\"scope\":\"openid app_metadata user_metadata\","
+ "\"client_id\":\"my_client_id\","
+ "\"client_secret\":\"my_secret_id\","
+ "\"grant_type\":\"password\""
+ "}";
RestTemplate template = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(req, headers);
ResponseEntity<String> response = template.exchange("https://my-domain.auth0.com/oauth/token", HttpMethod.POST, entity, String.class);
The id_token returned contains only :
{
"email": "test#domain.com",
"email_verified": true,
"iss": "https://my-domain.auth0.com/",
"sub": "auth0|xxx",
"aud": "my_client_id",
"exp": 1497744462,
"iat": 1495116462
}
I tried to add a rule :
function (user, context, callback) {
var namespace = 'https://my-domain.auth0.com/';
if (context.idToken && user.user_metadata) {
context.idToken[namespace + 'user_metadata'] = user.user_metadata;
}
if (context.idToken && user.app_metadata) {
context.idToken[namespace + 'app_metadata'] = user.app_metadata;
}
callback(null, user, context);
}
And a hook :
module.exports = function(client, scope, audience, context, cb) {
var access_token = {};
access_token.scope = scope;
access_token.scope.push('user_profile');
cb(null, access_token);
};
But nothing adds the metadata to the id_token.
How could I retrieve these metadata ?
Thanks.
I found that the /oauth/ro endpoint is working : https://auth0.com/docs/api/authentication#resource-owner
final String req = "{"
+ "\"username\":\"ambre#domain.com\","
+ "\"password\":\"test\","
+ "\"scope\":\"" + settings.getScope() + "\","
+ "\"connection\":\"Username-Password-Authentication\","
+ "\"client_id\":\"" + settings.getClientId() + "\","
+ "\"grant_type\":\"password\""
+ "}";
RestTemplate template = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(req, headers);
ResponseEntity<String> response = template.exchange("https://my-domain.auth0.com/oauth/ro", HttpMethod.POST, entity, String.class);
But I can't find the equivalent in java driver 1.0.0

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");

Get STRING response from restTemplate.put

I'm having a problem using Spring restTemplate.
For now i'm sending a PUT request for a restful service and that restful service send me back important informations in response.
The question is that restTemplate.put are a void method and not a string so i can't see that response.
Following some answers i've change my method and now i'm using restTemplate.exchange, here are my method:
public String confirmAppointment(String clientMail, String appId)
{
String myJsonString = doLogin();
Response r = new Gson().fromJson(myJsonString, Response.class);
// MultiValueMap<String, String> map;
// map = new LinkedMultiValueMap<String, String>();
// JSONObject json;
// json = new JSONObject();
// json.put("status","1");
// map.add("data",json.toString());
String url = getApiUrl() + "company/" + getCompanyId() + "/appointment/" + appId + "?session_token=" + r.data.session_token;
String jsonp = "{\"data\":[{\"status\":\"1\"}]}";
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
headers.add("Accept", "*/*");
HttpEntity<String> requestEntity = new HttpEntity<String>(jsonp, headers);
ResponseEntity<String> responseEntity =
rest.exchange(url, HttpMethod.PUT, requestEntity, String.class);
return responseEntity.getBody().toString();
}
Using the method above, i receive a 400 Bad Request
I know my parameters, url and so, are just fine, cause i can do a restTemplate.put request like this:
try {
restTemplate.put(getApiUrl() + "company/" + getCompanyId() + "/appointment/" + appId + "?session_token=" + r.data.session_token, map);
} catch(RestClientException j)
{
return j.toString();
}
The problem (like i said before) is that the try/catch above does not return any response but it gives me a 200 response.
So now i ask, what can be wrong?
Here's how you can check the response to a PUT. You have to use template.exchange(...) to have full control / inspection of the request/response.
String url = "http://localhost:9000/identities/{id}";
Long id = 2l;
String requestBody = "{\"status\":\"testStatus2\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestBody, headers);
ResponseEntity<String> response = template.exchange(url, HttpMethod.PUT, entity, String.class, id);
// check the response, e.g. Location header, Status, and body
response.getHeaders().getLocation();
response.getStatusCode();
String responseBody = response.getBody();
You can use the Header to send something in brief to your clients. Or else you can use the following approach as well.
restTemplate.exchange(url, HttpMethod.PUT, requestEntity, responseType, ...)
You will be able to get a Response Entity returned through that.
Had the same issue. And almost went nuts over it. Checked it in wireshark: The problem seems to be the escape characters from the request body:
String jsonp = "{\"data\":[{\"status\":\"1\"}]}";
The escape character (backslash) is not resolved. The String is sent with the backslashes, which is obviously not a valid json and therefore no valid request(-body).
I bypassed this by feeding everything in with an Object, that is mapping all the properties.

Categories