2

So I've got a bookmarklet which executes javascript on other websites, which I want to trigger an 403 Authentication Required header, once the Cache button on it, is clicked. That way, a prompt will come up asking them to login.

clickrobot on the apple website

The problem is that I'm not meant to provide an authentication header with the ajax request I am making, whilst having Access-Control-Allow-Origin: set to any domain with the * value. I'm supposed to explicitly define which domain I want to allow an 403 Authentication header to appear on, but I can't.

Here's my code.

.htaccess

header set Access-Control-Allow-Origin: *
#header set Access-Control-Allow-Methods: GET, POST, PUT, DELETE
header set Access-Control-Allow-Headers: Authorization

JQuery

$.ajax({
            headers : {
                "Authorization" : "Basic TVNF3TQtU1BGMjAx6C12bVxzbW4ydHBvaW50OlF3Z5J0eSEyM6Q1"
            },
            type: "GET",
            url: 'http://desbest.uk.to/clickrobot/favicon.png', //image for testing
            crossDomain:true,
            xhrFields: {
                withCredentials: true
            }, 
            //contentType: "application/json; charset=utf-8",
            //dataType: "json",
            success: function(data) {
                alert('ok!');
                //formatData(format_type,data);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert(textStatus + ' / ' + errorThrown);
            }
        }); 

The error I get

Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.

I've seen the Diigo bookmarklet do it, so it is possible, but how? Is it possible at all?

desbest
  • 4,269
  • 11
  • 45
  • 76

1 Answers1

5

Let us take a look at the documentation. There are two things that should be noted:

...the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header...

and

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding.

The headers that you should return are:

Access-Control-Allow-Origin: [some_origin]
Access-Control-Allow-Credentials: true 

You can return the first header by obtaining the Referer using your server script, retrieve the origin from the Referer and then returning the header with your script. In PHP we can do that as follows:

$urllist = parse_url($_SERVER['HTTP_REFERER']);
$origin = $urllist['scheme'] . '://' . $urllist['host'];
header("Access-Control-Allow-Origin: " . $origin);

Update: You should read Access-Control-Allow-Origin Multiple Origin Domains, in particular this answer. You might not need a PHP file if you can access your httpd.conf

Anyways, your url should not be the image, but the url to your PHP script.

url: 'http://desbest.uk.to/clickrobot/somescript.php'

In your php script you retrieve the origin of the request (which will be the page on which the bookmarklet appeared. And then you can output the header with the origin. Regardless, of where the bookmarklet appears, it should always about the correct header.

I'm not entirely sure, if the authorization dialog will popup using Ajax, even though you specified the correct headers. So, that is why we will have a look at Diigo below.


Diigo uses a different approach, namely: Once 'Sign in' has been clicked, JSONP is uses to request a javascript file which is generated by a server-side script (PHP for example) on their servers. JSONP is an alternative to CORS. JavaScript files from a different can be included in the page's header, with no problems at all, unlike Ajax requests.

If the user is not logged in, the request javascript file sends a 401 header on which the Authentication dialog is shown (this is coded in a server-side script!). The user enters his/her details and based on the entered information return the contents of the javascript file. If the user was successfully logged on it could return something like callback({ signedin : 1}), but otherwise callback({ signedin : 0}).

Now the javascript function callback with certain parameters are called. If the user is signed in, we display the bookmarklet's content.


What to put in your htaccess: Untested, but you would like to allow all origins and set the 'Access-Control-Allow-Origin' header to the value of the origin. I believe this should do the trick:

SetEnvIf Origin "^(.*)$" ORIGIN_DOMAIN=$1
Header set Access-Control-Allow-Origin "%{ORIGIN_DOMAIN}e" env=ORIGIN_DOMAIN
Community
  • 1
  • 1
dennisg
  • 4,328
  • 1
  • 21
  • 27
  • But all I have is a .js and .htaccess file, and no php pages used. The bookmarklet loads up the javascript to show on the page, and the htaccess file has the wildcard asterisk so that the bookmarklet can appear on any page. Where can I put the php? I need the bookmarklet to appear on every webpage **and** be able to have a 403 header by specifying a domain name. – desbest May 01 '12 at 22:11
  • 1
    I hope the update of my answer clarifies more. I also explained Diigo's approach. – dennisg May 01 '12 at 23:30
  • I can't figure out what to put inside .htaccess. I couldn't get the code in that answer to work. Why does the _allow origin_ have to be for multiple subdomains? I want it for every domain name. Putting in `"^(.*\.*\.*)$"` inside the regex, does not make it work. – desbest May 02 '12 at 12:07
  • Updated the answer. Currently sets the header to the Origin. I think this regular expression should work. If not: just see what headers all your files return now when requested and adapt your regular expression accordingly. – dennisg May 02 '12 at 12:28
  • The javascript will post to `ajaxcontrols.php` at `http://desbest.uk.to/clickrobot/ajaxcontrols.php`. I've put the source code of that file here. http://linesofcode.net/snippets/158 https://gist.github.com/c74195265d1cadf2f257. Also, `$urllist['origin']` and `$urllist['hostname']` are blank variables which don't print anything. – desbest May 02 '12 at 12:36
  • I changed the .htaccess file to what you said, and it didn't work. – desbest May 02 '12 at 12:43
  • In your php script, the following line is missing: $urllist = parse_url($_SERVER['HTTP_REFERER']), see my answer how to obtain the origin. If you set the header in your php script, you shouldn't have to put the same thing in your htaccess anymore. – dennisg May 03 '12 at 00:54
  • The $origin variable comes up blank, even if there is a referrer. If you click the _ajax controls link_ on http://filtermyarse4.uk.to at the top of the page, you will see for yourself. Updated code: https://gist.github.com/c74195265d1cadf2f257 – desbest May 03 '12 at 01:28
  • Sorry: it should be $urllist['host'] and not 'hostname'. It already prints the scheme like it should. – dennisg May 03 '12 at 09:20
  • I tried that and it made the $origin variable work. I tried it out in Firefox, and it says `401 Unauthorized` for `OPTIONS ajaxcontrols.php`. The login prompt never appeared. – desbest May 03 '12 at 23:44
  • If I visit the page: http://desbest.uk.to/tongclaw/ajaxcontrols.php?page=loginprompt, it does show the login prompt. Also, if I use your jQuery code it shows a login prompt. – dennisg May 04 '12 at 10:16
  • Yes it works now. I had a syntax error. I'll be testing my whole setup later this week. Thank you. – desbest May 04 '12 at 11:45
  • It works when called from the same page as on http://desbest.uk.to/clickrobot/test.html but not as a bookmarklet that runs on http://apple.com/startpage as the authentication prompt doesn't appear. You can install the bookmarklet at http://desbest.uk.to/clickrobot Click the cache button to get the #gocache authentication prompt to appear. The Apple search box is a good thing to click on, after clicking the robot face. – desbest May 04 '12 at 14:42
  • Seems like the following is still set incorrectly: Access-Control-Allow-Origin=://, http://stackoverflow.com. The server does not send a response if the request from a different origin than your own server. No response is received. Do you have something incorrect left in your htaccess? – dennisg May 04 '12 at 19:27
  • The .htaccess for http://desbest.uk.to/tongclaw/ajaxcontrols.php and which is what the javascript GETs, and http://desbest.uk.to/clickrobot/clickrobot.js is this https://gist.github.com/732275427231c4c87bc3 – desbest May 06 '12 at 14:41
  • I meant to say: if you've added Access-Control-Allow-Origin to your PHP file, you can remove it from your .htaccess. Make sure the header is set correctly. – dennisg May 06 '12 at 15:56
  • I've done that. Try out the Clickrobot bookmarklet in Safari or Chrome on the http://apple.com/startpage website. Click the robot face first, then the Apple search box, then cache. Then look in the Developer Tools console for the error. However it works on http://desbest.uk.to/clickrobot/test.html – desbest May 06 '12 at 16:34
  • Your header is currently incorrectly set to: Access-Control-Allow-Origin=:// It works on your test.html because it is the same domain. – dennisg May 06 '12 at 17:57
  • Header is set to what? Use ` backticks` to include code inside comments. (no spaces after or before one begins or ends) – desbest May 06 '12 at 18:10
  • The header `Access-Control-Allow-Origin` is set to `://` – dennisg May 06 '12 at 21:53
  • No it's not. It's set to `"%{ORIGIN_DOMAIN}e" env=ORIGIN_DOMAIN` like you said. – desbest May 06 '12 at 21:59
  • 1
    I mean: if you look at the response headers when you request the page `desbest.uk.to/tongclaw/ajaxcontrols.php?page=loginprompt` you can see that the header is set to `://`. Am I correct that you only set the header in your .htaccess file now? For some reason it does not work (I don't know why). It did seem to work when you set it *only* in your PHP file. – dennisg May 06 '12 at 22:58
  • But there are headers set in my php file, and my .htaccess file is blank. Now it works giving the 401 Unauthorised, but now there is no login prompt coming up in my web browser. – desbest May 07 '12 at 10:14