Secure UI but publicly allow AJAX request - symfony

I am working on a project using the API Platform.
I would like to have the documentation of the UI secured with basic authentication, while some of the routes should be publicly available.
For example:
/**
* An ordered dish.
*
* #ApiResource(
* attributes={"access_control"="is_granted('ROLE_USER')"},
* collectionOperations={
* "get"={"access_control"="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')"},
* "post"={"access_control"="is_granted('ROLE_ADMIN')"}
* },
* itemOperations={
* "get"={"access_control"="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')"}
* }
* )
*
* #ORM\Entity
* #ORM\Table(name="uitgekookt_dish")
*/
class Dish
When I view the docs in the browser, i can simply access /api/dishes, because of the IS_AUTHENTICATED_ANONYMOUSLY. I see other get/post methods available there as well (though some of the post methods are secured).
However, the docs should not be available at all publicly. How do I ensure, in Symfony 4, that I seperate my security config for docs and ajax requests?

Not sure if I get it right but you want to restrict /api/doc (or whatever url you are using for docs) so add it to access_control in security.yaml
security:
access_control:
- { path: ^/api/doc, roles: [ROLE_ADMIN] }

First, disable Swagger UI that is loaded for every page, and register it as a known location as pointed out in this docs entry:
# app/config/routes.yaml
api_platform:
# ...
enable_swagger_ui: false
# app/config/routes.yaml
swagger_ui:
path: /api/docs
controller: api_platform.swagger.action.ui
Then, as pointed out by #zajca, add an access control route to secure this page, and the underlying JSON and Hydra endpoints:
security:
access_control:
- { path: ^/api/docs, roles: [ROLE_ADMIN] }

Related

Cancel locale an redirect to another one in Symfony

i have website in Symfony 4.2 with 3 prefixed locales:
annotations.yaml
controllers:
resource: ../../src/Controller/
type: annotation
prefix:
en: '/en'
de: '/de'
cz: '/cz'
and with route annotations in controllers:
/**
* #Route({"en": "references"}, name="reference")
* #Route({"cz": "reference"}, name="reference")
* #Route({"de": "referenzen"}, name="reference")
*/
Now i need cancel deutch locale and all /de/route adresses redirect to /en/route.
Is here any easy way to do it?

User Role based routes in Symfony

I've got five types of roles in my Symfony project.
I want to create restrictions for each role, so that they will have access to specific routes. They will not be able to access others paths. I want to do this in an efficient way like Laravel uses middleware in the routes for access. Is there any way like this in Symfony?
You could do that in different ways, and it depends on your Symfony version.
In the older Symfony versions, the most common way to restrict access to certain routes is adding into config/packages/security.yaml some parameters such as:
access_control:
- { path: '^/agent', roles: ROLE_AGENT }
- { path: '^/profile', roles: ROLE_USER }
- { path: '^/admin', roles: ROLE_ADMIN }
- { path: '^/admin/statistics', roles: ROLE_SUPER_ADMIN }
Also, it's good practice to define the role hierarchy into the same file config/packages/security.yaml :
`role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN`
Hence, the users with a SUPER_ADMIN_ROLE will have access to routes restricted to ROLE_ADMIN.
However, my recommendation is if you've several parts to restrict define the general access roles into the config/packages/security.yaml file such as and define a role hierarchy as I said before:
access_control:
- { path: '^/admin', roles: ROLE_ADMIN }
- { path: '^/profile', roles: ROLE_USER }
Then restrict the other routes using annotations thanks to SensioFrameworkExtraBundle, for example:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
/**
* Require ROLE_ADMIN_SYSTEMS for *every* controller method in this class.
*
* #IsGranted("ROLE_ADMIN_SYSTEMS")
*/
public function YourFunction() { }
For more information look into official Symfony Docs that are very clear. Symfony Security official documentation
I hope this could help you, if you've any other doubts just tell me,
Kind regards.

NelmioApiDocBundle doesn't work "No operations defined in spec!"

I want to use nelmio for symfony-project, but it doesn't work.
It always says: No operations defined in spec!
I also try the example on https://symfony.com/doc/current/bundles/NelmioApiDocBundle/index.html
Whats's wrong? Any ideas?
routing.yml
app.swagger_ui:
path: /api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
config.yml
nelmio_api_doc:
areas:
path_patterns: # an array of regexps
- ^/api(?!/doc$)
host_patterns:
- ^api\.
Controller
/**
* #Route("/api/test", methods={"GET"})
* #SWG\Response(
* response=200,
* description="Returns the rewards of an user"
* )
* #SWG\Parameter(
* name="order",
* in="query",
* type="string",
* description="The field used to order rewards"
* )
*/
public function testAction()
{
}
composer.json
"symfony/symfony": "3.4.*",
"nelmio/api-doc-bundle": "3.2.1",
Just remove
host_patterns:
- ^api\.
and set your virtual host in
documentation:
host: symfony.localhost
The assets normally are installed by composer if any command event (usually post-install-cmd or post-update-cmd) triggers the ScriptHandler::installAssets script. If you have not set up this script, you can manually execute this command:
php bin/console assets:install --symlink
The problem is in config.yml path patterns. If you remove the config(all nelmio_api_doc) or change the path patterns will work. Example:
nelmio_api_doc:
areas:
default:
path_patterns: [ /api/ ]

Why does a custom route appears twice in Nelmio API Doc?

I've tried defining a custom route name for one of my APIs and since then, the API Doc displays that route twice. Any ideas why?
Here's the definition of my API:
/**
* #ApiDoc(
* description = "Sends the support email to the HelpDesk address",
* statusCodes = {
* 204 = "Returned when successful",
* 400 = "Returned when the parameters are incorrect",
* 401 = "Returned when the token is invalid",
* 500 = "Returned when there's an internal server error"
* },
* input="AppBundle\Form\Type\SupportEmailType"
* )
* #Post("/support-requests")
* #Rest\View ()
*/
public function postSupportAction(Request $request)
and here's how the route shows up in my doc:
And this is my routing.yml file:
# app/config/routing.yml
app:
resource: "#AppBundle/Controller/"
type: annotation
NelmioApiDocBundle:
resource: "#NelmioApiDocBundle/Resources/config/routing.yml"
prefix: /api/doc
user:
type: rest
resource: AppBundle\Controller\UserController
From the looks of it the only thing that comes to mind as having the potential to do this is the first part of your routing.yml
try removing this from your routing.yml
app:
resource: "#AppBundle/Controller/"
type: annotation
I think this code, and the separated definition of the user route makes nelmio see the route twice. I had a similar problem some time ago and I think this was the reason. Sorry for the amount of questions I had to ask but i needed to see the full picture.
Hope this helps,
Alexandru Cosoi

In Symfony2 (v2.3.4) - FOSUserBundle conflicts with Controller Route generated by CRUD

First of all im still learning so don't be angry at me for asking this question (and for my English - im trying my best).
Im going through book tutorial which is written for Symfony 2.0.10, but for each exercise i'm using newest Symfony 2.3.4 project, solving out eventually changes (learning that way) with a good results but finally i'm stuck.
The problem is that the point of exercise is to "make an app which is accessible only for logged users" using FOSUserBundle and CRUD panel. (without registering and all that unnecessary stuff)
Like in the tutorial, i created a bundle (My/BackendBundle), deleted its controller and views, then i created a entity called MyBackendBundle:Mountain and populate db with my data. Next i created CRUD panel for entity i've created before, so the new controller appears wth all those "show", "new" "edit" etc methods. The important thing is that generated controller class (which is named MountainController because of "MyBackendBundle:Mountain" entity) have this #Routing annotation before class:
/**
* Mountain controller.
*
* #Route("/mountain")
*/
class MountainController extends Controller
{
...
But tutorial ordered to delete this annotation in order to use simply Project/web/ address instead of Project/web/mountain. so i did.
Then i created and admin account and change my routing.yml to looks like this:
routing.yml
my_backend:
resource: "#MyBackendBundle/Controller/"
type: annotation
prefix: /
fos_user_security:
resource: "#FOSUserBundle/Resources/config/routing/security.xml"
Next step of tut is to modify the security.yml to looks like this:
security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
#role_hierarchy:
# ROLE_ADMIN: ROLE_USER
# ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
#id: fos_user.user_manager
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
# the user is redirected here when he/she needs to login
login_path: /login
# if true, forward the user to the login form instead of redirecting
use_forward: false
# submit the login form here
check_path: /login_check
# by default, the login form *must* be a POST, not a GET
post_only: true
#remember_me: false
# login success redirecting options (read further below)
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
# login failure redirecting options (read further below)
failure_path: null
failure_forward: false
# field names for the username and password fields
username_parameter: _username
password_parameter: _password
# csrf token options
csrf_parameter: _csrf_token
intention: authenticate
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_ADMIN }
Next steps is about to add logout link to base.html.twig and to override the login page, but this probably doesn't matter because problems already started. When i try to run my app i've got Unable to find Mountain entity. exception. which is pointed to this function in MountainController:
/**
* Finds and displays a Mountain entity.
*
* #Route("/{id}", name="mountain_show")
* #Method("GET")
* #Template()
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyBackendBundle:Mountain')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Mountain entity.');
}
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
);
}
I'm almost sure it has something to do with the #Route("/{id}", name="mountain_show") annotation which is generated by CRUD because the "login_path" from security.yml which is "/login" fits to #Route pattern of showAction. So the action instead of getting the id of record to show (which should be a number), receives an text or i don't know what, and tries to find id with negative results.
Ps. The example from tutorial (on Symfony 2.0.10) working because the "showAction" generated by CRUD has route: #Route("/{id}/show", name="mountain_show")
which isn't conflicts.
So if there is anybody who can help me with this i will be very appreciated.
If there is any more info i can give to better explain my problem just say. Regards. KB
symfony's routing will try to match the first matching route found ... in your case the other controller's annotation routes are configured before/above FOSUserBundle's ones ... Therefore symfony will first try to match /{id} and then /login.
just move FOSUserBundle's routes before your other controller's route in your configuration to fix this issue.

Resources