Backbone collection with CORS but no credentials - backbone.js

I have an app made with backbone. When collections try to sync, I get the following error:
XMLHttpRequest cannot load https://someserver/menu.json. The value of
the 'Access-Control-Allow-Origin' header in the response must not be
the wildcard '*' when the request's credentials mode is 'include'.
Origin 'http://www.otherdomain.com' is therefore not allowed access.
The credentials mode of requests initiated by the XMLHttpRequest is
controlled by the withCredentials attribute.
The collections just specify model and url, and have a simple parse.
I've try to override the sync method, as follows:
(function() {
var proxiedSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
options || (options = {});
if (!options.crossDomain) {
options.crossDomain = true;
}
if (!options.xhrFields) {
options.xhrFields = {withCredentials:true};
}
return proxiedSync(method, model, options);
};
})();
I run this function when app initialize. However, the error remains the same. I've tried different combinations (withCredentials:false, removing the line withCredentials etc) with no success.
The services are configured to serve '*'.
Is there a different way to tackle this problem?
Reconfiguring services or disabling browser security is not an option.

Your code will only execute if xhrFields is empty, maybe it is not.
Try something like
if (!options.xhrFields) {
options.xhrFields = {};
}
options.xhrFields.withCredentials = false;
This will only solve the problem temporarily. In a real application you will need the credentials, and you should add a whitelist of domains in server to actually solve the problem

Related

Laravel 5.4 / Angular possible mishandled rejection due to cross origin request blocked

I am currently building an application using token based authentication with Angular and Laravel. I initially set things up just to test the API by creating a BookController . At first I was getting a Cross Origin Request Block error when I tried to call this data from Angular. However I managed to resolve this by adding the headers to my routes/web.php file. Here is the whole file. NB: After adding these headers I was succesfully able to use the API even from another domain
<?php
header('Access-Control-Allow-Origin: *');
header( 'Access-Control-Allow-Headers: Authorization, Content-Type' );
//Route::get('/', 'BookController#show');
//Route::resource('book/create', 'BookController#create');
Auth::routes();
Route::get('/', 'HomeController#index');
Route::resource('book', 'BookController');
Route::resource('authenticate', 'AuthenticateController', ['only' => ['index']]);
Route::post('authenticate', 'AuthenticateController#authenticate');
However I am currently following this tutorial to set up token based authentication. https://scotch.io/tutorials/token-based-authentication-for-angularjs-and-laravel-apps
To summarise , my issue is when I submit the form containing username and password I am getting the following errors. Below I will try elaborate a bit more but it is quite difficult as there is alot to it.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://www.example.local/authenticate/.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).
And
Possibly unhandled rejection:
{"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://www.example.local/authenticate/","data":{"email":"dasdas#Dasa.com","password":"fsdfd"},"withCredentials":false,"headers":{"Accept":"application/json,
text/plain,
/","Content-Type":"application/json;charset=utf-8"}},"statusText":""}
I am using Angular UI Router V 0.4.2 and satellizer. My Angular version is 1.6.2 It using a different domain than the API. Much like the working example above.
On the laravel side I also followed this tutorial to add middleware to attempt to resolve this but no luck.
http://en.vedovelli.com.br/2015/web-development/Laravel-5-1-enable-CORS/
I will also include my AuthenticateController.php file..
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\User;
class AuthenticateController extends Controller
{
public function __construct()
{
// Apply the jwt.auth middleware to all methods in this controller
// except for the authenticate method. We don't want to prevent
// the user from retrieving their token if they don't already have it
$this->middleware('jwt.auth', ['except' => ['authenticate']]);
$this->middleware('cors');
}
public function index()
{
// Retrieve all the users in the database and return them
$users = User::all();
return $users;
}
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
try {
// verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
}
My issue is I do not even know if the "possibly unhandled rejection" is related to the "Cross-Origin Request Blocked" error. But I have to assume it is.
Can you recognise anything from my routes files that may be allowing one and not another?
EDIT:
I have noticed the difference between one request and another is that one is a GET request while another is an OPTIONS request. This may be the cause.
I have since added Header set Access-Control-Allow-Origin "*" to both the virtual hosts config file in Apache and to a .htaccess file in the root of the Laravel project. Still no change.
I am wondering is this related something in Angular
Your server code needs to handle that OPTIONS request by sending a headers-only response to it that includes the Access-Control-Allow-Methods: GET, POST, PUT, DELETE header and Access-Control-Allow-Headers: Authorization, Content-Type header.
Or you can just try using https://github.com/barryvdh/laravel-cors which makes all this easier.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests has general info you might want to read up on.

How to 'add' cookie only for angular.http request

I need to emulate some state in my developer utility, and for it I need to pass some special cookie to the http request which made via angular $http module.
Code for making http request looks simple:
if (condition){
var headers = getHeaders();
if (headers !== 'undefined'){
config['headers'] = headers;
}
}
return $http(config);
So looks like I should add some field to the this config. But I can't find any related data about this in $http docs.
I do not want to set cookie 'to the browser' becase I want to pass it only for some several requests performed asynchronously.
Is it real to nmake it with angular.js?

Angular and CORS once and for all

I have been struggling with this for quite a while now, and other than decided that I hate CORS with a passion, I can also confirm that the internet is full of ideas, but very few working solutions to this problem so thought I would try to get the answer once and for all.
The objective is to write angular code that can do the following.
1. Set the headers to allow for CORS.
2. Log into a CORS enabled application (in this case media wiki)
3. Make an api call to receive some JSON data.
I will even set up a test mediawiki server (with semantic media wiki) and set up a test user just for this. And who knows, if people are interested enough I'll even attempt to use the answer to write the worlds simplest CORS module for Angular.
On the server I'll do three things.
Install mediawiki and semantic Media wiki
Change the settings (in LocalSettings.php)
$wgEnableAPI = true;
$wgCrossSiteAJAXdomains = array( 'http://127.0.0.1:30004' );
$wgAPIRequestLog = "$IP/log/wgAPIRequestLog.log";
And change .htaccess to set the headers.
# CORS Headers (add this)
<ifModule mod_headers.c>
Header always set Access-Control-Allow-Origin: "*"
Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "X-Requested-With, content-type"
</ifModule>
# BEGIN WordPress (you should have this in your original WP .htaccess)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# CORS OPTIONS (add this too)
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
I think this is all I need to do, however, as I have only been able to make CORS requests in angular after using a chome extension to turn of origin headers, I don't know if this will work.
In the meanwhile, if anyone has any ideas or good resources for this. Please post.
====================== And now set up =====================
So have now set up a mediawiki for this purpose
Mediawiki url 'http://v-ghost.port0.org:8081/apiwiki'
User 'whowillhelp'
Password 'InternetWill'
If you want to try an API call:
http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=jsonfm
If you haven't logged in, it will return:
{
"error": {
"code": "readapidenied",
"info": "You need read permission to use this module",
"*": "See http://v-ghost.port0.org:8081/apiwiki/api.php for API usage"
}
}
Thats all OK.
If you run the same http.get('http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=json' in angular you will get a
XMLHttpRequest cannot load http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[MsgType::1]][[Parent::Support%20Functions]]|%3FMenuName&format=jsonfm. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:30004' is therefore not allowed access.
That's wrong on many levels:
first, it is horribly insecure to enable CORS without limitations on any service that is even remotely public.
second, you need to set the Access-Control-Allow-Credentials header for anything that CORS is actually useful for (if it's a public API, just use JSONP). MediaWiki does this for you, when properly configured.
third, $wgCrossSiteAJAXdomains takes domain names as its arguments, not URL prefixes, so that should be $wgCrossSiteAJAXdomains = array( '127.0.0.1:30004' );.
fourth, you need to set the origin parameter in the example, ie. the correct URL is 'http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=json&origin=http://127.0.0.1:30004.
Thank you Quentin.
After an awful lot of faffing about, it turns out that CORS is fully controlled bt the server, and at that the web server not the application.
All that was needed (once the API was on) would have been to add the stuff to the .htaccess file. Configure Apache to read it (http.conf).
You also need to ensure that mod_headers (called headers_module when httpd -t -D DUMP_MODULES) is loaded, but it should be default with Apache 2).
And if in doubt, there is a test service:)
http://client.cors-api.appspot.com/
================= Seems to work now ===================
And as I try to be a nice person that give back. Here is the factory I wrote. Technically it requires three calls (if login is required) one if you just want to run queries. Hope it helps someone
Might we worth mentioning, Mediawiki (and potentially all CORS implementations) require you to log in twice, once for authentication, once with the token it sent earlier. Guessing this is related to building the cookie.
.factory('CORSconnectFactory', function($http, $q){
//To call any of the http calls just do
// CORSconnectFactory.login(options )
// .then(function(data)
var CORSconnectFactory = {};
var CORScredentials = {};
var urlInit;
var deferred = $q.defer();
var datareq = {
method: 'POST',
//url: 'http://v-ghost.port0.org:8081/dbfswiki/api.php?action=login&format=json',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' //Set the coding, otherwise the server can't read you're request
}
//withCredentials: true,
/*
If you set Credentials your server gets rather picky oc CORS, more specifically Header always set Access-Control-Allow-Origin: needs to be set to exact address.
*/
//data: "lgname=APIread&lgpassword=apiread01"
}
CORSconnectFactory.initSettings = function(url, withCredentials) {
urlInit = url;
datareq.withCredentials= withCredentials;
}
CORSconnectFactory.login = function(id, password){
datareq.url = urlInit + "?action=login&format=json";
datareq.data= "lgname=" + id + "&lgpassword=" + password;
return $http(datareq)//You don't have to return this request, but it helps as it lets you use .login's promise in your code
.success(function(data) {
var results = data.login; //You might have to work around to find the right part of the structure
if ( results.result === "NoName"){
console.log("New request for Token")
} else if ( results.result === "NeedToken" ) {
console.log("Need a token this time") //Mediawiki API requires login then login with token to accept the connection.
CORScredentials = data.login
return results.result;
}
});
}
CORSconnectFactory.tokenReq = function(){
datareq.data = datareq.data = datareq.data + "&lgtoken=" + CORScredentials.token;
return $http(datareq)
.success(function (data) {
results= data.login;
CORScredentials=data.login;
console.log("And I am now " + results.result);
})
}
CORSconnectFactory.query = function(queryString) {
datareq.url = urlInit + "?action=ask&query="+ queryString + "&format=json";
datareq.data = ""; //Don't send data, it confuses the poor query (and your login details is in the token
return $http(datareq)
.success(function(data) {
var results = data.query.results;
return results;
});
}
return CORSconnectFactory;
});

Cross-Origin Request Blocked - Laravel

i have try to access(get request) my laravel api from ionic(angularjs) app.
but it keep getting bellow error.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL
please help me to fix this
This response is based on the fact that it appears you have control of serve-side code.
Have you added CORS support to the response? If you have not done so it could be like this.
You could add a handler thus:
Route::head("/<path to resource>", function () {
$r = Response::make("hello");
//Access-Control-Allow-Origin: http://api.bob.com
// Access-Control-Allow-Credentials: true
$r->header("Access-Control-Allow-Origin", "<*|client request domain>")
->("Access-Control-Allow-Credentials", "true")
->("Access-Control-Request-Method", "GET");
});
Perhaps you could set this headers on the response you are sending itself, I'm not sure. If that is possible and you might use this sort of thing on several routes it's better you prepare it as a filter. You can read more on CORS at http://www.html5rocks.com/en/tutorials/cors/ .
If what you want to send is json data think about serving your response to support jsonp. You could do something like:
$normalData = Model::all();
// if the client made a jsonp style request
if (Input::has("callback")) {
$data = "<script>" . Input::get("callback") . "(" . json_encode($normalData) . ")";
return Response::make($data)->header("Content-Type", "appplication/javascript");
}else {
//if not then return normally
return Response::json($normalData);
}
You are trying to access api from one domain to a different domain.
There are many ways to overcome this issue,but since it is a get Request,use **jsonp*.
Try something like this
var url = ' http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL&callback=JSON_CALLBACK';
$http.jsonp(url)
.success(function(data) {
});

Accessing / Setting Angular Cookie to interact with ServiceStack

I am working in a Windows Auth environment, and have created a Cookie in Angular to hold the currently logged in user's fullname:
returnsApp.run(["$cookies", "UserService", function($cookies, userService) {
userService.getUser().then(function(user) {
$cookies["ss-id"] = user.data.result.fullName;
console.log($cookies["ss-id"]); // Outputs: BiffBaffBoff (correct!)
});
}]);
Then when I try and access this cookie on the Server, inside my Service (It's hosted on a different server if that helps?), the cookie is null:
Cookie cookie;
Request.Cookies.TryGetValue(SessionFeature.SessionId, out cookie);
if (cookie == null)
throw new ArgumentException("User not found!");
I think I am missing a step, perhaps passing this cookie value along in the header when I make the service call? FYI, here is how I am making the service call:
var createReturn = function (returnObj) {
return $http.post(url, returnObj);
};
Something similar happened to me, but the other way,setting up a cookie in the server and when I tried to read in the client it was always null, I think you need to configure SS to be able to create non HttpOnly cookies.
try to put this setting in your host configuration:
Config.AllowNonHttpOnlyCookies = true;
As far I know you wanted to access an OOB auth cookie, I'm not quite sure if that cookie is only available in the server side, if that's the case try to create another cookie with the information you want to share between the client in the server and set the HttpOnly = false, that worked for me and it's something like that:
var resp =service.RequestContext.Get<IHttpResponse>();
resp.Cookies.AddCookie(new Cookie { Name = "r", Path = "/", Value = "from server", HttpOnly = false, Discard = false, Expires = DateTime.Now.AddHours(12) });
I hope that helps

Resources