POST405 (Method Not Allowed) - angularjs

I am using AngularJS to send a POST request from my controller and I'm getting this error:
POST not supported
The JS function is the following:
addUserDetails: function(addUser) {
alert("M into add user function in service");
return restClientTemplate.execute({
method: 'POST',
url: 'json/user-add',
data: addUser
});
}
My Java Spring Controller is the following:
#Controller
public class AddUserController {
#Resource
private Settings settings;
#Resource
private RestOperations rest;
private static final String ORGANIZATION_URL_KEY = "configuration.organization.service.endpointUrl";
private static final String ORG_PRODUCT_LIST_URL_KEY = "configuration.org.product.list.service.endpointUrl";
#RequestMapping(value = "/json/user-add", method = RequestMethod.POST, produces = "application/json")
public ServiceResponse addOrganization(#RequestBody SaveOrganizationForm request) {
System.out.println("M into controllerrrr");
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode requestBody = objectMapper.createObjectNode();
populateRequestObject(request, objectMapper, requestBody);
String url = MessageUtil.format(settings.getString(ORGANIZATION_URL_KEY) + "/s2");
ServiceResponse response = rest
.exchange(url, HttpMethod.POST, new HttpEntity<>(requestBody), ServiceResponse.class).getBody();
return response;
}

Related

Could someone help me build a test apex for an opportunity closed/won trigger?

I'm not a developer and we don't have one currently on our staff. So I looked all over the web and modified this Apex Class to suit my needs so that when an opportunity is marked as closed/won I get a small message in Slack.
It works great and I'd like to send this to Production. However, I didn't realize that I need to include a test for this and I am stuck on what that means.
Here's my Apex Class:
public with sharing class SlackPublisher {
private static final String SLACK_URL = 'https://hooks.slack.com/services/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';
public class Oppty {
#InvocableVariable(label='Opportunity Name')
public String opptyName;
#InvocableVariable(label='Opportunity Owner')
public String opptyOwnerName;
#InvocableVariable(label='Account Name')
public String acctName;
#InvocableVariable(label='Amount')
public String amount;
}
public class UrlMethods {
String BaseUrl; // The Url w/o the page (ex: 'https://na9.salesforce.com/')
String PageUrl; // The Url of the page (ex: '/apex/SomePageName')
String FullUrl; // The full Url of the current page w/query string parameters
// (ex: 'https://na9.salesforce.com/apex/SomePageName?x=1&y=2&z=3')
String Environment; // Writing code that can detect if it is executing in production or a sandbox
// can be extremely useful especially if working with sensitive data.
public UrlMethods() { // Constructor
BaseUrl = URL.getSalesforceBaseUrl().toExternalForm(); // (Example: 'https://na9.salesforce.com/')
}
}
#InvocableMethod(label='Post to Slack')
public static void postToSlack ( List<Oppty> opps ) {
Oppty o = opps[0]; // bulkify the code later
Map<String,Object> msg = new Map<String,Object>();
msg.put('text','Deal ' + o.opptyName + ' was just Closed/Won' + ':champagne:' + '\n' + 'for a total of ' + '$' + o.amount);
msg.put('mrkdwn', true);
String body = JSON.serialize(msg);
System.enqueueJob(new QueueableSlackPost(SLACK_URL, 'POST', body));
}
public class QueueableSlackPost implements System.Queueable, Database.AllowsCallouts {
private final String url;
private final String method;
private final String body;
public QueueableSlackPost(String url, String method, String body) {
this.url = url;
this.method = method;
this.body = body;
}
public void execute(System.QueueableContext ctx) {
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse res = http.send(req);
}
}
}
and what I found online as a base for a test was this:
#isTest
private class SlackOpportunityPublisherTest {
private class RestMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
String fullJson = 'your Json Response';
HTTPResponse res = new HTTPResponse();
res.setHeader('Content-Type', 'text/json');
res.setBody(fullJson);
res.setStatusCode(200);
return res;
}
}
static testMethod void service_call() {
Test.setMock(HttpCalloutMock.class, new RestMock());
Test.startTest();
//your webserive call code
Database.GetUpdatedResult r =
Database.getUpdated(
'amount',
Datetime.now().addHours(-1),
Datetime.now());
Test.StopTest();
}
}
When I try to validate this in production it says it only gives me 68% coverage and I need 75%. Can someone help me write the test so that I can put into Prod?

Spring API Cross Domain

I got a tomcat server using Spring and a React website. I'm trying to fetch data, with postman it's ok but when I'm using my react frontend this is the error I got :
Access to fetch at
'http://127.0.0.1:8080/planningAccouplementWS/acquerirFemelles' from
origin 'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: It
does not have HTTP ok status.
On the frontend side, I'm calling this code :
static acquerirFemelles(femelles) {
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("Content-Type", "application/json");
myHeaders.append("apikey", "sfj4-R5sdhffhs-fnhvSDFYT:DSRrfdj#fhqsm4zxwc-vhglxs15");
let obj = [];
femelles.forEach(femelle => {
obj.push({
"codePays": femelle.cheptel_pays,
"numeroNational": femelle.numero_national.substring(2),
"nom": femelle.bovin_nom
})
});
var raw = JSON.stringify({
"listeFemelles": obj
});
console.log(raw);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw
};
fetch("http://127.0.0.1:8080/planningAccouplementWS/acquerirFemelles", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
And on my server side :
WebConfig.java
public class WebConfig implements WebMvcConfigurer{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH")
.allowedOrigins("http://locahlost:3000")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
SecurityConfiguration.java
#Configuration
#EnableWebSecurity
#Order(1)
#PropertySource(value = "classpath:/security.properties")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${yourapp.http.auth-token-header-name}")
private String principalRequestHeader;
#Value("${yourapp.http.auth-token}")
private String principalRequestValue;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
System.out.println("Cors configure");
APIKeyAuthFilter filter = new APIKeyAuthFilter(principalRequestHeader);
filter.setAuthenticationManager(new AuthenticationManager() {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
if (!principalRequestValue.equals(principal))
{
throw new BadCredentialsException("The API key was not found or not the expected value.");
}
authentication.setAuthenticated(true);
return authentication;
}
});
httpSecurity.
antMatcher("/**").
csrf().disable().cors().and().
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilter(filter).authorizeRequests().anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl());
}
#Bean
CorsConfigurationSource corsConfigurationSource()
{
System.out.println("Cors corsConfigurationSource");
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin("http://localhost:3000");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
CorsFilter filter = new CorsFilter(source);
return source;
}
}
And finaly my GET method
#CrossOrigin(origins = "*", allowedHeaders = "*")
#PostMapping("/acquerirFemelles")
public DonneesElevages acquerirFemelle(#RequestBody DonneesElevages donneesElevage) throws MetierException {
System.out.println("Acquerir Femelles");
DonneesElevages de = new DonneesElevages();
FemelleMetier femelleMetier = new FemelleMetier();
CoefficientMetier coefMetier = new CoefficientMetier();
HashMap<String, ParametreIndex> listeParametreIndex = coefMetier.rechercherParametresIndex();
de.setListeFemelles(femelleMetier.rechercheFemelles(donneesElevage.getListeFemelles(), listeParametreIndex));
return de;
}
You have the #CrossOrigin annotation on your mapping method, put this annotation on to your controller class.
if you want to do it the simple way, you can just use #CrossOrigin annotation up on your controller classes.
But anyway, be cautious that this will let through all requests no matter from which url or port they're coming from.

Spring boot does not receive headers from react js

I'm implementing a ReactJs applications. I am using axios to invoke server side services built using Spring Boot. I need to send the header "Authorization: Bearer token-value". This is the client side code:
var options = {
withCredentials: true,
headers: {'Authorization': 'Bearer token-value'}
};
axios.post('http://localhost:9090/services/list', null, options)
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
This is the Spring Boot controller:
#RestController
public class ServiceController {
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
private static final String BEARER = "Bearer ";
private static String getToken(HttpServletRequest request) {
String header = request.getHeader(AUTHORIZATION_HEADER_NAME);
if (header == null || header.trim().equals("")) {
return null;
}
header = header.trim();
if (!header.startsWith(BEARER)) {
return null;
}
return header.substring(BEARER.length()).trim();
}
#GetMapping
#RequestMapping(value = "/services/list", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<?> getTargets(HttpServletRequest request, HttpServletResponse response) {
String token = getToken(request);
if (token == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
DTOObject obj = goForTheBusinessObject(token);
return new ResponseEntity<>(obj, HttpStatus.OK);
}
}
This is the CORS configuration
#Configuration
public class RestConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("POST");
config.addAllowedMethod("GET");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PUT");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
If I invoke the service using curl I got the expected response:
curl -X POST -H "Authorization: Bearer token-value" http://localhost:9090/services/list
If I invoke the service using post man, again I got the right answer.
But when I executed the ReactJS application, the server never receive the "Authorization" header.
Somebody help me please !!
You are facing CORS issues, Implement this class to resolve this-
#Component
public class CorsFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (exchange != null) {
exchange.getResponse().getHeaders().add("Access-Control-Allow-Origin", "*");
exchange.getResponse().getHeaders().add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
exchange.getResponse().getHeaders().add("Access-Control-Allow-Headers",
"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range");
exchange.getResponse().getHeaders().add("Access-Control-Max-Age", "1728000");
if (exchange.getRequest().getMethod() == HttpMethod.OPTIONS) {
exchange.getResponse().getHeaders().add("Access-Control-Max-Age", "1728000");
exchange.getResponse().setStatusCode(HttpStatus.NO_CONTENT);
return Mono.empty();
} else {
exchange.getResponse().getHeaders().add("Access-Control-Expose-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range");
return chain.filter(exchange);
}
} else {
return chain.filter(exchange);
}
}
}
For more info on CORS visit this
Update: For scanning the component you can do following-
#ComponentScan(value = "com.pck", // cors filter package
useDefaultFilters = false)
public class MainClass {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.
run(MainClass.class, args);
}
}

Spring-boot angularjs satelizer cors filter

Have a problem with CORS filter, i think.
Because when i send request with Authorization header by Intellij Idea REST Tools, my filter catch a Authorization header.
But when i try to send request from client side from another server, filter does not see my header(return null).
I`m using spring boot, angularjs, salelizer and JWT for build token.
Params for building token on server side.
private static final JWSHeader JWT_HEADER = new JWSHeader(JWSAlgorithm.HS256);
private static final String TOKEN_SECRET = "Bearer";
public static final String AUTH_HEADER_KEY = "Authorization";
My Auth filter
public class AuthFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String authHeader = httpRequest.getHeader(AuthUtils.AUTH_HEADER_KEY);
if (StringUtils.isBlank(authHeader) || authHeader.split(" ").length != 2) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_ERROR_MSG);
} else {
JWTClaimsSet claimSet = null;
try {
claimSet = (JWTClaimsSet) AuthUtils.decodeToken(authHeader);
} catch (ParseException e) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, JWT_ERROR_MSG);
return;
} catch (JOSEException e) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, JWT_INVALID_MSG);
return;
}
// ensure that the token is not expired
if (new DateTime(claimSet.getExpirationTime()).isBefore(DateTime.now())) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, EXPIRE_ERROR_MSG);
} else {
chain.doFilter(request, response);
}
}
}
#Override
public void destroy() { /* unused */ }
#Override
public void init(FilterConfig filterConfig) throws ServletException { /* unused */ }
}
My CORS filter in Web Mvc config file
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Authorization");
config.addExposedHeader("Content-Type");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
My security configure
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"**").permitAll().and().authorizeRequests()
.antMatchers( "/index","/api/**", "/auth/**", "/js/**", "/css/**", "/html/**")
.permitAll().anyRequest().authenticated();
My cliend side configs
function configHttp($httpProvider, $authProvider){
console.log("sdfd");
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
var token = sessionStorage.getItem("satellizer_token");
if (token && $authProvider.httpInterceptor) {
token = $authProvider.authHeader === 'Authorization' ? 'Bearer ' + token : token;
$httpProvider.defaults.headers.common[$authProvider.authHeader] = token;
}
}
function configAuth($authProvider) {
$authProvider.httpInterceptor = function() { return true; };
$authProvider.baseUrl = 'http://localhost:8080';
$authProvider.loginUrl = '/auth/login';
$authProvider.signupUrl = '/auth/registration';
$authProvider.tokenName = 'token';
$authProvider.storageType = 'sessionStorage';
$authProvider.authToken = 'Bearer';
$authProvider.authHeader = 'Authorization';
}
There are a few options described here.
One option would be to annotate your controller method or class with #CrossOrigin.
If you want global config, you could add a new bean. I took this from the Spring doc listed above and modified it so that the mapping is /*. You can modify that path to be suitable for your application. According to the javadoc all origins will be allowed by default.
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*");
}
};
}

How to send JSON from clinet and get DTO-Object on server?

At client I have:
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
var data = {f_name: 'test1', s_name: 'test2'};
var fd = new FormData();
fd.append('data', angular.toJson(data));
fd.append("file", file);
$http({
method: 'POST',
url: 'EmployeeService/employee/upload',
headers: {'Content-Type': undefined},
data: fd,
transformRequest: angular.identity
})
.success(function(data, status) {
alert("success");
});
}
And on server (Spring):
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String postFile(#RequestParam(value="file", required=false) MultipartFile file,
#RequestParam(value="data") Object data) throws Exception {
System.out.println("data = " + data);
return "OK!";
}
But data is String: "{"f_name":"test1","s_name":"test2"}". A have DTO-class:
public class EmployeeDTO(){
private String f_name;
private String s_name;
//setters and getters
}
And on server I want to get:
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String postFile(#RequestParam(value="file", required=false) MultipartFile file,
#RequestParam(value="data") EmployeeDTO employeeDTO) throws Exception {
//etc.
}
How to send data from client (file and data) and on server get file and EmployeeDTO object?
while you can use annotation #RequestBody to get Object from json string.
for example:
#ResponseBody
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(#RequestBody EmployeeDTO employeeDTO){
//TODO do something;
return "success";
}
or you can receive string and then use ObjectMapper to convert string to object
for example:
EmployeeDTO employeeDTO = new ObjectMapper().readValue("here is json string", EmployeeDTO.class);
You could register a Converter<String, EmployeeDTO> that would use Json ObjectMapper and you could write you controller method as you want (I assume you use Jackson2)
If you need that in only this method, it may be simpler to do it explicitely :
#Autowired
private MappingJackson2HttpMessageConverter jsonConverter;
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String postFile(#RequestParam(value="file", required=false) MultipartFile file,
#RequestParam(value="data") String data) throws Exception {
EmployeeDTO employeeDTO = jsonConverter.getObjectMapper().readValue(data,
EmployeeDTO.class);
return "OK!";
}
Alternatively, you could put the object directly in the FormData (angularJS side) and get it with #ModelAttribute spring side :
var fd = new FormData();
fd.append("file", file);
fd.append("f_name", 'test1');
fd.append("s_name", 'test2'};
and
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String postFile(#RequestParam(value="file", required=false) MultipartFile file,
#ModelAttribute EmployeeDTO employeeDTO) throws Exception {

Resources