I am trying to configure a classic Sinatra 2.0.8.1 app ("www.example.com") to use Rack::Protection, and especially Rack::Protection::AuthenticityToken, on some but not all routes.
Internal forms (within the app) work fine. Each form has a hidden CSRF authenticity token, so the forms in the app can POST data to routes in the app.
However I cannot find any documentation how to EXCEPT or SKIP AuthenticityToken for certain routes so that external apps can POST data to this app.
In this case we have a few routes to which two of our other apps ('foo.example.com' and 'bar.example.com') POST data to. But when we implemented Rack::Protection::AuthenticityToken all of those routes now return a 403 when posted to.
I've tried a variety of things such as permitted_origins and origin_whitelist as shown below, but no external app can POST data to the Sinatra app unless I disable Rack::Protection::AuthenticityToken for the entire app.
# foo.example.com
# doesnt work:
require 'rack/protection'
use Rack::Protection, permitted_origins: ["https://foo.example.com", "https://bar.example.com"]
set :protection, :origin_whitelist => ['https://foo.example.com', 'https://bar.example.com'], except: [:remote_token, :frame_options, :path_traversal]
use Rack::Protection::AuthenticityToken
use Rack::Protection::RemoteReferrer
Surely there is some mechanism for "omitting" the requirement for a CSRF token on certain routes, such as api routes that receive POSTed data?
Although the solution makes me feel dirty, here's what worked:
put all routes in their own file/class (kind of like controllers in Rails)
the (api) routes that I wanted to NOT use a CSRF token, I use THAT class file before I do the Rack protection initializations.
The classes containing the (normal) routes I DO want to protect from CSRF gets use after the Rackprotection initialization.
use Rack::Protection
set :protection, except: [:path_traversal]
# FIRST LOAD ROUTES *NOT* PROTECTED BY Rack::Protection::AuthenticityToken
use ApplicationController
use ApipostController # external POST routes to omit
# NOW enable the AuthenticityToken protection
Rack::Protection::AuthenticityToken
use Rack::Protection::AuthenticityToken
use Rack::Protection::RemoteReferrer
# now LOAD NORMAL ROUTES TO BE PROTECTED BY Rack::Protection::AuthenticityToken
use FooController
use BarController
Related
I'm developer my first symfony (3) app. it is a REST service publicly accessible.
I'm doing this using FOSRestBundle.
I'll have to ad some admin forms soon or later, and I'll probably want to create them directly (without passing by the extra work of consuming my own web services)
I wonder how to handle the CSRF token in this case. I see different solutions:
globally deactivate the CSRF token : I don't want to do this
create two set of forms, one with the token activated : form my admin forms, the other one for the REST API. => in this case, the rest API can't have a fallback _format=html
find a way to give the api consumer an auth, with an API_GROUP, and disable the token for this group
it seem to me the best solution, but I don't know how to do it transparently, without affecting the auth of my future admin, and without needing to give credentials in the REST request.
use an event listener in order to hack symfony's auth mechanism and give an auth if a call is made to the REST API (all but _format=html)
Which one of this (or other) solution seem the best to you, and how would you code it?
I found a way, perhaps not the best one, but it works :
$_format = $request->attributes->get('_format');
if ('html' == $_format) {
$form = $this->createForm(ItopInstanceUserType::class, $itopInstanceUser);
} else {
$form = $this->createForm(ItopInstanceUserType::class, $itopInstanceUser, ['csrf_protection' => false]);
}
For me, forget CSRF token managed by yourself, check subjects like Oauth authentication.
Take a look here: https://github.com/FriendsOfSymfony/FOSOAuthServerBundle/blob/master/Resources/doc/index.md
FOSOAuthServerBundle works perfectly with FOSRestBundle.
I am creating api for mobile app in laravel 5.2 version but now I am facing one problem. Problem is that in my routes.php I am created routes for my website. Now my question is if I start creating api for mobile for that I have to create new routes for mobile api Or I can use same routes for RESTapi also?
In Laravel 5.2 I have to add any webservices libraries or not? If yes, Please suggest me how to use RESTapi in Laravel 5.2? Please help.
My routes.php
Route::auth();
Route::get('/', 'Auth\AuthController#login');
Route::get('admin/users', 'UserController#getUsers');
Route::get('admin/users/add', 'UserController#addUser');
If your routes an their inside logic returns json response, Its not necessary to create new routes, But if your routes does not returns json response, you must write new routes.
For having better APIs, json-hal, jsend or json-api conventions may help you.
Your api routes can coexist with your regular web routes. It's customary, however, to separate them, typically by a subdomain (https://api.yoursite.com), or at least a path (https://yoursite.com/api/v1).
Also, api version number is often included, as in my last example.
As for a package to develop apis in Laravel, have a look at Dingo. It's very complete, provides its own router, versioning, security, etc.
You have different middleware in laravel. By default you should have "web" middleware activated. It is either directly in your routes.php, in your controler constructor OR in the RouteServiceProvider.php
You wouldn't use web middleware for an api / restful service, therefore you should use another middleware ( e.g. "api" middleware which throttles requests to only allow max. 60 requets per minute etc. )
Typically you group your api requests
Route::group(['prefix' => 'api/v1'], function()
{
...
}
to strictly divide them from your application. You can then also easy change to v2 for example if you plan many releases
Update
if your api logic follows your business logic then you could aswell just watch for ajax calls and return json
public function index(Request $request) {
// do stuff here
if($request->ajax()) {
// return json
}
// return view
}
I've created the blog from blog tutorial, and I would to protect articles list, but I want that this be accesible across REST, I've activated json extensions.
All works well. I can add and retrieve list, but now I want to deny index and add from web and only be accesible from .json to public.
I tried with
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('index.json');
}
But this obviously doesn't work. All webpage is login protected as is in tutorial. Web services should be accesible to Android App (code is ready and working).
Thank you!
Of course that doesn't work, the allow() methods expects valid method names, and that's all the authentication component cares about, method/action names, it doesn't matter how the action was requested.
What you are trying to do requires you to check the type of the request, and based on the results, allow the actions. Checking the request type can be done using Request::is().
See Cookbook > Request & Response Objects > Checking Request Conditions
So it might be as simple as
if ($this->request->is('json')) {
$this->Auth->allow(['index', 'add']);
}
I have the following Auth object in my app:
App.Auth = Ember.Auth.create
signInEndPoint: '/users/sign_in'
signOutEndPoint: '/users/sign_out'
tokenKey: 'auth_token'
tokenIdKey: 'user_id'
userModel: 'App.User'
modules: ['emberModel', 'rememberable', 'actionRedirectable']
actionRedirectable:
signInRoute: 'home'
signOutRoute: 'login'
rememberable:
tokenKey: 'remember_token'
period: 7
autoRecall: true
Everything with authentication is working great. The problem I'm seeing now, though, is that when a user attempts to access, say, 'mydomain.com/#/articles/12' and has a valid remember token, accessing the application is tantamoun to starting a new boot of the application. The user is signed in via remember token, and actionRedirectable takes over and takes the user to HomeRoute instead of going to the requested resource.
I feel like I could get around this by manually transitioning the routes in the relvant login/logout controllers, but I wonder if there's a baked in way of solving this in EmberAuth?
ember-auth dev here.
This looks like a known issue. Try the fix in this comment from github issue #69.
In short, module order does matter. actionRedirectable needs to register the route (probably the article route in your case), before rememberable signs in the user and requests a redirect. Otherwise it would have nowhere to redirect to, and falls back to your home route as specified.
There have already been requests of fixing this unexpected behavior, but I haven't been able to find a fix yet - sorry.
There are plenty of related posts to what I'm asking, but after some lengthy searches couldn't quite find what I was looking for, my apologies if it exists somewhere.
My goal -- ALL requests to my Zend App must go through a preDispatch plugin, then pass to a custom Auth controller that will decide whether existing auth credentials are sufficient for the requested operation. 'Sufficient' depends on the logic of the app, hence why I want to do this at the controller+model level. If they suffice, they send the original request along to the specified controller+action, if not they default to a 'get lost' action.
At present I'm using an auth custom plugin set in the preDispatch to simply check for POST'ed auth credentials (if we are logging in), then in all cases the plugin stores the original request and redirects everyone (auth'd or not) to my auth controller, a-la:
$request->setModuleName('default')
->setControllerName('auth')
->setActionName('check')
->setParam('oreq',$request->getParams());
My problem/question is that within my auth->check action, how should I perform the redirect after a decision is made? If I use:
$this->_helper->redirector($or['action'], $oreq['controller']);
then I obviously get an infinite loop as these requests pass through the preDispatch plugin again. Sure I could pass something with the redirect so that the Auth plugin ignores such requests, but this is clearly a security hole. I had thought about maybe generating and storing an md5 hash, storing it to session and passing that as an escape param, but that seems a little sketchy.
Any better ideas out there? Perhaps a redirect method that does not go through the standard predispatch routine in Zend App? Thanks in advance!
This is not how it is done usually in Zend Framework. Not all requests go to a common place and gets redirected to the original requested place authentication.
For access control, use Zend_Acl. Through that, you could easily determine whether the current user has the necessary auth to access the content, else redirect to 'get lost' action.
If you are still adamant on using your technique, use _forward method instead of redirect method.
Since _forward is an internal redirect, you could pass additional arguments and check that in preDispath to avoid a loop.
$this->_forward($action, $controller, $module, $params)