has been blocked by CORS policy: Request header field x-xhr-logon is not allowed by Access-Control-Allow-Headers in preflight response - sapui5

I am trying to consume external restful web service in sap ui5. When I consume the same in fiori launchpad it throws below error in cosole and no data comes in the tile app. How can I over come with that? I have checked many blogs relted to that but didn't get any help from that.
Error :
Access to XMLHttpRequest at 'https://api.myjson.com/bins/ijyy2' from origin 'url2' has been blocked by CORS policy: Request header field x-xhr-logon is not allowed by Access-Control-Allow-Headers in preflight response.
Note : url2= https://sapmobile.mycompanyname.com is nothing but our fiori
launchpad url.

This is a known Fiori Launchpad problem. There is a file abap.js which overrides the default send method of XMLHttpRequest.
If you add the external API as a new destination in the SAP Cloud Platform (or use a Web Dispatcher in an on-premise environment) then there will be no more CORS calls and thus no more CORS problems.
If you want a pure JavaScript solution you can restore the original implementation with two functions. Add these to your controller.
Call the following immediately before accessing your external API
_overrideRequestPrototype: function () {
if (!XMLHttpRequest._SAP_ENHANCED) {
return;
}
this.__send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (oBody) {
let oChannel = {};
this._checkEventSubscriptions();
try {
oChannel = this._channel;
this._saveParams(oBody);
this._send(oBody);
if (oChannel) {
oChannel.sent();
}
} catch (oError) {
if (oChannel) {
oChannel["catch"](oError);
} else {
throw oError;
}
}
};
}
After the call, restore the SAP code with the following function:
_restoreRequestPrototype: function () {
if (!XMLHttpRequest._SAP_ENHANCED) {
return;
}
XMLHttpRequest.prototype.send = this.__send;
}

Related

Implementing Progress Bar for a client server case

I have following case, I have a client implemented in vue.js and a python base backend using flask framework.
I have a restful interface where from client I need to send a request to server to start certain operations. This operation may take long time 4-5 minutes and I know to show the progress. How this can be implemented between client and server with current technology stack for a http REST interface.
Since there are buncha of "loading" components for Vue (as Nuxt has their own $loading), i will just use an example b-spinner of BootstrapVue and Axios as HTTP Client:
<b-spinner ng-if="loadingProgress"> (shows Spinner if loadingProgress/sending request until server return response)
methods: {
sendEmail() {
//set loading progess as true
this.loadingProgress = true;
axios.post(
'[your_API_URL]',
{
// data you wanted to POST as JSON
},
).then((response) => {
// reset your component inputs like textInput to null
// or your custom route redirect with vue-router
}).catch((error) => {
if (error.response) {
alert(error.response.data); // the error response
}
});
},
Further example of my contact form using BSpinner + AJAX Axios POST on Formspree.io here
Another is vue-wait component (link here)
Hope those're what you're seeking.

Call external API using Mule SDK

I am trying to implement a Mule 4.x policy using Mule SDK. In doing so, I need to call an external API in the policy operations implementation. The result returned by the external API response would determine the policy output.
public class MyMulePolicyOperations
{
#MediaType( value = ANY, strict = false )
public void handle(
#Config MyMulePolicyConfiguration configuration,
#Alias( "httpRequestMethod" ) String httpRequestMethod,
CompletionCallback<String, HttpResponse> callback ) throws Exception
{
HttpResponseBuilder httpResponseBuilder = HttpResponse.builder();
String result = // call an external API and extract "result" from the response
if ( result.equals( configuration.getMyConfigValue() ) )
{
httpResponseBuilder.addHeader( "allow_request", "true" );
}
else
{
httpResponseBuilder.addHeader( "allow_request", "false" );
}
Result<String, HttpResponse> result = Result.<String, HttpResponse> builder()
.attributes( httpResponseBuilder.build() )
.build();
callback.success( result );
}
}
Can someone tell me how I can implement the REST client using Mule SDK?
If you want to implement an HTTP request inside a custom module, created with the Mule SDK, then you have to use the HTTP Client as described in the documentation: https://docs.mulesoft.com/mule-sdk/1.1/HTTP-based-connectors#use-the-mule-http-client
You didn't provide any reason or needs to implement the request inside a custom module. It would be way easier just to perform the HTTP request using the HTTP Requester inside the custom policy.

convenience method in spray (soon to be akka-http) to create a Location header w/ host port & contextRoot ?

When I create an object through POST in my Spray app I'd like to return a 201 status, together with a Location header that has the absolute URI of the newly created resource (including host port & contextRoot of my app)
Here is an example code fragment from my application...
post {
respondWithHeaders(Location( fullyQualifiedUri("/movies"))) {
entity(as[MovieImpl]) { (movieToInsert: MovieImpl) => {
addMovies(movieToInsert)
complete("OK")
}
}
}
}
Note that I now have to write the method 'fullyQualifiedUri' to return
a URI with host, port, etc. It would be nice if Spray did that for me
automagically.
Side note:
I think that having the Location header include the absolute URI of the newly
created resource makes it easier on my REST API's clients (although it does seem that there are a variety of opinions on this.)
Thanks in advance for any guidance you can provide.
-chris
To build the URI you'll need the Id of the newly created resource. Then you can use the requestInstance directive to get the incoming request URI and build the new resource URI from it. You also need to set the return code to Created to meet your requirements:
post {
requestInstance { request =>
val movieId = ???
respondWithHeaders(Location( request.uri.withPath(request.uri.path / movieId))) {
entity(as[MovieImpl]) { (movieToInsert: MovieImpl) => {
addMovies(movieToInsert)
complete(StatusCodes.Created)
}
}
}
}
}

Handling CSRF/XSRF tokens with Angular frontend and Drupal 7 backend

I'm in the process of building a new AngularJS frontend for a Drupal 7 website. This is using the Services module with session-based authentication, across two domains using CORS. I am able to authenticate with Drupal, retrieve the user object and session data, and then get the CSRF token from the services module. What I'm having trouble with is setting all this up in the header so that subsequent requests are authenticated. I understand the overall concept but am new to both AngularJS and preventing CSRF attacks.
From what I have gathered reading about this set-up with AngularJS and RubyOnRails, there can be inconsistencies between platforms concerning what the token is named and how it is processed. There also seems to be a number of suggestions on how to set this token in the header. However, I'm having trouble in finding a solid example of how to get these platforms speaking the same language.
The only thing I'm doing with my $httpProvider in app.js is:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
The login controller, in controller.js:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
The solution has to do with how the cookies need to be set and then passed through subsequent requests. Attempts to set them manually did not go well but the solution was simpler than I expected. Each $http call needs to set the options:
withCredentials: true
Another change I made was to use the term CSRF instead of XSRF, to be consistent with Drupal. I didn't use any built-in AngularJS CSRF functionality.
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
since it has been a year of this topic! not sure still encountering the same problem but for the ones who comes to search for answers here is how i handle it!
Pay attention the headers{} part i define a new header and call it X-CSRF-Token and grab value from the DOM of (serverside) generated html or php. It is not a good practise to also request the csrf token from the server.Cuz attacker could somehow request that as well. Since you save it as a cookie. Attacker can steal the cookie! No need to save it in a cookie! send the token with header and read it in the serverside to match it!
and for multitab of a same page issue. I use the same token thruout the whole session.
Only regenerate on login, logout and change of major site or user settings.
There is a great library callse ng-drupal-7-services. If you use this in you project it solves authentication / reauthentication and file / node creation aut of the box and you can fokuse on the importent stuff in your project.
So Authentication is there solved like this:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
There is also some kind of kitchen sink for this project here: Drupal-API-Explorer
Yes, each platform has their own convention in naming their tokens.
Here is a small lib put together hoping to make it easy to use with different platforms. This will allow you to use set names and could be used across all requests. It also works for cross-domain requests.
https://github.com/pasupulaphani/angular-csrf-cross-domain

Restangular all("customers").getList() does not return result

I started using Restangular to send RESTful requests from my AngularJS app. I have a REST service deployed on http://localhost:20080/v1/customer which produces JSON with customer information.
When I debug AngularJS app it hits a breakpoint in the back-end REST service, however in the browser console it always logs "Failed to find customers with status code 0". Moreover, I never hit the breakpoint in the function that I register as setResponseExtractor.
I also don't see any errors in the console.
When I open http://localhost:20080/v1/customer in the browser I get the following response:
[{"customerInfo":{"name":"My Name","email":"My Email"},"id":"6ca43d0f-94a8-36e8-af3d-963584573d6d"}]
My Restangular code is as follows:
var customerModule = angular.module('customer-module',
['restangular' ]).config(
['RestangularProvider', '$httpProvider',
function (RestangularProvider, $httpProvider)
{
RestangularProvider.setBaseUrl('http://localhost\\:20080/v1');
RestangularProvider.setResponseExtractor(function (response, operation, what) {
return response;
});
...
customerModule.controller('CustomerCtrl',
[ '$scope', 'Restangular', function ($scope, Restangular)
{
var baseCustomers = Restangular.all("customer");
$scope.customers = baseCustomers.getList().then(function (result) {
console.log("Got customers", response.status);
}, function (response) {
console.log("Failed to find customers with status code", response.status);
});
Thoughts?
I'm the creator of Restangular.
You also don't have to add the responseExtractor to the config if you're just returning the response. That's what it does by default.
If you have any other problem, please contact me!
The problem turned out to be with accessing REST services running on a different port than my AngularJS app.
I am moving this thread to AngularJS mailing list - "Problems with a basic $resource.get() call"
Alec