Redirecting requests form a catch-all controller in Zend Application without looping forever - zend-framework

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)

Related

.HttpContext.User is null after successful login from SAML Identity Provider?

Trying to retrofit an old webforms application.
Got my configuration working so that it's prompting for login and successfully redirecting back to the application. The folks that manage the IP can see the response is generated.
However in the callback to my application the User is null. I'm told if it's configured correctly it should be populated.
We have a custom IHttpModule and that is where I can see getting hit with the call to /Saml2/Acs with the User not populated. I think this may be expected as the handler for that is supposed to populate the User, I think? However the following call (the returnUrl configured in sustainsys.Saml2) still has no User and I don't see any sort of error or anything.
Anyone with experience have an idea how to debug this?
The call to /Saml2/Acs should be taken care of by the Sustainsys.Saml2.HttpModule. It will process the response and then call the SessionAuthenticationModule to set a cookie that preservers the User across calls.
To get some more information about what's happening in the library, you can assign an implementation of ILoggerAdapter to Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOPtions.Logger to get some logging output from the library.
My issue turned out to be that I had another authentication module loaded before SessionAuthenticationModule and Saml2AuthenticationModule in the web config.
The comment in the example was
Add these modules below any existing. The SessionAuthenticatioModule
must be loaded before the Saml2AuthenticationModule
However in my case with I had another authentication module involved that needed to go last.

How to configure ASP.NET Identity with Facebook login - strict redirect

In March of 2018 Facebook began requiring "Strict Mode" for redirect URIs. This means any redirect URI needs to be known in advance, and added to your app's profile (Valid OAuth Redirect URIs). The problem is when the redirect URI contains a dynamic parameter, like a state variable, guid, or user id, etc.
The answer I have found on many websites is that you can hold dynamic state in a "state" parameter. So if your allowed redirect uri is "www.example.com/signin" then this will also allow "www.example.com/signin?state=12344". However, this seems to be no longer allowed. The state parameter no longer seems to be ignored by this strict rule - it fails validation (there is a valid url checker on your facebook app settings page). To test this, I simply put "a.com" in the allow uri field, and "a.com?state=x" in the Redirect URI Validator, and it fails. Without the ?state-x it succeeds. What am I missing?
So I have two questions:
1) First, how to I find out what redirect url my app is actually sending to FB? I can't sniff my traffic since it's https (also required now by fb). I think I know what it is (https://www.example.com/signin-facebook?state=xxxxxx) but I can't be sure and there is no way to verify. The logic that calls FB is wrapped up in the MS Identity library.
2) Second, if it's the state parameter that is causing my login fails, is there any way to disable that in my ASP.NET Core app, or allow it in FB?
Just to clarify, here are two images showing that without the state parameter, the url is valid, but adding the state parameter makes it an invalid URL. Clearly the 'state' parameter is not being ignored by this strict rule checker, as many people have claimed. If I add the state param url to the list of allowed urls, it works but only with that exact state value, not with any different value.
The state parameter is dynamic to begin with (or at least it should be, because its original purpose is CSRF protection), so it is not taken into account when the URL is checked for a “strict” match to the one you have configured.
If you want to use
https://www.example.com/signin-facebook?state=xxxxxx
then configure
https://www.example.com/signin-facebook
as your Valid OAuth Redirect URI.
If you have other (static!) parameters besides the dynamic state, then those must be input into the field as well. You want to use
https://www.example.com/signin-facebook?action=foobar&state=xxxxxx
then the URL in your settings needs to be
https://www.example.com/signin-facebook?action=foobar
And since, as mentioned, the original purpose of this parameter is CSRF protection, it might still be a good idea to add a “random“ component to it, if the actual value you are trying to transport via it is “guessable”, or from a limited range of pre-defined values only.
In that case, I would probably go with an encoded JSON object as the parameter value -
state={"mystate":"foobar","random":8473628}
(Don’t forget to apply proper URL encoding, if your system doesn’t do that automatically.)

Dancer Hooks on a per-request method basis?

I'm working on a CRUD application using Dancer. One of the things I need to do is check a user is authorized to perform POST (create) and PUT (update) / DELETE (remove) operations.
I've read up on before hooks in the Dancer documentation, but have been unable to figure out the best way to do varying types of authorization.
For a POST operation, all I want to do is check that a valid API key has been submitted with the request, but for a PUT/DELETE operation, I want to check that the API key submitted matches the user who is attached to the record to be updated or deleted.
I understand how to do the logic behind checking the API keys, but I'm wondering if hooks (or something else) would allow me to call that logic without having to add the same boilerplate function call to every single PUT/POST/DELETE function on every route.
like I told the poster on IRC, I think a combination of https://metacpan.org/pod/Dancer#request (the Dancer request object) and its HTTP verbs querying things should do the trick. See for example: https://metacpan.org/pod/Dancer::Request#is_post .
I'm not sure if it's a very elegant solution, but I think it should work.
Here's another take on this issue, based on experience:
Since Dancer has not had the opportunity to parse your input parameters when the 'before' hook executes, you may not have a consistent way to read in your authentication credentials, if your application allows them to be provided in a variety of ways.
In particular, if you're using input parameters to pass a nonce to prevent CSRF attacks (which you should definitely consider!), you won't have a consistent way to obtain that nonce. You could do your own mini-parameter-parsing within 'before', but that could be messy too.
I ran into this problem when I worked on an application some time ago, and remember having to add the dreaded boilerplate authentication function to every PUT/POST/DELETE route. Then, if you're doing that, it becomes irrelevant to check request->is_post because you're already deciding whether to place the boilerplate authentication function within the route.
I haven't tried this yet, but it may be possible to handle the pre-requisite action in your Route base class, then pass upon success. This will leave your specific packages to handle the request as normal once your base class has verified authentication.
An action can choose not to serve the current request and ask Dancer to process the request with the next matching route. This is done with the pass keyword, like in the following example
get '/say/:word' => sub {
return pass if (params->{word} =~ /^\d+$/);
"I say a word: ".params->{word};
};
get '/say/:number' => sub {
"I say a number: ".params->{number};
};

EmberAuth actionRedirectable Module prevents use from accessing a resource by URL

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.

An explanation of the Zend Redirector Action Helper

Is there a comprehensive explanation of how the Zend Redirector Action Helper works? I've read the reference guide, but am still not 100% clear. For example:
Apparently the goToSimple() is more like a forward(), than a redirect. Does this mean that it won't send a redirect message back to the browser?
If I want to send a redirect message back to the browser, which Redirector method should I be using?
Is there a way to get the forward() type of behaviour, without re-executing the init() method of Action Helpers?
This problem cropped up when I was implementing an ACL. I have an ACL Action Helper and its init() method adds the role 'current'. When I use the redirector's goToSimple() I get an error saying that the role is already registered. I can use if (!$acl->hasRole('current')) however I think it would be preferable not to be re-executing the helper's init() in the first place.
Not too comprehensive just a few quick notes about the redirector.
The redirector does a little bit more than a regular PHP redirect which you would use with header('Location: www.domain.com/new/location') in your script--following by an exit().
If you look at Zend_Controller_Action_Helper_Redirector it ultimately does exactly the same; if $_exit==true (default) everything leads to redirectAndExit() which calls header() and ends with an exit() call. However it terminates the framework properly, mainly the session if any.
The redirector does not forward internally it sends a default 302 code back unless you have set another code with setCode().
Methods gotoRoute() and gotoSimple() assemble the destination URL for you and call redirectAndExit() but only if $_exit==true. Or you can use their brethren gotoRouteAndExit() and gotoSimpleAndExit() which will exit immediately. The gotoSimple methods pass on to setGotoSimple which uses some methods to assemble the URL for you.
In your case I can only assume that the setGotoSimple method and one of the methods in it call the destination controller and fire up the init() method; however, only for checking but not forwarding.