How do I specify Origin Whitelist Options in Sinatra using Rack/Protection - sinatra

I have a web app, lets say http://web.example.com making a POST request to http://api.example.com. The api server is running the latest version of Sinatra with rack protection enabled. I am getting this error 'attack prevented by Rack::Protection::HttpOrigin'.
I can do something like this:
set :protection, :except => [:http_origin]
but I feel like I am just ignoring the actual problem.
I have tried to do this:
use Rack::Protection::HttpOrigin, :origin_whitelist => ['http://web.example.com']
but I still get the warning.
The request does not get rejected, but Sinatra clears my session see this post and I need the session_id.
Any help or examples on how to specify the option_whitelist for the HttpOrigin class would be greatly appreciated.

Pass your options as a hash to set :protection:
set :protection, :origin_whitelist => ['http://web.example.com']
Sinatra will then pass them through to Rack::Protection when setting it up.
I suspect the reason it is failing when you have use Rack::Protection::HttpOrigin, :origin_whitelist => ['http://web.example.com'] is that you still have protection enabled, so that you end up with two instances of HttpOrigin. You could try
set :protection, :except => [:http_origin]
use Rack::Protection::HttpOrigin, :origin_whitelist => ['http://web.example.com']
(i.e. have both the lines you’ve tried together), but I think the first solution is cleaner.

Related

Testing a JSON PUT request in mojolicious

I am creating test cases for my app developed using Mojolicious framework. I am testing the routes for appropriate responses for the REST calls that are made. I use JSON as a means of communication between the server and client. To test GET, POST and DELETE requests I use the following functions
GET : get_ok()POST: post_json_ok() DELETE: delete_ok()
but for PUT I am not able to use put_ok(). And example of my usage of put_ok() would be my $t = Test::Mojo->new;$t->put_ok('this/is/url/to/resource'=>{ "element" => "modified value"})->status_is(204)
I get a bad request status every time(400) and so the test fails. I use Test::Mojo for testing my application.
Additional information:
$t->put_ok('http://localhost:3000/application/instances/system/test'=>{"model" => "testing put"})->status_is(204);
This is the exact test for PUT request that is attempted. model is a property of resource test that is being attempted to be changed to testing put and the expected status response is 204.
The mapping to the controller is done by
$r->route('/application/instances/system/:id, id => qr/[A-Za-z0-9 ]+/ -> via('put')
->to(controller => 'system', action => 'update_sys');
This route calls the update_sys method in the system controller and that is how the resource is located.
Actually, after discussions with SRI on IRC, he pointed me to an example almost identical you your needs in the documentation.
# Test custom transaction
my $tx = $t->ua->build_json_tx('/user/99' => {name => 'sri'});
$tx->req->method('PUT');
$t->tx($t->ua->start($tx))
->status_is(200)
->json_is('/message' => 'User has been replaced.');
So this should work for you!
Postscript:
You might be interested to know that this discussion has brought some progress: the next release of Mojolicious (version 3.66) will now have a cleaner syntax for this purpose, the new request_ok method. The above example can then be rewritten as
my $tx = $t->ua->build_json_tx('/user/99' => {name => 'sri'});
$tx->req->method('PUT');
$t->request_ok($tx)
->status_is(200)
->json_is('/message' => 'User has been replaced.');
Can you share the definition of your route for 'this/is/url/to/resource' ? the server is returning 400, so it appears Mojo::Controller in your app does not understand what you are sending ...

Register new memer for vBulletin via Mobile API

I'm trying to use the vBulletin REST Mobile API to simply register.
The sourced are installed on my local machine and according the documentation https://www.vbulletin.com/forum/content.php/393-User-Registration-Process-Mobile-API
This procedure should not be so hard, especially without humanity and COPPA authentication.
However I've stacked!
The method definition describes "addnewmember" clear, so I've generated a test link, which should do the job.
https://www.vbulletin.com/forum/content.php/365-User-Related-Methods
The link is:
.../forum/api.php?&api_m=register_addmember&api_c=1&api_s=76ec9eec61e7fdfef2f3feee28d5f392&api_sig=8fe54313b333cc0fef4ddd8e398b5c80&api_v=6&agree=1&username=testuser&email=XXXXXX%40gmail.com&emailconfirm=XXXXX%40gmail.com&password=12345678&passwordconfirm=12345678
As a response I get: register_not_agreed
The Docs: register_not_agreed
The agree parameter should be set to 1.
Which is also clear - agree parameter was not there.
Here comes the funny part - In the API-Log I can see that the 'agree' parameter is correctly passed
*1 test_client Gast 13:23, 18.06.2012 register_addmember Array ( [api_m] => register_addmember [api_c] => 1 [api_s] => 76ec9eec61e7fdfef2f3feee28d5f392 [api_sig] => 8fe54313b333cc0fef4ddd8e398b5c80 [api_v] => 6 [agree] => 1 [username] => testuser [email] => ....*
Is there anybody with experience with the Mobile API that could help?
I don't know why it does not work with a pure GET call but I'm sure it will work (because I'm working on a vBulletin API client in Python and I did it this way) if you:
use GET parameters to send api_c, api_sm, api_m, and api_sig
use POST data for all the rest (username, email, agree, etc)

Setting cookies in mojolicious response

How do i set a cookie in mojolicious response and later read it from the request. I tried different ways but none of them set cookie on the response object.
tried these ways
$self->res->cookies({name => 'foo', value => 'bar'});
$self->res->headers->set_cookie('foo=bar');
$self->res->headers->cookie('foo=bar');
plz, help!!
thanks.
You can use the shortcut methods directly from the controller:
# Set
$self->cookie(foo => 'bar');
# Get
$self->cookie('foo');
http://mojolicio.us/perldoc/Mojolicious/Controller#cookie
However, if your intent is simply to store a value and retrieve it on subsequent requests, there's no need to set cookies directly. Mojolicious sessions use signed cookies by default, will handle the complexities of the cookies, and will verify that the values have not been changed by the client.
# Set
$self->session(foo => 'bar');
# Get
$self->session('foo');
http://mojolicio.us/perldoc/Mojolicious/Controller#session
If sessions are the best solution for you, make sure you set your app secret. Also, check out:
http://mojocasts.com/e4#Session

Session Management (Zend Framework specific)

I'm trying to get the rememberMe() function to remember users and retain sessions for months at a time.
I've read that if you pass a value through rememberMe() it will not work if the session has already been started. From the session_set_cookie_params() documentation in the PHP manual, "you need to call session_set_cookie_params() for every request and before session_start() is called."
By I am calling Zend_session::start() in my bootstrap as i thought I was supposed to. My problem is that rememberMe() doesn't seem to be working.
When I call session_get_cookie_params(); I get:
Array([lifetime] => 0 [path] => / [domain] => [secure] => httponly] =>)
Any thoughts?
I've solved the problem. sessions were being erased by another website on the same server which expires sessions every 24 minutes. To fix this I set the session.save_path to a new folder. I also set session.gc_maxlifetime and session.cookie_lifetime to be very large numbers.
problem solved!
Don't use the start() method. It should work fine if you are using MVC. The session_start must be called before any output is send and that's right before sending response (because of outputbuffering). The session is started automatically upon first Zend_Session_namespace usage.

How do I use and debug WWW::Mechanize?

I am very new to Perl and i am learning on the fly while i try to automate some projects for work. So far its has been a lot of fun.
I am working on generating a report for a customer. I can get this report from a web page i can access.
First i will need to fill a form with my user name, password and choose a server from a drop down list, and log in.
Second i need to click a link for the report section.
Third a need to fill a form to create the report.
Here is what i wrote so far:
my $mech = WWW::Mechanize->new();
my $url = 'http://X.X.X.X/Console/login/login.aspx';
$mech->get( $url );
$mech->submit_form(
form_number => 1,
fields =>{
'ctl00$ctl00$cphVeriCentre$cphLogin$txtUser' => 'someone',
'ctl00$ctl00$cphVeriCentre$cphLogin$txtPW' => '12345',
'ctl00$ctl00$cphVeriCentre$cphLogin$ddlServers' => 'Live',
button => 'Sign-In'
},
);
die unless ($mech->success);
$mech->dump_forms();
I dont understand why, but, after this i look at the what dump outputs and i see the code for the first login page, while i belive i should have reached the next page after my successful login.
Could there be something with a cookie that can effect me and the login attempt?
Anythings else i am doing wrong?
Appreciate you help,
Yaniv
This is several months after the fact, but I resolved the same issue based on a similar questions I asked. See Is it possible to automate postback from the client side? for more info.
I used Python's Mechanize instead or Perl, but the same principle applies.
Summarizing my earlier response:
ASP.NET pages need a hidden parameter called __EVENTTARGET in the form, which won't exist when you use mechanize normally.
When visited by a normal user, there is a __doPostBack('foo') function on these pages that gives the relevant value to __EVENTTARGET via a javascript onclick event on each of the links, but since mechanize doesn't use javascript you'll need to set these values yourself.
The python solution is below, but it shouldn't be too tough to adapt it to perl.
def add_event_target(form, target):
#Creates a new __EVENTTARGET control and adds the value specified
#.NET doesn't generate this in mechanize for some reason -- suspect maybe is
#normally generated by javascript or some useragent thing?
form.new_control('hidden','__EVENTTARGET',attrs = dict(name='__EVENTTARGET'))
form.set_all_readonly(False)
form["__EVENTTARGET"] = target
You can only mechanize stuff that you know. Before you write any more code, I suggest you use a tool like Firebug and inspect what is happening in your browser when you do this manually.
Of course there might be cookies that are used. Or maybe your forgot a hidden form parameter? Only you can tell.
EDIT:
WWW::Mechanize should take care of cookies without any further intervention.
You should always check whether the methods you called were successful. Does the first get() work?
It might be useful to take a look at the server logs to see what is actually requested and what HTTP status code is sent as a response.
If you are on Windows, use Fiddler to see what data is being sent when you perform this process manually, and then use Fiddler to compare it to the data captured when performed by your script.
In my experience, a web debugging proxy like Fiddler is more useful than Firebug when inspecting form posts.
I have found it very helpful to use Wireshark utility when writing web automation with WWW::Mechanize. It will help you in few ways:
Enable you realize whether your HTTP request was successful or not.
See the reason of failure on HTTP level.
Trace the exact data which you pass to the server and see what you receive back.
Just set an HTTP filter for the network traffic and start your Perl script.
The very short gist of aspx pages it that they hold all of the local session information within a couple of variables prefixed by "__" in the general aspxform. Usually this is a top level form and all form elements will be part of it, but I guess that can vary by implementation.
For the particular implementation I was dealing with I needed to worry about 2 of these state variables, specifically:
__VIEWSTATE
__EVENTVALIDATION.
Your goal is to make sure that these variables are submitted into the form you are submitting, since they might be part of that main form aspxform that I mentioned above, and you are probably submitting a different form than that.
When a browser loads up an aspx page a piece of javascript passes this session information along within the asp server/client interaction, but of course we don't have that luxury with perl mechanize, so you will need to manually post these yourself by adding the elements to the current form using mechanize.
In the case that I just solved I basically did this:
my $browser = WWW::Mechanize->new( );
# fetch the login page to get the initial session variables
my $login_page = 'http://www.example.com/login.aspx';
$response = $browser->get( $login_page);
# very short way to find the fields so you can add them to your post
$viewstate = ($browser->find_all_inputs( type => 'hidden', name => '__VIEWSTATE' ))[0]->value;
$validation = ($browser->find_all_inputs( type => 'hidden', name => '__EVENTVALIDATION' ))[0]->value;
# post back the formdata you need along with the session variables
$browser->post( $login_page, [ username => 'user', password => 'password, __VIEWSTATE => $viewstate, __EVENTVALIDATION => $validation ]);
# finally get back the content and make sure it looks right
print $response->content();