Global Route on condition - symfony

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.

Related

LexikjwtAuthenticator Symfony define route for authentication

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.

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.

Response from Jasig CAS

I'm working with a servlet in which I want to add filters to log in with cas, and after successful login, i need to get some information from authentication (I need username and usergroup). So, in order to understand how to do that, can someone tell me, or refer me to a documentation, what's the response from CAS and what's in it? Thank you in advance.
If you are using CAS with Spring Security you can use AuthenticationSuccessHandler for this. You can get all the information from "authentication" parameter.
If you are not, you can override some methods of the filter you are using for ticket validation. There are onSuccessfulValidation and onFailedValidation methods in AbstractTicketValidationFilter which are empty by default. You can extend the filter you are using and override these methods. The information will be available under "assertion" parameter.
Last of all i think you can create your own filter and in that filter check if the user is logged in and retrieve the desired inforation. But since i haven't used CAS without Spring Security i am not sure the desired information will be available to you there.

find user by username from multiple providers [symfony2]

I need to find a user object in symfony2 based on the username or emailadres. This is not for loggin in, but for other actions on a user.
I can simply request the (Doctrine2) repository and call the method loadByUsername from the UserProviderInterface that is on my repository-class.
But the code that needs to do this will be used in multiple projects and I need it to be a bit more generic. The user class/table might be different or the users might come from a completely different type of provider.
Is there a way to find a user by username just like Symfony2 itself uses when logging in?
This way it will work no matter how the user providers are configured in security.yml.
Is there some service in Symfony2 I can use for this?
Is there a "user provider service" where I can call a method something like "loadUserByUsername" that will try each configured provider?
After some poking into the SecurityBundle of Symfony itself, I figured out the following:
Given this is in your security.yml:
providers:
AdministrationUser:
entity:
class: AdministrationBundle\Entity\User
Symfony will create a service with the following name:
security.user.provider.concrete.administrationuser
This service uses the UserProviderInterface and when you fetch this service you can simply call the method loadUserByName and find your user.
So all you need to know is the name of the provider you configured yourself and you can determine the service-name and fetch it.
I'm in a more generic situation, so I added an alias to that service in the Extension-class of my bundle:
// alias the user_provider mentioned
$container->setAlias('my_security_bundle.user.provider', new Alias('security.user.provider.concrete.' . strtolower($config['user']['provider'])));
Where $config['user']['provider'] comes from config.yml (and needs to be configured in your Configuration class, but that is a different story.
Now I can simply use that new alias and I will get the correct service to find my user in a Controller like so:
/** #var UserProviderInterface $userProvider */
$userProvider = $this->get('my_security_bundle.user.provider');
$user = $userProvider->loadUserByUsername('someone#somewhere.tld');

spring security logout trigger

I want to remove logged out user from a Hashmap I have for logged in users but I don't find the way to do this as when I press the logout link. It just redirected to login page.
In spring security I have
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/logout.htm"/>
logout link is like
Logout
When I press this link it just go to my login mapping
#RequestMapping("login")
public ModelAndView login(){}
and when I try to get user detail using
SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
it returns me anonymous user. So how can I get the logged out user detail.
Please let me know if you need more details.
Add an implementation of org.springframework.security.web.authentication.logout.LogoutSuccessHandler interface as a bean to your security context.
Then you can use it:
<logout success-handler-ref="yourLogoutSuccessHandler" />
EDIT.
As mentioned by Marcel this solution will not work out of the box because you can't mix success-handler-ref and logout-success-url attributes (reference). I prefer slightly different solution : instead of inheritance, you can use composition:
Prepare configuratio for SimpleUrlLogoutSuccessHandler bean.
Set up logout-success-url via corresponding defaultTargetUrl property.
Inject SimpleUrlLogoutSuccessHandler bean into your CustomUrlLogoutSuccessHandler using LogoutSuccessHandler interface and call it after doing your stuff.
Advantage is that you will be less coupled with a framework code. So you will have less problems in a case of migration from Spring Security 3.1 to Spring Security Y.Y
The hint about the LogoutSuccessHandler is correct. However, you have to consider that configuring success-handler-ref and logout-success-url are mutually exclusive if I'm not mistaken. Hence, you need to implement the forwarding to URL manually in your success handler. Pointer: https://stackoverflow.com/a/6770785/131929
Authentication authentication = SecurityContextHolder.getContext().getAuthentication()
authentication.getName()
In your applicationContext-security.xml file add the success-handler like below
< logout logout-url="/resources/j_spring_security_logout" success-handler-ref="com.mycompany.security.SpringSecurityLogoutHandler" />
Create the Class which will be implemneting org.springframework.security.web.authentication.logout.LogoutHandler interface and in it's logout method do all the stuff you want at the time of logout.

Resources