Why doesn't Safari set the cookies from my Perl CGI script? - perl

I have a Perl-based website that attempts to set a number of cookies on the users first visit and I just noticed that Safari has stopped setting all but the first cookie that is passed. On first visit two cookies should be set which are 'location' and 'referrer'. In IE and Firefox the cookies are being set correctly but Safari is only setting the 'location' cookie. I tried changing the names, values, etc. and the conclusion I've come to is that Safari is just setting the first of the two cookies:
Here is the code that is setting the cookies:
# Add location cookie if necessary
if(!$query->cookie('location') && $user_location) {
my $cookie = $query->cookie(-name=>'location',-value=>qq|$user_lcoation|,-domain=>".domain.com",-path=>'/',-expires=>'+1Y');
push(#cookies,$cookie);
}
# Add referrer if first visit
if(!$query->cookie('referrer')) {
if($ENV{'HTTP_REFERER'}) {
my $cookie = $query->cookie(-name=>'referrer',-value=>$ENV{'HTTP_REFERER'},-domain=>".domain.com",-path=>'/',-expires=>'+3M');
push(#cookies,$cookie);
}
else {
my $cookie = $query->cookie(-name=>'referrer',-value=>'unknown',-domain=>".domain.com",-path=>'/',-expires=>'+3M');
push(#cookies,$cookie);
}
}
if(scalar(#cookies)) {
print $query->header(-cookie=>\#cookies);
}
Here is what I get when I try to access the website from curl:
curl -so /dev/null -D - http://domain.com
HTTP/1.1 200 OK
Date: Thu, 18 Feb 2010 20:19:17 GMT
Server: Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 PHP/5.2.8 mod_perl/2.0.4 Perl/v5.8.8
Set-Cookie: location=Dallas; domain=.domain.com; path=/; expires=+1Y
Set-Cookie: referrer=unknown; domain=.domain.com; path=/; expires=Wed, 19-May-2010 20:19:20 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=ISO-8859-1
Any ideas? I'm at a loss as to what I can do to help resolve this issue since it seems that my script is passing them correctly. Thanks in advance for any insights or ideas you might have!

Look at the expires date on the first cookie header -- it's a literal +1Y instead of the actual standard datestamp that it should be. My guess is that your version of Safari is choking on this and simply refuses to parse the remaining cookie headers.
To set a one-year expiration date, the correct syntax is -expires => '+1y' (lowercase Y).

Try upgrading CGI.pm (do cpan CGI). I had similar problem with cookies that was solved by CGI.pm upgrade.

a bit late for an aswer, but later better than never :
a simple way, without having to reinstall/update CGI.pm, is to specify the date you
want your cookie to expire, using DateTime.pm :
my $cookie = CGI->new->cookie(
-name=>'cookie_name',
-value=>'value',
-domain=>$ENV{'HTTP_HOST'},
-expires=>((DateTime->now->set_time_zone('local'))->add(months=>1)->strftime("%a, %d %b %Y %I:%M:%S GMT")),
-path=>'/',
);
there i've got a cookie that will last for 1 month.
I tested it on safari under XP, works fine.
hope this will help

Related

SharePoint Online REST by using access_token still getting 403

following this article http://www.ktskumar.com/2017/01/access-sharepoint-online-using-postman/
I was able to register an app and get a client_id as well as a security token.
Now if I follow the article, I'm able to get an access token by using Postman, SOAP UI as well as by using a REST client in browser. I'm also able to fetch data from SharePoint using this token.
However, I need to do this from a unix based middleware, which is able to do HTTP calls as well. I tried everything but I can't get it work.
Preparation that has been done before:
register new app by using https://.sharepoint.com/sites//_layouts/15/appregnew.aspx
add app and permission to site collection to grant access by using https://.sharepoint.com/sites//_layouts/15/appinv.aspx
After this, I do some webservice calls like this
I try to get an access token by calling https://accounts.accesscontrol.windows.net/<mytenant_id>/tokens/OAuth/2 and got one. I can use this token in every REST client as well as in Postman. So I assume it is a valid one.
Now I try to retrieve the Title of web by calling this URL https://<my_tenant>.sharepoint.com/sites/<site_collection>/_api/web?$select=Title
This always returns a 403 but only when using middleware system. If I do the same from any other client, it works.
Could someone please enlight me what is going wrong here?
This is how the request header looks like (I've shorten some things)
cookie'='fpc=...some other stuff; domain=.accounts.accesscontrol.windows.net; path=/; secure; HttpOnly; SameSite=None
x-ms-gateway-slice=prod; path=/; SameSite=None; secure; HttpOnly
stsservicecookie=ests; path=/; SameSite=None; secure; HttpOnly'
'User-Agent'='Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0'
'accept'='application/json;odata=verbose'
'Authorization'='Bearer eyJ0eXAiOiJKV1QiLCJhbG... lot following here, but only value of access_token'
This is what the response looks like:
'RESPONSE_HTTP_HEADER_X-ASPNET-VERSION'='4.0.30319'
'RESPONSE_HTTP_HEADER_LAST-MODIFIED'='Tue, 23 Jun 2020 08:10:42 GMT'
'RESPONSE_HTTP_HEADER_X-SHAREPOINTHEALTHSCORE'='1'
'RESPONSE_HTTP_HEADER_X-FORMS_BASED_AUTH_RETURN_URL'='https://<mytenant>.sharepoint.com/_layouts/15/error.aspx'
'RESPONSE_HTTP_HEADER_CACHE-CONTROL'='private, max-age=0'
'RESPONSE_HTTP_DATA'='<?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code>-2147024891, System.UnauthorizedAccessException</m:code><m:message xml:lang="en-US">Access denied. You do not have permission to perform this action or access this resource.</m:message></m:error>'
'RESPONSE_HTTP_HEADER_X-POWERED-BY'='ASP.NET'
'RESPONSE_HTTP_HEADER_DATE'='Tue, 23 Jun 2020 08:10:42 GMT'
'RESPONSE_HTTP_STATUSLINE'='Forbidden'
'RESPONSE_HTTP_HEADER_EXPIRES'='Mon, 08 Jun 2020 08:10:42 GMT'
'RESPONSE_HTTP_HEADER_CONTENT-SECURITY-POLICY'='frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com;'
'RESPONSE_HTTP_HEADER_MICROSOFTSHAREPOINTTEAMSERVICES'='16.0.0.20203'
'RESPONSE_HTTP_HEADER_X-MSDAVEXT_ERROR'='917656; Access+denied.+Before+opening+files+in+this+location%2c+you+must+first+browse+to+the+web+site+and+select+the+option+to+login+automatically.'
'RESPONSE_HTTP_HEADER_SPREQUESTGUID'='78265f9f-40b3-b000-f2bb-2df685280534'
'RESPONSE_HTTP_HEADER_STRICT-TRANSPORT-SECURITY'='max-age=31536000'
'RESPONSE_HTTP_HEADER_TRANSFER-ENCODING'='chunked'
'RESPONSE_HTTP_HEADER_MS-CV'='n18meLNAALDyuy32hSgFNA.0'
'RESPONSE_HTTP_HEADER_CONTENT-TYPE'='application/xml;charset=utf-8'
'RESPONSE_HTTP_HEADER_P3P'='CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"'
'RESPONSE_HTTP_HEADER_X-FRAME-OPTIONS'='SAMEORIGIN'
'RESPONSE_HTTP_HEADER_X-IDCRL_AUTH_PARAMS_V1'='IDCRL Type="BPOSIDCRL", EndPoint="/sites/<sitecollection>/_vti_bin/idcrl.svc/", RootDomain="sharepoint.com", Policy="MBI"'
'RESPONSE_HTTP_HEADER_SERVER'='Microsoft-IIS/10.0'
'RESPONSE_HTTP_HEADER_REQUEST-ID'='78265f9f-40b3-b000-f2bb-2df685280534'
'RESPONSE_HTTP_HEADER_X-MS-INVOKEAPP'='1; RequireReadOnly'
'RESPONSE_HTTP_HEADER_X-CONTENT-TYPE-OPTIONS'='nosniff'
'RESPONSE_HTTP_HEADER_X-FORMS_BASED_AUTH_REQUIRED'='https://<mytenant>.sharepoint.com/_forms/default.aspx?ReturnUrl=/_layouts/15/error.aspx&Source=%2f_vti_bin%2fclient.svc%2fweb%3f%24select%3dTitle'
'RESPONSE_HTTP_STATUS'='403'
'RESPONSE_HTTP_HEADER_DATASERVICEVERSION'='3.0'
I also tried it with different HTTP Headers, by using cookies and by skip them. Nothing works from middleware but everything from my PC.
Patrick
You could try this way to get authentication:
https://www.c-sharpcorner.com/article/access-sharepoint-online-rest-api-via-postman-with-user-context/
I use some kind of middleware called "Lobster data". This is a software product to map data between different kind of systems. It's comparable to Microsoft BizTalk or others.
However this software uses some special prefix for HTTP header which I was not aware of. Thanks to their support team, I was able to overcome this issue.
Commonly, if you set a HTTP header, you simple use the name of the header you want to add like "content-type" or "authorization" and pass a value.
When using Lobster, you need to add "REQUEST_HTTP_HEADER_" as a prefix, so it needs to be "REQUEST_HTTP_HEADER_authorization" instead of just "authorization". Otherwise it will not send the data as a HTTP Header.
This is only true when using Lobster and not in general. I wasn't aware that they use this syntax.

CGI returns OK for 403

I wrote a simple script to serve custom HTTP error 403 page and I use the following code:
use CGI qw/:standard/;
print header(
'-Status' => 403,
'-Type' => 'text/html; charset=utf-8',
'-Cache-Control' => 'private, no-cache, no-store, must-revalidate, max-age=0',
'-Pragma' => 'no-cache');
...
print $html;
I expected system to return Forbidden status text automatically in HTTP header.
Unfortunately it returns 403 OK instead of 403 Forbidden. Text phrase is more likely added by browser.
Sure, I can explicitly add the status text using '-Status' => '403 Forbidden', but I would still like to know why isn't this done automatically, and why I am getting OK status instead...
Is there a way to force Perl to add default (English) status text for selected response code?
Chrome is the culprit here. You can verify by running your snippet on the command line, which outputs the following headers:
Status: 403
Pragma: no-cache
Cache-control: private, no-cache, no-store, must-revalidate, max-age=0
Content-Type: text/html; charset=utf-8
Notice the status is plain-old 403.
CGI.pm does not know about the reason phrases recommended by the HTTP spec. Nor should it: they are merely recommendations (not defaults), and you can change them to whatever you want without affecting the protocol (403 Go away anyone?). According to the standard, clients are not required to even look at the reason phrase.
So no, unless you modify CGI.pm, there is no way to force Perl to add a reason phrase. Even if you do provide a reason phrase, browsers can do what they wish with them (although most browsers will probably behave sanely).
I've been looking long time for this, and basically it's very simple:
see
https://serverfault.com/questions/121735/how-to-return-404-from-apache2-cgi-program
In sort:
change
use CGI qw/:standard/;
print header(
'-Status' => 403,
'-Type' => 'text/html; charset=utf-8',
...
to
print "Status: 403 Forbidden\r\n";
print "Content-Type: text/html\r\n\r\n";
print "<h1>403 Forbidden!</h1>";

Strange website behaviour after refresh

There's some strange behaviour on my website and I don't know how to fix it.
An important fact to start with: When i click on the address bar and hit enter the website is loaded very well BUT when i refresh it with F5 the nightmares happen. For example I use this jQuery script for centering a div:
jQuery.fn.center = function(parent) {
if (parent) {
parent = this.parent();
} else {
parent = window;
}
this.css({
"position": "fixed",
"top": ((($(parent).height() - this.outerHeight()) / 2) + $(parent).scrollTop() + "px"),
"left": ((($(parent).width() - this.outerWidth()) / 2) + $(parent).scrollLeft() + "px")
});
return this;
}
and after refresh the div disappears. I found out that it's because it's "top" attribute is assigned in a very strange way. After first entrance it's ok (it's centered) after second refresh its "top" attribute was set to 900px and after the third refresh it was 1100px.
The other thing is that I use this calendar script on my website: http://www.eyecon.ro/datepicker/ . I just assign it to block and everything works fine but after hitting F5 sometimes it gets doubled (double calendar is shown) and things like this. I thought it might happens because I use a form on the website and some javascript to handle it (modern browsers remember inputs' values after refresh) so I set autcomplete="off" on the whole form. Didn't fix the problem. What might be the reason of this?
How do you implemented the call of the functions ? Evrything after "doucment ready" ?
$(document).ready(function () {
// javascript code here
});
Ok I just found out some clue.
Ctrl + F5 helps and since it's about clearing the cache it might be it. But I STILL DON'T KNOW why this happens because when I look in the headers I see this:
HTTP/1.1 200 OK
Date: Fri, 12 Jul 2013 09:03:12 GMT
Server: Apache/2.4.3 (Win32) OpenSSL/1.0.1c PHP/5.4.7
X-Powered-By: PHP/5.4.7
**Cache-Control: no-cache**
X-Debug-Token: a4c0e3
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
So it looks like Cache shouldn't work? Why does it then?

How to make Fake HTTP response objects for testing in perl

I have written a perl script that feeds data into a web service.
I have some system tests for the perl script that check that I can interact with the webservice, and these work just fine, but I do not want to be running system tests when I make small changes - I want to run unit tests:
So far I have written a subclass of my importer that simply intercepts the web requests before it actually calls the URL in question and tests that all the inputs are of the right type and form, and this works fine in all cases except where the perl script needs to read the response for instructions, and then proceed to the next steps.
My problem is that I cannot fake a response object.
I've tried using HTTP::Response->new, but it keeps complaining about bad header arguments
How do I best FAKE a response object?
There is no need to mock the HTTP::Response object. They are easy to construct—at least as easy as mocking would be and less likely to introduce bugs into the tests. You need to read the documentation and not just guess at usage.
You can construct them in code, of course, but what I've done in the past more than once is just save the output of curl or a stringified request that was made against an application and parse it back into an object.
Try playing around with these–
use warnings;
use strict;
use HTTP::Response;
my $response = HTTP::Response->new(204);
print $response->as_string;
my $other = HTTP::Response->parse(join "", <DATA>);
print $other->decoded_content, $/;
__DATA__
HTTP/1.1 200 OK
Cache-Control: public, max-age=53
Content-Type: text/html; charset=utf-8
Expires: Wed, 06 Jul 2011 19:13:54 GMT
Last-Modified: Wed, 06 Jul 2011 19:12:54 GMT
Vary: *
Date: Wed, 06 Jul 2011 19:12:59 GMT
Content-Length: 198121
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Stack Overflow</title>
</head>
<body class="home-page">
<blockquote>O HAI!</blockquote>
</body>
</html>
You may be looking for mock objects - in this case a mock LWP object?
See Test::Mock::LWP on CPAN.
Its documentation shows usage like this:
use Test::Mock::LWP;
# Setup fake response content and code
$Mock_response->mock( content => sub { 'foo' } );
$Mock_resp->mock( code => sub { 201 } );
# Validate args passed to request constructor
is_deeply $Mock_request->new_args, \#expected_args;
# Validate request headers
is_deeply [ $Mock_req->next_call ],
[ 'header', [ 'Accept', 'text/plain' ] ];
# Special User Agent Behaviour
$Mock_ua->mock( request => sub { die 'foo' } );
If you search CPAN for Test::Mock, there are quite a few modules for mocking/faking objects for testing.

No output in Firebug when _redirect was called

The code (taken from SO):
// create the logger and log writer
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);
// get the wildfire channel
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
// create and set the HTTP response
$response = new Zend_Controller_Response_Http();
$channel->setResponse($response);
// create and set the HTTP request
$channel->setRequest(new Zend_Controller_Request_Http());
// record log messages
$logger->info('info message');
$logger->warn('warning message');
$logger->err('error message');
// insert the wildfire headers into the HTTP response
$channel->flush();
// send the HTTP response headers
$response->sendHeaders();
$this->_redirect('/login/success');
Apparently, all the messages won't appear if I use _redirect(), however, if I use something like
$this->getResponse()->setHeader('Refresh', '0; URL=/login/success');
it will work. So my question is:
What should I do to make sure the messages will appear in my Firebug Console (using _redirect())?
Update 1:
In the Net tab, I can see the messages are in the HEADER, but it's not appearing in my Firebug
Date Wed, 08 Dec 2010 03:42:15 GMT
Server Apache/2.2.16 (Unix) DAV/2 PHP/5.3.3
X-Powered-By PHP/5.3.3
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
X-Wf-Protocol-1 http://meta.wildfirehq.org/Protocol/JsonStream/0.2
X-Wf-1-Structure-1 http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1
X-Wf-1-Plugin-1 http://meta.firephp.org/Wildfire/Plugin/ZendFramework/FirePHP/1.6.2
X-Wf-1-1-1-1 156|[{"Type":"INFO","File":"\/home\/foo\/workspace\/php\/identiti\/application\/modules\/default\/controllers\/LoginController.php","Line":64},"info message"]|
X-Wf-1-1-1-2 159|[{"Type":"WARN","File":"\/home\/foo\/workspace\/php\/identiti\/application\/modules\/default\/controllers\/LoginController.php","Line":65},"warning message"]|
X-Wf-1-1-1-3 158|[{"Type":"ERROR","File":"\/home\/foo\/workspace\/php\/identiti\/application\/modules\/default\/controllers\/LoginController.php","Line":66},"error message"]|
Location /login/success
Content-Length 0
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type text/html
Update 2:
Apparently it's a bug, confirmed in FirePHP Official Forum. I'll wait untill there's a real fix before I answer this question.
Thanks for the detailed test case.
This is a bug in FirePHP Companion.
Working on a fix. Will let you know
when done (ETA Friday).
Thanks! Christoph
Does enabling the "Persist" option in the Firebug Console tab help?
This is the official answer from the author himself:
I have good and bad news. Logging during redirects works now for FirePHP 1.0 + FirePHP Companion. It will not work for the native Zend Framework implementation until early next year.
To get a working solution, please upgrade to FirePHP 1.0: http://upgrade.firephp.org/
Also see: http://www.christophdorn.com/Blog/2010/11/29/firephp-1-0-in-5-steps/
Instructions for logging during redirects:
http://reference.developercompanion.com/#/Tools/FirePHPCompanion/FAQ/#Redirect Messages
I would suggest using the FirePHP 1.0 library in addition to or instead of the ZF components. This will be much improved early next year.
Please let me know if you get this working.