Spring Boot Inject Rest Template to Login Filter - spring

in default, my Login Filter output like this :
"role": "ROLE_ABC",
"succeed": "Success!",
"id": 123,
"username": "111222333",
"token": "xxxxx"
now i want to inject the output of rest tempalte, the output of rest template like this one :
{
"ResponseHeader": {
"ErrorCode": "0",
"ErrorDescription": "Success",
"TrxId": "123"
},
"UserInfo": {
"UserId": "111222333",
"FullName": ""
}
}
now i want to inject the output of rest template to my default login filter.
this is my code, im confuse how i can send the Request Body of rest template inside Login Filter
#Autowired
RestTemplate restTemplate;
#Override
protected void successfulAuthentication(final HttpServletRequest req, final HttpServletResponse res, final FilterChain chain,
final Authentication auth) throws IOException, ServletException {
logger.info("successfulAuthentication");
logger.info(auth);
Set<String> roles = AuthorityUtils.authorityListToSet(auth.getAuthorities());
String hasil=roles.toString().replace("[","").replace("]", "");
AuthenticationService.addToken(res, auth.getName());
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic uYycjhow9iJOFOJj=");
HttpEntity<vwCredentials> entity = new HttpEntity<vwCredentials>(product,headers);
->variable "product" is request body,
i confuse where should i put this code "#RequestBody vwCredentials product"
ResponseEntity<vwJWTLDAP> respon = restTemplate.exchange(
"http://123/LDAP/", HttpMethod.POST, entity, vwJWTLDAP.class);
HashMap<String, Object> map = new HashMap<>();
String email = auth.getName();
User user = repository.findByEmail(email);
map.put("id", user.getId());
map.put("username", auth.getName());
map.put("role", hasil);
//map.put("LDAP", respon); -> I WANT TO CALL LIKE THIS WAY
map.put("token", AuthenticationService.addToken(auth.getName()));
map.put("succeed", "Success !");
String authString = new Gson().toJson(map);
PrintWriter out = res.getWriter();
res.setContentType("application/json");
res.setCharacterEncoding("UTF-8");
out.print(authString);
out.flush();
}
}
how can i call like this way. //map.put("LDAP", respon); -> I WANT TO CALL LIKE THIS WAY

lass.
You would go about this using the getBody() method. This method is inherited from the class HttpEntity.
That being said, a way to get it would be map.put("LDAP", respon.getBody());

Related

Spring Webclient multipart/form-data request

I am new to Java (Spring Boot), and i am trying to send a multipart/form-data POST request to s3 to upload a file.
I managed to do this using spring's RestTemplate like this :
public String uploadFile(byte[] file, Map<String, Object> fields, String url) throws URISyntaxException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> formData= new LinkedMultiValueMap<String, Object>();
for (Map.Entry<String, Object> entry : fields.entrySet()) {
formData.add(entry.getKey(), entry.getValue());
}
formData.add("file", file);
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(formData, headers);
String response = restTemplate.postForObject(new URI(url), request, String.class);
return response;
}
Then i tried to do the same using webclient, but i can not and AWS respond with The body of your POST request is not well-formed multipart/form-data.
Here is the code using webclient :
public String uploadFileWebc(byte[] file, Map<String, Object> fields, String url) {
MultipartBodyBuilder builder = new MultipartBodyBuilder();
for (Map.Entry<String, Object> entry : fields.entrySet()) {
builder.part(entry.getKey(), entry.getValue(), MediaType.TEXT_PLAIN);
}
builder.part("file", file).filename("file");
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
Void result = webClient.filter(errorHandlingFilter()).build().post().uri(url)
.contentType(MediaType.MULTIPART_FORM_DATA)
.contentLength(file.length)
.bodyValue(parts)
.retrieve()
.bodyToMono(Void.class)
.block();
return "Done Uploading.";
}
Can anybody please point out what am i missing ?
It turns out that webclient does not add the content-length header due to its streaming nature, and S3 API needs this header to be sent.
I ended up using restTemplate for uploading files to S3.

HttpClientErrorException$BadRequest: 400 : [no body] when calling restTemplate.postForObject

I am calling a POST service getOrder3 written in SpringBoot which is working fine (tested in Postman), but getting error when called via restTemplate.postForObject from another service. I tried 2 versions of the client service getOrderClient and getOrderClient2, but both are giving same error :
HttpClientErrorException$BadRequest: 400 : [no body]
Please find the details below. Any help is appreciated.
getOrder3
#PostMapping(value="/getOrder3/{month}",produces="application/json")
public ResponseEntity<OrderResponse> getOrder3(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam(required=false) String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) {
OrderResponse orderResponse = new OrderResponse();
log.info("In getOrder3...parmRequestSource = " + parmRequestSource + " parmAudienceType = " + parmAudienceType);
try {
//validate JSON schema
//orderService.validateMessageAgainstJSONSchema(orderRequestForm);
//process order
orderResponse = orderService.processOrder(orderRequestForm);
orderResponse.setParmRequestSource(parmRequestSource);
orderResponse.setParmAudienceType(parmAudienceType);
orderResponse.setMonth(month);
}catch (Exception e) {
throw new OrderException("101", e.getMessage(), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(orderResponse,HttpStatus.OK);
}
The service is working fine , tested in postman
Now when I try to call via another microservice via restTemplate.postForObject, I get the error. Tried 2 versions of the client as below, getOrderClient and getOrderClient2
getOrderClient
#PostMapping(value="/getOrderClient/{month}",produces="application/json")
public OrderResponse getOrderClient(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) throws URISyntaxException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://localhost:51001/orders/v1/getOrder/"+month+"?parmRequestSource="+parmRequestSource+"&parmAudienceType="+parmAudienceType);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String requestJson = new ObjectMapper().writeValueAsString(orderRequestForm);
HttpEntity<String> httpEntity = new HttpEntity<String>(requestJson,headers);
String response = restTemplate.postForObject(uri, httpEntity, String.class);
return new ObjectMapper().readValue(response, OrderResponse.class);
}
getOrderClient2
#PostMapping(value="/getOrderClient2/{month}",produces="application/json")
public OrderResponse getOrderClient2(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) throws URISyntaxException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://localhost:51001/orders/v1/getOrder/"+month+"?parmRequestSource="+parmRequestSource+"&parmAudienceType="+parmAudienceType);
return restTemplate.postForObject(uri, orderRequestForm, OrderResponse.class);
}
Both are giving same error :
HttpClientErrorException$BadRequest: 400 : [no body]
Please suggest.
To improve the visibility of the solution, #astar fixed the issue by annotating the model object's properties with #JsonProperty.

How can I pass parameter as post to endpoint using RestTemplate in springboot?

I am using RestTemplate in my project to make a post request to an endpoint. Basically I have lambda function written in nestjs. I am injecting lambda service in my java project. If vehicleName if condition passes, I would like to POST that vehicleName to the url. Is there any suggestions on how I can achieve this? I would be testing my application using this command
curl -X POST "https://gdxdispatcher.dev.awstrp.net/dispatcher/service/api/message" -H "accept: */*" -H "Content-Type: application/json" -d "{\"vehicleType\":\"US Mutual Fund,VIP\",\"source\":\"PCS_DATACACHE_TOPIC\"}"
Here is my code
private void callLambdaService(String vehicleTypesParamValue)
{
final String url = "http://localhost:3000/dispatcher/service/api/message";
final String zMETHOD = "callLambdaService - ";
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("url", HttpMethod.POST, vehicleName, String.class);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String result = restTemplate.getForObject(url, String.class);
VehicleType vehicleName=null;
String[] vehicleTypes = vehicleTypesParamValue.split(",");
Set<VehicleType> results = new HashSet<>();
try
{
for (String vehicleTypeParam : vehicleTypes)
{
vehicleName =
vehicleTypeFactory.getVehicleTypeByIspName(
vehicleTypeParam);
if (vehicleName == null)
{
LOGGER.warn("No codes for products or vehicle types were supplied");
}
else if (vehicleName.equals("US Mutual Fund"))
{
LOGGER.info(zMETHOD + "Vehicles provided: "
+ vehicleName.getIspName());
}
else
{
LOGGER.warn(
String.format("Unknown vehicle type provided: [%s]",
vehicleName.getIspName()));
}
}
}catch (Exception e) {
LOG.error("Unable to get vehicletype data", e);
}
}
Well, following the instructions:
Create headers which will be a data structure representing HTTP request.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Build a JSONObject from org.json package that is a modifiable set of name/value mappings and put names and values.
JSONObject requestBody = new JSONObject();
requestBody.put("vehicleType", "US Mutual Fund,VIP");
requestBody.put("source", "PCS_DATACACHE_TOPIC");
Create our HttpEntity that represents an HTTP request or response, in this case request consisting of headers and body.
HttpEntity<String> request = new HttpEntity<>(requestBody.toString(), headers);
Create a new resource by posting an object to the given URI template.
It returns the result as automatically converted to the type specified in the responseType parameter.
Then we define a ObjectNode as our resource and response type as our result.
ObjectNode result = restTemplate.postForObject("https://gdxdispatcher.dev.awstrp.net/dispatcher/service/api/message",
request, ObjectNode.class);

Why OAuth2AccessTokenSupport always send POST request ??

I'm working with a Spring Boot + Spring Security OAuth2 to consume the Restful Oauth2 service.
Our Oauth2 service is always expects HTTP GET But OAuth2AccessTokenSupport always sending HTTP POST.
Result:
resulted in 405 (Method Not Allowed); invoking error handler
protected OAuth2AccessToken retrieveToken(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) throws OAuth2AccessDeniedException {
try {
this.authenticationHandler.authenticateTokenRequest(resource, form, headers);
this.tokenRequestEnhancer.enhance(request, resource, form, headers);
AccessTokenRequest copy = request;
ResponseExtractor delegate = getResponseExtractor();
ResponseExtractor extractor = new ResponseExtractor(copy, delegate) {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().containsKey("Set-Cookie")) {
this.val$copy.setCookie(response.getHeaders().getFirst("Set-Cookie"));
}
return ((OAuth2AccessToken) this.val$delegate.extractData(response));
}
};
return ((OAuth2AccessToken) getRestTemplate().execute(getAccessTokenUri(resource, form), getHttpMethod(),
getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()));
} catch (OAuth2Exception oe) {
throw new OAuth2AccessDeniedException("Access token denied.", resource, oe);
} catch (RestClientException rce) {
throw new OAuth2AccessDeniedException("Error requesting access token.", resource, rce);
}
}
<b>protected HttpMethod getHttpMethod() {
return HttpMethod.POST;
}</b>
protected String getAccessTokenUri(OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) {
String accessTokenUri = resource.getAccessTokenUri();
if (this.logger.isDebugEnabled()) {
this.logger.debug(new StringBuilder().append("Retrieving token from ").append(accessTokenUri).toString());
}
StringBuilder builder = new StringBuilder(accessTokenUri);
String separator;
if (getHttpMethod() == HttpMethod.GET) {
separator = "?";
if (accessTokenUri.contains("?")) {
separator = "&";
}
for (String key : form.keySet()) {
builder.append(separator);
builder.append(new StringBuilder().append(key).append("={").append(key).append("}").toString());
separator = "&";
}
}
return builder.toString();
}
Can Anyone explain me why OAuth2AccessTokenSupport always returns POST and
How to send HTTP GET request
To enable GET requests for the token endpoint, you need to add the following in your AuthorizationServerConfigurerAdapter:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
As for why only POST by default: I think that is due to GET requests potentially sending username and password information as request params (this is certainly the case for password grant). These may well be visible in web server logs, while POST body data is not.
Indeed the RFC for OAuth2 declares that the client must use HTTP POST when requesting an access token (https://www.rfc-editor.org/rfc/rfc6749#section-3.2)

Rally Changeset request returning null

I am attempting to automate some stuff in my Rally environment. Just as of a few days ago I have having this problem that I cannot seem to fix when I attempt to a valid rest exchange with Rally for information about some Changesets. This is run using Tomcat and simply listens from another server we have.
Here is some of the code and some logs:
String changesetRef defect.getAsJsonObject().get("Changesets").getAsJsonObject().get("_ref")
.toString();
try {
ResponseEntity<QueryResultWrapper> changeSetsRequest = caller.callRestfulAPIForRally(
changesetRef.substring(1, changesetRef.length() - 1), httpmethod,
new ParameterizedTypeReference<QueryResultWrapper>() {
});
// The Auth key is received from a file
public <T> ResponseEntity<T> callRestfulAPIForRally(String url, HttpMethod method, ParameterizedTypeReference<T> paramRef) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", RallyAuthKey);
headers.add("Content-Type", "application/json");
headers.add("Accepts", "application/json");
return callRestfulAPI(url, headers, method, paramRef);
}
private <T> ResponseEntity<T> callRestfulAPI(String url, HttpHeaders headers, HttpMethod method, ParameterizedTypeReference<T> paramRef) {
RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();
//Set timeout on connection to 20 seconds
simpleFactory.setConnectTimeout(20*1000);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(simpleFactory));
ResponseEntity<T> result = restTemplate.exchange(url, method, new HttpEntity<String>(headers), paramRef);
logger.info("Result: " + result.toString());
logger.info("Result body: " + result.getBody());
return result;
}
These loggers return the following when this is run:
INFO - Result: <200
OK,com.mycompany.webservice.core.jenkins.QueryResultWrapper#33eb30ec,{Date=[Thu, 07 Jul 2016 22:08:41 GMT], Content-Type=[application/json; charset=utf-8], Transfer-Encoding=[chunked], Connection=[keep-alive], Set-Cookie=[__cfduid=dc0b3ebf63634c86250efdedf10fd4ead1467929321; expires=Fri, 07-Jul-17 22:08:41 GMT; path=/; domain=.rallydev.com; HttpOnly, JSESSIONID=qs-app-111wgnt86c424tz1hwu48m187shg.qs-app-11;Path=/;Secure;HttpOnly, ZSESSIONID=CONFIDENTIAL;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SUBBUCKETID=0;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SERVERID=CONFIDENTIAL; path=/], Strict-Transport-Security=[max-age=31536000 ; includeSubDomains], X-XSS-Protection=[1; mode=block], RallyRequestID=[qs-app-111wgnt86c424tz1hwu48m187shg.qs-app-1128098501], Expires=[Thu, 01 Jan 1970 00:00:00 GMT], ETag=[W/"028b6add6cf4389520d5bdb5163a9a21c"], Vary=[Accept-Encoding], P3P=[CP="NON DSP COR CURa PSAa PSDa OUR NOR BUS PUR COM NAV STA"], Cache-Control=[private,max-age=0,must-revalidate], Server=[cloudflare-nginx], CF-RAY=[2bee9dd3697809b2-ORD]}>
2016-07-07 17:08:41,361 RestCallHelper
INFO - Result body:com.mycompany.webservice.core.jenkins.QueryResultWrapper#33eb30ec
Here is the structure for the request and how I have it set up... Spring should autopopulate all of theses values.
QueryResultWrapper
--> QueryResult
--> Results[]
--> Changes
-->_ref
When this executes it says it has made a GET request that, when I copy and past it into the browser, contains a valid Json like this:
{"QueryResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": [], "Warnings": [], "TotalResultCount": 1, "StartIndex": 1, "PageSize": 20, "Results": [{"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "_ref": "STUFF IS IN HERE", "_refObjectUUID": "9b96f131-f7a3-4615-b699-f793677836ba", "_objectVersion": "2", "_refObjectName": "Automate-web:057c595a52d0b39233bc4796d69cb09fb329d007", "CreationDate": "2016-07-07T18:45:31.240Z", "_CreatedAt": "today at 1:45 pm", "ObjectID": 58917491560, "ObjectUUID": "9b96f131-f7a3-4615-b699-f793677836ba", "VersionId": "2", "Subscription": {STUFF IS IN HERE}, "Workspace": {STUFF IS IN HERE }, "Artifacts": {STUFF IS IN HERE}, "Author": {STUFF IS IN HERE}, "Branch": null, "Builds": {STUFF IS IN HERE}, "Changes": {STUFF IS IN HERE}, "CommitTimestamp": "2016-07-07T18:44:16.000Z", "Message": "DE3333. Check for an agent on the agent lookup.", "Name": "CONFIDENTIAL", "Revision": "057c595a52d0b39233bc4796d69cb09fb329d007", "SCMRepository": {STUFF IS IN HERE}, "Uri": "STUFF IS IN HERE", "_type": "Changeset"}]}}
Now why does QueryResult return null?
It happens that the Spring integration of Jackson doesn't seem to like how the QueryResultWrapper looks and was not able to assign that variable anything. This is the following changes I made to no use Jackson.
public <T> T callRestfulAPIForRallyObjectMapper(String url, HttpMethod method, T obj) throws JsonParseException, JsonMappingException, IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", RallyAuthKey);
headers.add("Content-Type", "application/json");
headers.add("Accepts", "application/json");
return callRestfulAPIObjectMapper(url, headers, method, obj);
}
private <T> T callRestfulAPIObjectMapper(String url, HttpHeaders headers, HttpMethod method, T obj) throws JsonParseException, JsonMappingException, IOException {
RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();
//Set timeout on connection to 20 seconds
simpleFactory.setConnectTimeout(20*1000);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(simpleFactory));
ResponseEntity<String> result = restTemplate.exchange(url, method, new HttpEntity<String>(headers), new ParameterizedTypeReference<String>(){});
ObjectMapper mapper = new ObjectMapper();
#SuppressWarnings("unchecked")
T wrapper = (T) mapper.readValue(result.getBody(), obj.getClass());
return wrapper;
}
This is the changes I made in the code that calls the methods.
QueryResultWrapper changeSetsRequest = caller.callRestfulAPIForRallyObjectMapper(
changesetRef.substring(1, changesetRef.length() - 1), httpmethod,
new QueryResultWrapper());
QueryResult qr = changeSetsRequest.getQueryResult();

Resources