Skip to content
Advertisement

Symfony 5.2.11: Problem with creating Custom Access Decision Manager

I am trying to create a Custom Access Decision Manager by implementing AccessDecisionManagerInterface on Symfony 5.2.

Symfony recognizes the decision manager and instantiate it, but it doesn’t pass Voters array to decision manager. So it can’t collect votes, however the default decision manager works fine. I have followed the information provided on Symfony website. I have also copied the decision manager file to my AppSecurity and just changed the class+file name but it didn’t work. Adding the custom decision manager to service.yml didn’t help too.

Has anyone encountered the same problem? Any chance to fix it?

UPDATE #1

With reference to the issue https://github.com/symfony/symfony/issues/41123

I encountered this issue with different symptoms!

Although I knew the service is automatically registered but I did this in service.yml:

    AppSecuritySpecialAccessDecisionManager:
        class: AppSecuritySpecialAccessDecisionManager  
        autowire: false
        autoconfigure: false
        public: false

then I added decision manager to security.yml:

security:
    access_decision_manager:
        service: AppSecuritySpecialAccessDecisionManager

As you can see below, arguments haven’t been passed to the decision manager:

[root@dev7 rouzonline.test]# bin/console debug:container debug.security.access.decision_manager.inner --show-arguments                            

 // This service is a private alias for the service                                                                     
 // AppSecuritySpecialAccessDecisionManager                                                                           

Information for Service "AppSecuritySpecialAccessDecisionManager"
===================================================================

 Description of SpecialAccessDecisionManager

 ---------------- ------------------------------------------- 
  Option           Value                                      
 ---------------- ------------------------------------------- 
  Service ID       AppSecuritySpecialAccessDecisionManager  
  Class            AppSecuritySpecialAccessDecisionManager  
  Tags             -                                          
  Public           no                                         
  Synthetic        no                                         
  Lazy             no                                         
  Shared           yes                                        
  Abstract         no                                         
  Autowired        no                                         
  Autoconfigured   no                                         
 ---------------- ------------------------------------------- 


 ! [NOTE] The "debug.security.access.decision_manager.inner" service or alias has been removed or inlined when the      
 !        container was compiled.                                                                                       

[root@dev7 rouzonline.test]#

When I use default AccessDecisionManager voters are passed. I need to implement special authorization so I need to create my own decision manager. By the way, my decision manager implements AccessDecisionManagerInterface

I also checked SecurityBundleDependencyInjectionCompilerAddSecurityVotersPass->process() , it is not being called when my decision manager is set.

UPDATE #2 For testing, I temporarily renamed default AccessDecisionManager.php and placed my decision manager, it surprisingly worked. But it is not the solution. Still looking for the correct solution.

Advertisement

Answer

Thank you guys for your replies and helps, I figured it out.

Workaround

When Symfony compiles the code, it (somehow) has its own service definitions, so it doesn’t get confused. I traced the code into the compiled cache and I found that it can’t determine the service definitions of my ADM. So I changed my service.yml and defined arguments as follows:

    security.access.decision_manager:
        class: AppSecuritySpecialAccessDecisionManager  
        arguments:
            - []
            - 'affirmative'
            - false
            - true

Inside vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSecurityVotersPass.php I found that there is argument replacement which enumerates service arguments by number, that is why I added unnamed service arguments.

        $container->getDefinition('security.access.decision_manager')
            ->replaceArgument(0, new IteratorArgument($voterServices));
    }

The traces showed that Symfony collects all voters correctly up to this point, so it is not needed to manage dependencies manually.

By using this service.yml, I didn’t need to define the access_decision_manager in security.yml.

After finding the problem, I tried to use access_decision_manager but it caused the same error, means it didn’t receive list of voters. Then I decided to stop working on the problem as it is working for me now.

Conclusion

I know AccessDecisionManager is somehow a deep Symfony concept which is rarely used for common projects, but:

  1. Documentation doesn’t adequately cover this part
  2. When a developer implements an interface and injects it to Symfony, it is supposed either to be treated exactly same as the native code or provide enough descriptive logs or details to show noncompliance
  3. The method I used to fix the problem is not standard and might need modification in the future
  4. Symfony misbehaves when it is processing access_decision_manager from security.yml

Probably this part of Symfony needs to be reviewed.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement