LexikjwtAuthenticator Symfony define route for authentication - symfony

I'm trying to use Lexikjwtauthenticator on a Symfony project but I cannot figure out where is the /api/login_check Controller defined.
I'm receiving "Unable to find the controller for path "/api/login_check". The route is wrongly configured." all the times.
The only way to work around this is to define a form_login (other than json_login) configuration inside the login firewall. Is it correct or am I missing something?
Thanks

I discovered that the real problem was caused by using "postman" which apparently sends data as "form" instead of "json".
Modifying security.yaml "json_login" and replacing it with "form_login" (which is documented) everything seems to work fine with Postman.
I still have to try it from my JS front-end.

Related

Symfony kernel creates 302-redirect instead of using correct route

I am building a Symfony 5.3 app and have mapped the route /logout to a controller method logout().
Running the symfony console with router:match /logout yields for the value of "Defaults": App\Controller\IndexController::logout(), just as expected.
But when I visit the page in my browser with xdebug enabled and breakpoints put at multiple relevant points in my code, I see that even though the route is correctly matched (the log agrees), the logout method in the controller is never run. A simple $logger->debug("This is never run") confirms that it's not just a xdebug issue.
Instead, the kernel decides to return a 302 that redirects to "/" without even touching the method.
I have checked that my browser doesn't cache old redirects and have run cache:clear in the console a few times.
What could possibly cause this behaviour? Any ideas?
Symfony never actually calls your controller for logout, it executes its own logic and redirects user to some page. If you need to customize logout behaviour please hook into the LogoutEvent event as per documentation: https://symfony.com/doc/current/security.html#customizing-logout

Symfony redirect to dynamic route name

I'm using the Symfony CMF Routing Bundle to create dynamic routes (I'm using one example here):
$route = new Route('/dynamic-url');
$route->setMethods("GET");
$route->setDefault('_controller', 'AppBundle:MyRoute:getResponse');
$routeCollection->add('my-dynamic-route', $route);
The response is loaded from the getResponseAction() function inside the MyRouteController:
/**
* No annotations here, because I want the url to be dynamic from the database
*/
public function getResponseAction(Request $request) {
return $this->render('dynamic-page-template.html.twig');
}
When I go to '/dynamic-url', it works.
When in another controller, I want to redirect to this dynamic route, like this:
return $this->redirectToRoute('my-dynamic-route');
But I get this error: "None of the chained routers were able to generate route: Route 'my-dynamic-route' not found"
Also interesting: when I go to '/dynamic-url', the dev bar actually says that the Route name is 'my-dynamic-route'.
Edit
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Since it's a dynamic route, which wasn't saved anywhere (like routing.yml ) it will be only availabe for Request where it has been defined. So at the end of Request your app will immediately "forget" about new Route generated at runtime.
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Actualy No. It depends on where you call $this->get('router')->getRouteCollection();
Just try to call
dump($this->get('router')->getRouteCollection();)
right before the return statement in your Action where you're adding the my-dynamic-route route. I'm sure you'll see your my-dynamic-route in the list of routes, but if you call it anywhere else - you won't see it.
It's less about symfony rather about stateless nature of web (see Why say that HTTP is a stateless protocol?)
I started to think about this and pointed your question to an routing issue on symfony-cmf. You tagged with #symfony-cmf and i think this would be important feature for us.
I also think, when you persist your route with /my-route you should also ask the router for that name (or in case of the CMF with an content object with that a route.)
If you use the CmfRoutingBundle dynamic router, you should persist your routes to doctrine. The idea of dynamic here is that they can be created at runtime, e.g. in an admin interface or elsewhere by code. The DynamicRouter loads routes from the database.
If you use PHPCR-ODM, the route name is the repository id, typically something like /cms/routes/my-route and you can generate it with that name. If you have access to the route object loaded from the database, you can also generate from that, rather than the path. If you have to hardcode a path in your application, its an indication that probably a normally configured route would be better.
If you just add a route to the route collection on the fly, you would have to make sure that happens in each request, its only available when you add it. With the CMF ChainRouter you could register your own router that does that, but i would not know of a good use case for that. Either you know the route, then you can configure it in the routing.xml|yml|php config file. Or routes are loaded dynamically, in which point you should use DynamicRouter, potentially with a custom route loader.

Symfony route without controller

I have to work on a Symfony project that I never met before. There is a route that I'd like to figure out what script generates the result. Normally int the routing.yml the the _controller in the defaults tells this, but this route does not have any controller associated with:
vendorname_admin_generate_external_site_admin:
path: /admin/
host: "{current}.%vendorname_academic_base_host%"
defaults: {current: %vendorname_academic_base_subdomain%}
The two parameters are:
vendorname_academic_base_host: vendordomain.com
vendorname_academic_base_subdomain: developmentserver-vpn
Could you help me to understand what does this route definition do?
Because of the fact it is defining a specific host (ie, a domain name) as part of the route, makes me think that it's just an alias to an external website, that isn't actually in the same codebase. -- Also the fact its called 'external_site_admin'.
I've just added a similar route with a specific host, mine is still in the same codebase, but under a specific, shorter URL, but I defined my route as a template that I can use to setup as an alias.

Spring Security OAuth2 Behind a Proxy Server

There seem to be many examples of Spring Security OAuth2, but most of them run on localhost at some specific set of ports. I was able to get my application working with ports specified for my AuthorizationServer and my ResourceServer. The next step I needed to take was move this application behind a proxy server, but the application stopped functioning. The main issues seem to be path related, but I'm struggling with lack of examples on how to accomplish the task of moving OAuth2 Spring behind a proxy server. I've focused on overriding the WhitelabelApprovalEndpoint, but I'm not sure if this is what is required.
I was able to create a controller that is nearly identical to the WhiteLabelApprovalEndpoint, but do not know how to adapt it to accommodate being behind a proxy.
#Controller
#SessionAttributes("authorizationRequest")
public class ApprovalEndpoint {
#RequestMapping("/oauth/confirm_access")
...
private static String TEMPLATE = "<html><body><h1>OAuth Approval</h1>"
+ "<p>Do you authorize '${authorizationRequest.clientId}' to access your protected resources?</p>"
+ "<form id='confirmationForm' name='confirmationForm' action='authorize' method='post'><input name='user_oauth_approval' value='true' type='hidden'/>%csrf%%scopes%<label><input name='authorize' value='Authorize' type='submit'/></label></form>"
+ "%denial%</body></html>";
...
The only change I made to the class was to update the form action string, making the path relative by replacing
action='${path}/oauth/authorize'
with
action='authorize'
This allows the POST to go to the correct URL
http://localhost/proxy/stuff/javaPath/oauth/authorize
instead of
http://javaPath/oauth/authorize
The latter doesn't map when submitted through Apache (the frontend proxy). But it would seem that this creates other problems in the Java application, because this results in the error
error="invalid_request", error_description="Cannot approve uninitialized authorization request."
I see that this exception is thrown in the AuthorizationEndpoint when the authorizationRequest is null. This looks like it should be handled by my custom class having SessionAttributes set properly, but updating the just the path that I'm POSTing to seems to break this.
May be you already solved it but posting the answer as it may help someone.
It is because authorize end point URL (domain + path(including proxy)) should be consistent. I mean either it should be 'localhost' or your proxy path but it should be consistent.
As OAuth uses session internally and later fetches it from the same path (when the POST happens) . So if the URL changes (POST) it wont get the session then it throws Cannot approve uninitialized authorization request.
For my case ,I was using the authorize end point as:
https://mydomain/myapp/oauth/authorize?grant_type=authorization_code&client_id=clientid&redirect_uri=http://localhost:8181&response_type=code
but in the properties I was having :
server:
session:
cookie:
path: /appProxy
context-path: /myapp
port: 8081
After successful authorization when POST is done on it tries to fetch the session from /appProxy/myapp instead of /myapp and resulting in Cannot approve uninitialized authorization request.
So to solve this, I can either remove Session.cookie.path property or run Oauth server on https://mydomain/appProxy/myapp/oauth/authorize to make it consistent.

Global Route on condition

I have a tutorial page, and need a global redirect
that will send to user to /tutoroal if they don't pass a DB check:
User->passedTutorial()
Can I make this with a route configuration calling a controller/model method ?
This sounds more like a security context/question. Have you considered creating a custom role, eg ROLE_USER_PASSED?
You could then either check for this role in security.yml or annotate your controllers with #Security("has_role('ROLE_USER_PASSED')")
You can do that using #Security annotation like described there: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html.
Particularly:
/**
* #Security("user.passedTutorial()")
*/
UPD.
Finally problem can be solved using expression in access_control section of security.yml: http://symfony.com/doc/current/cookbook/security/access_control.html#securing-by-an-expression
By doing so it's still needed to implement access_denied_handler in used firewall (http://symfony.com/doc/current/reference/configuration/security.html) so that it will check the request/user again and perform redirect.

Resources