TYPO3 9.5 Extbase How redirect a call of showAction with a invalide object to a custom page (not 404!) - typo3

I want to redirect a call of a showAction with an invalid uid to a custom page. How can I do this with TYPO3 9 when routing and a 404 handling is active? At moment I always end at the 404 because the page is not found..
Where should I attack?
checking plugin settings like throwPageNotFoundExceptionIfActionCantBeResolved? ignore param validation? overwrite errorAction or callActionMethod? write a custom global 404 handling? overwrite routing?
routing + error handling config:
...
type: Extbase
extension: ext
plugin: Pi1
routes:
-
routePath: '/{object}'
_controller: 'object::show'
_arguments:
object: object
defaultController: 'object::list'
defaults:
page: '0'
requirements:
object: '^[0-9].*$'
page: \d+
aspects:
object:
type: PersistedAliasMapper
tableName: tx_ext_domain_model_object
routeFieldName: uid
page:
type: StaticRangeMapper
start: '1'
end: '100'
...
errorHandling:
-
errorCode: '404'
errorHandler: Page
errorContentSource: 't3://page?uid=174'

Ok, the best way is to overwrite the TYPO3-Errorhandling..
config.yaml
errorHandling:
-
errorCode: '404'
errorHandler: PHP
errorPhpClassFQCN: My\secret\namespace\Error\ErrorHandling
ErrorHandling.php
namespace My\secret\namespace\Error;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface;
use TYPO3\CMS\Core\Http\RedirectResponse;
class ErrorHandling implements PageErrorHandlerInterface{
/**
* #param ServerRequestInterface $request
* #param string $message
* #param array $reasons
* #return ResponseInterface
*/
public function handlePageError(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface{
if (strpos($request->getRequestTarget(), '/page-where-i-want-my-special-404') !== false) {
return new RedirectResponse('/my-custom-404', 404);
}
return new RedirectResponse('/404', 404);
}
}

First of all, custom error handling is an easy way to solve the problem. Given solution by Kroff works fine.
But, it is just working in case of pages with one language. And it is not really useful to add a static path in the comparison (due to possibly changing page slugs).
Has anyone found a solution to check the called page id? Or even better add a default route directly in the route enhancers configuration?
By the way, if you want to keep the typed in url and still show the 404 page (default of typo3 page error handler) just change the return value return parent::handlePageError($request, $message, $reasons); and extend class by PageContentErrorHandler.

Related

TYPO3 Ext. Custom Routes: Reverse Resolution not working

I am struggling with the URL generation of TYPO3 in my own extension.
Site Config:
routeEnhancers:
JobsPlugin:
type: Extbase
limitToPages: [11]
extension: Company
plugin: Jobs
routes:
- { routePath: '/{job_title}', _controller: 'Jobs::job', _arguments: {'job_title': 'id'} }
defaultController: 'Jobs::job'
requirements:
job_title: '[0-9]{1..6}'
aspects:
job_title:
type: PersistedAliasMapper
tableName: 'tx_company_domain_model_job'
routeFieldName: 'path_segment'
routeValuePrefix: '/'
Controller:
/**
* #param int $id
*/
public function jobAction(int $id) { }
Problem
The generated URL looks fine: /de/karriere/technischen-verkaufsberaterin-aussendienst
But when you want to access the page a PageNotFoundException is thrown.
Do I need to make any additional configurations or did I configure anything wrong?
Thanks in advance!
The problem was routeValuePrefix.
After I removed it, the URL could be resolved.
I assume, that this leads to a double slash when resolving: /de/karriere//technischen-verkaufsberaterin-aussendienst

Can't resolve route - basic login

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.

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