Can't resolve route - basic login - neoscms

so I'm currently looking into Neos CMS and wanted to create a very basic login logic. [for practice]
I basically followed: http://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/Security.html#authentication
My Code: [neos/ being the root dir]
Routes: [neos/Configuration/Routes.yaml] Note that's what I added in the beginning of the file, not the whole content of the file.
-
name: 'Authentication'
uriPattern: 'authenticate'
defaults:
'#package': 'VMP.Auth'
'#controller': 'Authentication'
'#action': 'authenticate'
AuthenticationController.php [neos/Packages/Plugins/VMP.Auth/Classes/VMP/Auth/Controller/]
<?php
namespace VMP\Auth\Controller;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Mvc\ActionRequest;
use TYPO3\Flow\Security\Authentication\Controller\AbstractAuthenticationController;
class AuthenticationController extends AbstractAuthenticationController {
/**
* Displays a login form
*
* #return void
*/
public function indexAction() {
}
/**
* Will be triggered upon successful authentication
*
* #param ActionRequest $originalRequest The request that was intercepted by the security framework, NULL if there was none
* #return string
*/
protected function onAuthenticationSuccess(ActionRequest $originalRequest = NULL) {
if ($originalRequest !== NULL) {
$this->redirectToRequest($originalRequest);
}
$this->redirect('someDefaultActionAfterLogin');
}
/**
* Logs all active tokens out and redirects the user to the login form
*
* #return void
*/
public function logoutAction() {
parent::logoutAction();
$this->addFlashMessage('Logout successful');
$this->redirect('index');
}
public function fooAction() {
print "lol";
}
}
NodeTypes.yaml [neos/Packages/Plugins/VMP.Auth/Configuration/]
'VMP.Auth:Plugin':
superTypes:
'TYPO3.Neos:Plugin': TRUE
ui:
label: 'Auth Login Form'
group: 'plugins'
Policy.yaml [neos/Packages/Plugins/VMP.Auth/Configuration/]
privilegeTargets:
'TYPO3\Flow\Security\Authorization\Privilege\Method\MethodPrivilege':
'VMP.Auth:Plugin':
matcher: 'method(TYPO3\Flow\Security\Authentication\Controller\AbstractAuthenticationController->(?!initialize).*Action()) || method(VMP\Auth\Controller\AuthenticationController->(?!initialize).*Action())'
roles:
'TYPO3.Flow:Everybody':
privileges:
-
# Grant any user access to the FrontendLoginLoginForm plugin
privilegeTarget: 'VMP.Auth:Plugin'
permission: GRANT
Settings.yaml [neos/Packages/Plugins/VMP.Auth/Configuration/]
TYPO3:
Neos:
typoScript:
autoInclude:
'VMP.Auth': TRUE
Flow:
security:
authentication:
providers:
'AuthAuthenticationProvider':
provider: 'PersistedUsernamePasswordProvider'
Index.html [neos/Packages/Plugins/VMP.Auth/Resources/Private/Templates/Authentication/]
<form action="authenticate" method="post">
<input type="text"
name="__authentication[TYPO3][Flow][Security][Authentication][Token][UsernamePassword][username]" />
<input type="password" name="__authentication[TYPO3][Flow][Security][Authentication][Token][UsernamePassword][password]" />
<input type="submit" value="Login" />
</form>
**Root.ts2 [neos/Packages/Plugins/VMP.Auth/Resources/TypoScript/]
prototype(VMP.Auth:Plugin) < prototype(TYPO3.Neos:Plugin)
prototype(VMP.Auth:Plugin) {
package = 'VMP.Auth'
controller = 'Authentication'
action = 'index'
}
Problem:
if I call: www.neos.dev/authenticate I get:
Validation failed while trying to call VMP\Auth\Controller\AuthenticationController->authenticateAction().
So I think, the route itself does work. I now added the login form of my VMP.Auth Plugin to some page and logged in (with an existing user). The login form uses /authenticate as its action, but now I get the following error:
Page Not Found
Sorry, the page you requested was not found.
#1301610453: Could not resolve a route and its corresponding URI for the given parameters. This may be due to referring to a not existing package / controller / action while building a link or URI. Refer to log and check the backtrace for more details.
I don't really know what's the issue here. I guess my routing is wrong but I can't see it.

your onAuthenticationSuccess method has:
$this->redirect('someDefaultActionAfterLogin');
which is probably triggered (correctly) now. That tries to redirect to an action someDefaultActionAfterLoginAction in your AuthenticationController but this action does not exist. For starters try
$this->redirectToUri('/') to just have a redirect to the homepage.

Related

Failed CSRF check! in postman when trying POST method (API with slim 3)

I am working with a Slim 3 project and I installed the CSRF package ("slim/csrf": "^0.8.2",)
In order to make POSTs request I am using postman. When sending the action I get the following error:
Failed CSRF check!
Here are my API routes (in this case, focus on the POST route):
<?php
/* RESTful endpoints or routes */
use App\Controllers\api\users\UserController;
$app->group('/api',function () use ($app){
$app->group('/users', function () {
$this->get('', UserController::class.':index');
$this->get('/{id}', UserController::class.':show');
$this->post('', UserController::class.':store');
});
});
Here is the controller supposed to get the info from the POST request where I get the error:
//Save a user via API
public function store($request,$response,$args)
{
//todo: validation!
var_dump($request->getParams());//todo: CSRF check failed!
die();
}
Here is where I registered the CSRF component:
//Register the CSRF Component
$container['csrf'] = function ($container){
return new \Slim\Csrf\Guard();
};
I tried this solution: https://stackoverflow.com/a/48266488/1883256 but it didn't work.
Is there any workaround to make it work? How do I prevent the CSRF to run on my API routes?
* Solved *
As Zamrony P. Juhara suggested, I decided to apply CSRF to the web routes except for the APIs routes.
Grouping all my web routes:
$app->group('',function ()use($app,$container){
/* ******* H O M E ********** */
require __DIR__ . '/web/home/home.php';
/* ********** T O P I C s ********** */
require __DIR__ . '/web/topics/topics.php';
/* ********** C O N T A C T *********** */
require __DIR__ . '/web/contact/contact.php';
/* And so on and etcetera ....*/
/* ********************************************************************************* */
})->add($container->get('csrf'));//Adding CSRF protection only for web routes
And, for example, inside the topics.php routes file I have:
$app->group('/topics',function(){
$this->get('',TopicController::class.':index');
$this->get('/{id}',TopicController::class.':show')->setName('topics.show');
});
And as for the API routes, they stay the same.
Finally, inside my container I commented the following:
//$app->add($container->get('csrf')); //I've commented this line in order to add CSRF for specific routes (all except APIs ones)
You need to make sure that you add Slim\Csrf\Guard middleware to route or application (if you want to apply csrf for all routes). For example
To apply csrf middleware to all routes
$csrf = $container->csrf;
$app->add($csrf);
or to apply for certain routes only
$csrf = $container->csrf;
$app->group('/api',function () use ($app, $csrf){
$app->group('/users', function () {
$this->get('', UserController::class.':index')
->add($csrf);
$this->get('/{id}', UserController::class.':show');
$this->post('', UserController::class.':store')
->add($csrf);
});
});
You also need to make sure that there are Csrf token name/value data passed with request. When you use Postman, you need to find a way to obtain token name key/value pair before execute POST.
Following code is excerpt from Slim Csrf Readme.
// CSRF token name and value
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);
// Render HTML form which POSTs to /bar with two hidden input fields for the
// name and value:
// <input type="hidden" name="<?= $nameKey ?>" value="<?= $name ?>">
// <input type="hidden" name="<?= $valueKey ?>" value="<?= $value ?>">
Read Slim Csrf Readme for more information.

Symfony2 - Form submit does not work depending on a route of page

So I have this route:
/**
* #Route("/", name="homepage")
*
* #param Request $request
*
* #return Response
*/
public function indexAction(Request $request)
{
// ...
In this page is a correct form that was working some time ago.
{{ form_start(company_sign_up_form, {'action': path('homepage', { 'sign_up': 'company' }) }) }}
Here sign_up is a parameter that I am passing through the url.
Example: http://localhost/?sign_up=company
When I am submitting form I am redirected to the page without this sign_up parameter and both $form->isSubmitted() and $form->isValid() are giving me false.
But when I change the route from #Route("/", name="homepage") to #Route("/something", name="homepage") the submit is working just fine.
The only similar route that could conflict is the dynamic one:
/**
* #Route("/{page}", name="public", requirements={"page": "about|programs|contacts"})
*
* #param Request $request
* #param $page
*
* #return Response
*/
public function publicAction(Request $request, $page)
{
I tried changing this route to different, but it does not fix my issue.
Does anyone know the problem, why my form is not submitting properly with current route?
UPDATE
So I overcame the issue by modifying the route my form is in and refers to.
/**
* #Route("/{page}", name="homepage", defaults={"page": ""}, requirements={"page": "|home"})
*
* #param Request $request
*
* #return Response
*/
public function indexAction(Request $request)
{
So in this case I can access my homepage by http://localhost/ and http://localhost/home so if I set form action to /home, my form is submitted successfully.
Anyway, this is not the solution or answer, I leave it as it is and wait for better solution.
In the end problem was caused by login form. I had to modify check_path of each area that login logic would not be executed in same page as other forms.
main:
pattern: ^
anonymous: ~
provider: main
context: primary_auth
form_login:
login_path: /
check_path: /login_check
default_target_path: /authorization
logout:
path: /logout
target: homepage
remember_me:
secret: '%secret%'
lifetime: 31536000

HWIOAuthBundle - FOSUserBundle - Symfony 2 - Redirect to custom path after login with facebook

Reflected the following problem after the user login with the Facebook account: that is redirected to the following route /#_=_
How can I redirect it to this route instead: / Or to more to this /# ?
On the client side, I use the backbone.
Taking #Prynz's idea, we can get further and create a "redirect to page user comes from" this way:
1) In your firewall, take care to remove the following lines:
# security.yml
# ...
logout: true
logout:
path: /logout
target: /
As we will implment the logout ourselves to avoid redirecting to the specified target.
2) Add #Prynz's solution to your security.yml (or config.yml depending on your implementation)
oauth:
resource_owners:
google: "/login/check-google"
facebook: "/login/check-facebook"
twitter: "/login/check-twitter"
sensio_connect: "/login/check-sensio-connect"
login_path: /login
failure_path: /login
default_target_path: /welcome # THIS LINE CONTRIBUTES TO THE MAGIC
oauth_user_provider:
service: app.oauth_user_provider
3) In your routing, add a new controller (here, LoginController) before HWIO's imports:
fuz_app_login:
resource: "#FuzAppBundle/Controller/LoginController.php"
type: annotation
prefix: /
4) Create the corresponding controller:
<?php
namespace Fuz\AppBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
class LoginController
{
/**
* #Route("/login", name="login")
* #Method({"GET"})
*/
public function loginAction(Request $request)
{
if ($this->getUser())
{
// already-logged user accessed /login
return $this->redirect($request->headers->get('referer'));
}
else
{
// redirect to the login page
return $this->forward('HWIOAuthBundle:Connect:connect');
}
}
/**
* #Route("/logout", name="logout")
* #Method({"GET"})
*/
public function logoutAction(Request $request)
{
// we do a manual logout just to redirect the user to where he comes from
$this->container->get('security.context')->setToken(null);
return $this->redirect($request->headers->get('referer'));
}
/**
* #Route("/connect/{service}", name="connect")
* #Method({"GET"})
*/
public function connectAction(Request $request, $service)
{
// we overwrite this route to store user's referer in the session
$this->get('session')->set('referer', $request->headers->get('referer'));
return $this->forward('HWIOAuthBundle:Connect:redirectToService', array('service' => $service));
}
/**
* #Route("/welcome", name="welcome")
* #Method({"GET"})
*/
public function welcomeAction()
{
// on login success, we're redirected to this route...
// time to use the referer we previously stored.
$referer = $this->get('session')->get('referer');
if (is_null($referer))
{
return new RedirectResponse($this->generateUrl('home'));
}
return new RedirectResponse($referer);
}
}
5) relax.
You simply add default_target_path: /whatever/path/you/want to the oauth section under the firewall setup
oauth:
resource_owners:
facebook: '/login/check-facebook'
google: '/login/check-google'
windows: '/login/check-windows'
twitter: '/login/check-twitter'
login_path: /login
failure_path: /login
default_target_path: /whatever/path/you/want
Have a look at https://github.com/hwi/HWIOAuthBundle/issues/89
Redirect using javascript. Add following to the page.
<script>
// Handle facebook callback
if (window.location.hash && window.location.hash == '#_=_') {
window.location.hash = '';
}
</script>
If you want, you can redirect the users to the current page doing this way:
Add in your config.yml
hwi_oauth.target_path_parameter: "target_path"
In your view append the urls with:
&target_path=...
remember you can take the current route name with
app.request.get('_route')

FOSFacebookBundle does not call custom provider

I'm facing big issue while implementing FOSFacebookBundle.
I followed the docs and have following situation:
* when user clicks login a popup appears
* after user grants permission to the app, FB button is being changed (to Logout)
However, my custom provider is not called (only a constructor is called) - yes, I use a noobish debug method (creating empty files with the name of the class method :-)).
Anybody has any suggestion why? Any tips?
Edit
After some time of trying to solve that issue, I feel I'm lost.
Once again, here's my configuration:
app/config/config.yml:
fos_facebook:
file: %kernel.root_dir%/../vendor/facebook/src/base_facebook.php
alias: facebook
app_id: xxx
secret: xxx
cookie: true
permissions: [email, user_location]
app/config/routing.yml:
_security_login:
pattern: /login
defaults: { _controller: TestBundle:Main:login }
_security_check:
pattern: /login_check
defaults: { _controller: TestBundle:Main:loginCheck }
_security_logout:
pattern: /logout
defaults: { _controller: TestBundle:Main:logout }
app/config/security.yml
security:
factories:
-"%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
providers:
my_fos_facebook_provider:
id: my.facebook.user
fos_userbundle:
id: fos_user.user_manager
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
login_path: /login
check_path: /login_check
logout: true
anonymous: true
public:
pattern: ^/.*
fos_facebook:
app_url: "http://www.facebook.com/apps/application.php?id=xxx"
server_url: "http://symfonytest.com.dev/app_dev.php/"
login_path: /login
check_path: /login_check
provider: my_fos_facebook_provider
default_target_path: /
anonymous: true
logout: true
I'm also implementing code into twig template as shown in docs (also implemented snippet from #Matt).
I have the same workflow as you and my custom user provider is called correctly and everything is working fine.
The first thing that you need to check is: do you have a JavaScript script that redirects the user to the login_check route after it has successfully login into Facebook via the popup? This is important because calling the login_check route after a valid authentication will trigger the security mechanism of Symfony2 that will call the FOSFacebookBundle special security code that will then call your own custom user provider. I think you may be just missing this small piece.
Here the pieces of JavaScript code required to make it work (using jQuery):
$(document).ready(function() {
Core.facebookInitialize();
});
var Core = {
/**
* Initialize facebook related things. This function will subscribe to the auth.login
* facebook event. When the event is raised, the function will redirect the user to
* the login check path.
*/
facebookInitialize = function() {
FB.Event.subscribe('auth.login', function(response) {
Core.performLoginCheck();
});
};
/**
* Redirect user to the login check path.
*/
performLoginCheck = function() {
window.location = "http://localhost/app_dev.php/login_check";
}
}
I put here my security.yml just to help you check for differences with your own file:
security:
factories:
- "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
providers:
acme.facebook_provider:
# This is our custom user provider service id. It is defined in config.yml under services
id: acme.user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
public:
pattern: ^/
fos_facebook:
app_url: "http://www.facebook.com/apps/application.php?id=FACEBOOK_APP_ID"
server_url: "http://localhost/app_dev.php/"
default_target_path: /
login_path: /login
check_path: /login_check
provider: acme.facebook_provider
anonymous: true
logout: true
And my service definition for the custom user provider we use:
services:
acme.user_provider:
class: Application\AcmeBundle\Security\User\Provider\UserProvider
arguments:
facebook: "#fos_facebook.api"
entityManager: "#doctrine.orm.entity_manager"
validator: "#validator"
You also need to create a new route for the /login_check, /login and /logout paths. Those route will be hooked by Symfony2 for the security process. Here an example of the implementation of the actions in a controller called MainController in my cases:
<?php
namespace Application\AcmeBundle\Controller;
use ...;
class MainController extends Controller
{
/**
* This action is responsible of displaying the necessary informations for
* a user to perform login. In our case, this will be a button to connect
* to the facebook API.
*
* Important notice: This will be called ONLY when there is a problem with
* the login_check or by providing the link directly to the user.
*
* #Route("/{_locale}/login", name = "_security_login", defaults = {"_locale" = "en"})
*/
public function loginAction()
{
if ($this->request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $this->request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $this->request->getSession()->get(SecurityContext::AUTHENTICATION_ERROR);
}
return $this->render('AcmeBundle:Main:login.html.twig', array(
'error' => $error
));
}
/**
* This action is responsible of checking if the credentials of the user
* are valid. This will not be called because this will be intercepted by the
* security component of Symfony.
*
* #Route("/{_locale}/login_check", name = "_security_check", defaults = {"_locale" = "en"})
*/
public function loginCheckAction()
{
// Call intercepted by the Security Component of Symfony
}
/**
* This action is responsible of login out a user from the site. This will
* not be called because this will be intercepted by the security component
* of Symfony.
*
* #Route("/{_locale}/logout", name = "_security_logout", defaults = {"_locale" = "en"})
*/
public function logoutAction()
{
return $this->redirect('index');
}
}
Hope this help, if you have more questions or I misunderstand something from your problem, don't hesitate to leave a comment.
Regards,
Matt

Zend Framework: How to redirect to original url after login?

I'm trying to implement a login system that will be smart enough to redirect a user back to the page they were on before they decided (or were forced to) go to the login page.
I know this seems like a similar question to this one, and this one, but they do not address both of my scenarios.
There are two scenarios here:
User specifically decides to go to login page:
<a href="<?php echo $this->url(array(
'controller'=>'auth',
'action'=>'login'), 'default', true); ?>">Log In</a>
User is redirected because they tried to access protected content:
if (!Zend_Auth::getInstance()->hasIdentity()) {
$this->_helper->redirector('login', 'auth');
}
How can I implement a solution for this without displaying the "redirect to" url in the address bar?
Save the destination URL in the session. I guess you have some kind of access pre-dispatch plug-in. Do it there. And then, in the login form handler, check for the destination URL in the session, and redirect to it after a successful authentication.
Sample code from my project:
class Your_Application_Plugin_Access extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
foreach (self::current_roles() as $role) {
if (
Zend_Registry::get('bootstrap')->siteacl->is_allowed(
$role,
new Site_Action_UriPath($request->getPathInfo())
)
) return; // Allowed
}
$this->not_allowed($request);
}
private function not_allowed(Zend_Controller_Request_Abstract $request) {
$destination_url = $request->getPathInfo();
// If the user is authenticted, but the page is denied for his role, show 403
// else,
// save $destination_url to session
// redirect to login page, with $destination_url saved:
$request
->setPathInfo('/login')
->setModuleName('default')
->setControllerName('login')
->setActionName('index')
->setDispatched(false);
}
...
}
Here, current_roles() always contains 'guest', which is unauthenticated user, for which Zend_Auth::hasIdentity() is false.