Spring Cloud Gateway and CORS header - java

I am trying to proxy-forward a request using org.springframework.cloud.gateway.mvc.ProxyExchange.
The call is working fine.
In my scenario I like to integrate it with the browser calls, but
get a CORS-header issue there.
(1) Source in the controller:
#RequestMapping(value = "/public**", method = RequestMethod.GET)
public ResponseEntity<byte[]> forwardHttpRequestForGet(
HttpServletRequest httpServletRequest,
#RequestParam MultiValueMap<String, String> requestParams,
#RequestHeader HttpHeaders requestHeaders,
ProxyExchange<byte[]> proxy) throws Exception {
ResponseEntity<byte[]> responseEntity = cloudGatewayService.proxyForwardToApplication(httpServletRequest, requestParams,requestHeaders, proxy);
return responseEntity;
}
(2) Source of used CloudGatewayService:
public ResponseEntity<byte[]> proxyForwardToApplication(
HttpServletRequest httpServletRequest,
MultiValueMap<String, String> requestParams,
HttpHeaders requestHeaders, ProxyExchange<byte[]> proxy) throws Exception {
String authorizationHeader = httpServletRequest.getHeader(AUTHORIZATION_HEADER);
String forwardUrl = "newUrl"
return proxy.sensitive("cookie")
.headers(requestHeaders)
.uri(forwardUrl).get();
}
How can I add CORS support for Spring Cloud Gateway ?

There is nothing specific to cloud MVC. Even if it is a proxy, we have to add CORS support to the web application.
As it is a spring boot project, I have added spring security as well here. Added a filter which can populate the headers did the job.
Note : add whatever required headers for your OPTION call (preflight),
Also support GET,POST, DELETE, etc calls accordingly.
The response headers can be added to the http response

Related

How to receive application/x-www-form-urlencoded Request parameters in Spring rest controller

I'm trying to write a rest endpoint which receives application/x-www-form-urlencoded. But the endpoint does not accept request parameters for #RequestBody or #RequestParam
I Have tried using MultiValueMap to grab the request parameters. But I always get 0 parameters.
Is there a way to get request values to the MultiValueMap or some other POJO class.
AD=&value=sometestvalue - This is the application/x-www-form-urlencoded requestbody. I'm trying to do the request using postman
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap formData,
HttpServletRequest servletRequest, ServiceContext serviceContext){
log.info("!--REQUEST START--!"+formData.toString());
}
You need to use MultiValueMap<String, String>
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap<String, String> formData) {
System.out.println("!--REQUEST START--!" + formData.toString());
return null;
}
You do not use #RequestParam on a POST request as the data is not in the URL as in a GET request.
You should use #RequestBody (doc) along with registering appropriate HttpMessageConverter. Most likely you should use: FormHttpMessageConverter
Try #ResponseBody. Then, change to a String, not a MultiValueMap, to see if the body comes in to the request.

How to set HTTP Header for OAuth2RestTemplate

Am trying to use Spring Secruity's OAuth API to obtain an access token from an externally published API within a Spring MVC 4 based Web Services (not Spring Boot).
This curl command works (and its contents are all that I need to obtain an access token):
curl -X POST \
https://api.app.com/v1/oauth/token \
-H 'content-type: application/x-www-form-urlencoded' \
-d'grant_type=client_credentials&client_id=bcfrtew123&client_secret=Y67493012'
Spring Security OAuth API:
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
My code to obtain access token:
#RequestMapping(value = "/getAccessToken", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
public OAuth2AccessToken getAccessToken(#RequestParam(value="client_id", required=true) String clientId, #RequestParam(value="client_secret", required=true) String clientSecret) throws Exception {
String tokenUri = "https://api.app.com/v1/oauth/token";
ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
resourceDetails.setAccessTokenUri(tokenUri);
resourceDetails.setClientId(clientId);
resourceDetails.setClientSecret(clientSecret);
resourceDetails.setGrantType("client_credentials");
resourceDetails.setScope(Arrays.asList("read", "write"));
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
oauth2RestTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
OAuth2AccessToken token = oauth2RestTemplate.getAccessToken();
return token;
}
When I invoke the getAccessToken call from my local tomcat instance:
access_denied
error_description=Unable to obtain a new access token for resource 'null'.
The provider manager is not configured to support it.
Am suspecting the reason is that my Http Header's Content-Type is not set for
application/x-www-form-urlencoded
How do I do set that for:
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
If you notice, I am trying to set in inside the #RequestMapping and don't think that its working:
#RequestMapping(consumes="application/x-www-form-urlencoded")
The http headers for accessing the token in Oauth2Restemplate in case of Client credentials are set in below method of ClientCredentialsAccessTokenProvider (since grant type is client credentials)
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
throws UserRedirectRequiredException, AccessDeniedException,
OAuth2AccessDeniedException {
ClientCredentialsResourceDetails resource = (ClientCredentialsResourceDetails) details;
return retrieveToken(request, resource, getParametersForTokenRequest(resource), new HttpHeaders());
}
We can set the http headers by having new custom Access token provider for client credentials and modifying the method as follows:
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
throws UserRedirectRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
ClientCredentialsResourceDetails resource = (ClientCredentialsResourceDetails) details;
HttpHeaders headers1 = new HttpHeaders();
headers1.add("Content-Type", "application/x-www-form-urlencoded");
return retrieveToken(request, resource, getParametersForTokenRequest(resource), headers1);
}
You can keep the class same as ClientCredentialsAccessTokenProvider and add just the header lines.
Last step will be to set this new class as access token in configuration of Oauth2RestTemplate.
oauth2RestTemplate.setAccessTokenProvider(new ClientCredentialsCustomAccessTokenProvider());
This worked for me!
Here's another variation on the answer just to override the default Accept Header interceptor using a Lambda expression:
#Bean
protected RestTemplate restTemplate() {
return new RestTemplate() {
#Override
public <T> RequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
return request -> {
request.getHeaders().setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
};
}
};
}
If you are using Spring boot mention the authentication scheme as form, it will solve the issue.
security:
oauth2:
client:
clientAuthenticationScheme: form

Optional Request Header in Spring Rest Service

I'm using Spring Restful web service & having request body with request header as shown below:
#RequestMapping(value = "/mykey", method = RequestMethod.POST, consumes="applicaton/json")
public ResponseEntity<String> getData(#RequestBody String body, #RequestHeader("Auth") String authorization) {
try {
....
} catch (Exception e) {
....
}
}
I want to pass one more optional request header called "X-MyHeader". How do I specify this optional request header in Spring rest service?
Also, how do I pass this same value in response header??
Thanks!
UPDATE: I just found that I can set required=false in request header, so one issue is resolved. Now, the only issue remaining is how do I set the header in the response??
Use required=false in your #RequestHeader:
#PostMapping("/mykey")
public ResponseEntity<String> getData(
#RequestBody String body,
#RequestHeader(value = "Auth", required = false) String authorization) {}
This question is answered here:
In Spring MVC, how can I set the mime type header when using #ResponseBody
Here is a code sample from: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-httpentity
#RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}

Spring MVC Flash Attributes

How do I enhance the Controller below to utilize Spring MVC's Flash Attributes? The use case is a copy function.
POST/REQUEST/GET implementation:
client clicks "copy" button in the UI
server sets the response "Location" header
client redirects to "path/to/page?copy"
server provides ModelAndView
client (jQuery success function) sets window.location
FooController redirect method:
#RequestMapping(value = "{fooId}", method = POST, params = { "copy" })
#Transactional
#ResponseStatus(CREATED)
public void getCopyfoo(#PathVariable String fooId,
HttpServletResponse response, RedirectAttributes redirectAttrs) {
response.setHeader("Location", uriPath);
//no worky?!:
redirectAttrs.addFlashAttribute("barKey", "barValue");
}
FooController get method:
#RequestMapping(value = "{fooId}", method = GET)
#Transactional(readOnly = true)
public ModelAndView findFooById(#PathVariable String fooId,
HttpServletRequest request){
Map<String, ?> map = RequestContextUtils.getInputFlashMap(request);
// map is empty...
return modelAndViewFromHelperMethod();
}
I'm affraid that RedirectAttributes work only with RedirectView,
so Your controller should return for example:
1. String: "redirect:/[uriPath]"
2. new RedirectView([uriPath])
If you realy need to handle server response with JS, then maybe handling HTTP status 302 would help.

Insert info into an HTTP header

I’m trying to add some data to the http header that comes back from a RESTful web service call. Is it possible to use JAX-RS or something else to add data to the response header?
Example of my method:
#GET
#Path("getAssets")
public List<Asset> getAssets(#QueryParam("page") #DefaultValue("1") String page,
#QueryParam("page_size") #DefaultValue(UNLIMITED) String pageSize) throws Exception
{
stuff…
}
Thanks for your help.
Using something such as Spring's MVC controller, you can easily get and set response headers as in the below example. A list of common headers can be found here Wikipedia - Common Headers
...
#RequestMapping(method = RequestMethod.GET)
public String myGetMethod(#PathVariable string owner, #PathVariable string pet, HttpServletResponse response) {
response.setContentType("text/html");
response.setHeader("Content-disposition","Content-Disposition:attachment;filename=fufu.png");
}
...

Categories

Resources