In my app, I have set up the routes and security to use secure connection for certain routes:
<route id="store_checkout" pattern="/checkout" scheme="https">
<default key="_controller">Store:Store:checkout</default>
</route>
access_control:
- { path: ^/checkout, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
However, since this app is open-source and can run on any server (which may not have SSL), I want to allow users to disable/ignore SSL requirement (at their own risks) if they choose to do so.
Currently I can think of several ways:
I can have 2 routing files (1 with ssl, 1 without) and also 2 security files. Then based on user's selection on installation the app can decide which file to use
Or perhaps I can also customize router's generate function to generate http or https links based on the _scheme settings AND the SSL status (which user can enable/disable if they have/dont have SSL cert)
Is there any better way to resolve this issue?
I know the answer is late, but if you stumble upon this when googling:
Just add a to parameters.yml:
url_scheme: https
And in your security.yml:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: %url_scheme% }
Related
I am trying to debug a Resque setup in an (inherited) app, and so I found that there is a route for resque at /hidden/resque that would be nifty to access, but I am unable to access the route. I am wondering what I need to do ... When I try to access that route I get a HTTP 500 due to this error being thrown:
Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException: Full authentication is required to access this resource.
I have tried accessing it both as a web page (after authenticating as an admin role on a different route) and using curl -H 'Authorization: Basic 9339034147964aebec6716c0110311d1' 'https://web.mysite/hidden/resque' -v. No go.
So what constitues "full authentication"? I am already logged in as an admin user on one of the other routes. Would I need to add anything more to the below config? This has not been setup by me, so I would not know if it ever worked.
app/config/routing.yml
ResqueBundle:
resource: "#ResqueBundle/Resources/config/routing.xml"
prefix: /hidden/resque
app/config/security.yml
access_control:
- { path: ^/hidden, roles: ROLE_ADMIN }
According to the docs:
IS_AUTHENTICATED_FULLY: This is similar to IS_AUTHENTICATED_REMEMBERED, but stronger. Users who are logged in only because of a "remember me cookie" will have IS_AUTHENTICATED_REMEMBERED but will not have IS_AUTHENTICATED_FULLY.
How can I be "more logged in" than using a cookie? Should I send a basic auth header with username and password base64 encoded?
If you ask for full authentication.
I.E:
/**
* Requiring IS_AUTHENTICATED_FULLY
*
* #IsGranted("IS_AUTHENTICATED_FULLY", message="Nope, no access")
*/
Then when you are logging in with an user, your Authorization Checker must have granted you the IS_AUTHENTICATED_FULLY status in order to have access.
As explained in the docs:
IS_AUTHENTICATED_FULLY: This is similar to IS_AUTHENTICATED_REMEMBERED, but stronger. Users who are logged in only because of a "remember me cookie" will have IS_AUTHENTICATED_REMEMBERED but will not have IS_AUTHENTICATED_FULLY.
You will be completely Authenticated if you manually log in, and not via a cookie. If you are using a command that remembers your credentials, that might be the issue.
Check Doc nº3 to see whether your actual way of entering that route falls inside the IS_REMEMBERED status. Even maybe you end up prefering using the less restrictive IS_AUTHENTICATED_REMEMBERED
Check the different documentations here:
https://symfony.com/doc/3.4/security.html#checking-to-see-if-a-user-is-logged-in-is-authenticated-fully
https://symfony.com/doc/3.4/security.html#learn-more
https://symfony.com/doc/3.4/security/remember_me.html
https://symfony.com/doc/3.4/components/security/authorization.html#authorization-checker
https://github.com/symfony/symfony/blob/3.4/src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php
I try to set up security per folder under src/ in Symfony. But I want a different set of security rules per main folder "General" and "Intranet" without having to prefix the routes... So I only have to prefix "Extranet"
Is that possible? I know that with a prefix in routing.yml it is very easy to do but that is not an option since the visible urls will suddenly change
The problem arises when we have to allow External users to our platform. For years it was only available for the companies' employees only but now external people must have access to certain pages. And some general routes (ajax calls etc) must be available for all
src/
Intranet/ => Open routes for internal users
SomeBundle
...
General/ => Open routes for all users
AnotherBundle
...
Extranet/ => Open routes for external users
TheBestBundle
...
Then the Extranet routes all get an extra prefix /extranet/. But I would like to have the other 2 (General and Intranet) without any prefix
# routing.yml
extranet:
resource: "#ExtranetBundle/Controller/"
prefix: /extranet/
Then with access control I take care of the /extranet routes
access_control:
# Login and the base_route "/" is always available
- { path: ^/$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
# External users + Super admins + server IP's can only access urls starting with /extranet/
-
path: ^/extranet/*
roles: [ROLE_EXTERNAL_USER, ROLE_SUPER_ADMIN]
ips: !php/const:SomeBundle\SomeClass\ConstantProvider::ALLOWED_SERVER_IPS
# Some routes need to be available for both internal and external users
# but hopefully without having to prefix them
...
# All other routes are only for internal users and the right ip addresses
-
path: ^/*
role: ROLE_INTERNAL_USER
ips: !php/const:SomeBundle\SomeClass\ConstantProvider::ALLOWED_SERVER_IPS
Or maybe an idea of approaching this problem differently?
I Think the best approche is to use voter external user need to have a unique ROLE (EXTERNAL_ROLE) then you can use voter to deney resources you want to protect https://symfony.com/doc/current/security/voters.html so this way you can protect a resource based on a the logic not on the folder
I have an application with the framework Symfony, I have users with particular rights, if they don't have the right to access into a page, I must block them, but the users still can access into page with modifying URLs. For example I have this URL that they have the right to access in it:
dialog/campany/sms/fid/setting/new
and they don't have the right to access to this URL:
dialog/campany/mail/fid/setting/new
but they can by remplacing sms by mail.
You have to checkout how your security.yml is configured and control the access from there. If you need information about it you can visit: http://symfony.com/doc/current/security/access_control.html.
Also you could control the access making a function that checks the user's credentials before given access to a given page.
Supposing that ROLE_SMS can only access to dialog/campany/sms/ and ROLE_MAIL can only access to dialog/campany/mail/
In app/config/security.yml , you should have:
security:
access_control:
- { path: ^/dialog/campany/sms/, roles: ROLE_SMS }
- { path: ^/dialog/campany/mail/, roles: ROLE_MAIL }
If you only want to limit the /new URL, you can change the path to:
- { path: ^/dialog/campany/sms/fid/setting/new$, roles: ROLE_SMS }
- { path: ^/dialog/campany/mail/fid/setting/new$, roles: ROLE_MAIL }
I am working on a project that is on expansion and needs to support multi-domain and multi-language.
I find that the way the standard routing is managed does not cover in an efficient way the project needs.
I found this: https://github.com/alexandresalome/multisite-bundle
It's find it good but I see the following drawbacks:
1) The bundle has not really much movement
2) The routing is set up at Controller/annotation level instead of yml file, what makes project hard to maintain.
Do you know any bundle/strategy based on symfony2 for this need? thanks a lot !!!
That doesn't solve the problem.
This is my scenario:
I have a parameter where I set up several hosts: landing_hosts, separated by “|”
I have some landings, that are only valid for those hosts, routing: landings
When a request comes, I can’t see any way to dynamically set the current host for the default => hosts entry.
I am forced to specify one, that is %domain%. This works this way because there is a cached file appDevUrlGenerator.php that is created at first time website is visited or ran the command app/cache cache:clear.
If I visit a landing page as host2, the urls and paths created inside twig templates will follow the hosts1 instead hosts2, and this is not valid.
// parameters.yml
parameters:
landing_hosts: host1|host2
main_host: host1
// routing.yml
landings:
host: "{hosts}"
path: /
defaults: { _controller: FrontendBundle:Landings:index }
requirements:
hosts: %landing_hosts%
defaults:
hosts: %main_host%
I am setting up a website which I want to use separate firewalls and authentication systems for frontend and backend. So my security.yml is configured as below. I am using in_memory user provider in early development phase.
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
backend_in_memory:
memory:
users:
admin: { password: admin, roles: [ 'ROLE_ADMIN' ] }
frontend_in_memory:
memory:
users:
user: { password: 12345, roles: [ 'ROLE_USER' ] }
firewalls:
# (Configuration for backend omitted)
frontend_login_page:
pattern: ^/login$
security: false
frontend:
pattern: ^/
provider: frontend_in_memory
anonymous: ~
form_login:
check_path: login_check_route # http://example.com/login_check
login_path: login_route # http://example.com/login
access_control:
# (Configuration for backend omitted)
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
I have omitted the backend part because it doesn't matter. The problem is still there when the omitted part is commented out.
The problem is that frontend authentication won't work with the above configuration. Here's what I did:
Visit http://example.com/login
Enter the credential (user:12345), click login
http://example.com/login_check authenticates the user
The authentication service redirects user back to http://example.com/. No error is thrown. In fact, when I turned on the debug_redirects option, it clearly shows that "user" is authenticated on the redirect page.
Expected behavior: The security token should show that I'm logged in as "user" after following the redirect and go back to the index page.
Actual behavior: The security token still shows "anonymous" login after following the redirect and go back to the index page.
But with nearly identical settings (paths and route names aren't the same), the backend part works correctly.
After some investigation I found that the cause is the way user providers is currently written. Notice that frontend_in_memory section is placed below backend_in_memory that is used for backend authentication. So I explicitly specify the frontend_in_memory provider for the frontend firewall. And it kind of works - I must login with "user:12345" in the frontend login page. Logging in with "admin" won't work. So it must be using the correct user provider. But I suspect that the framework cannot update the security token correctly because it is still searching the "user" account from the first user provider which is backend_in_memory. In fact I can make the above config work with either one of the following changes:
add "user" login to the backend_in_memory provider's user list (password needn't be the same), or
swap frontend_in_memory with backend_in_memory so that frontend_in_memory becomes the first user provider.
Of course they are not the correct way of solving this problem. Adding "user" account to the backend makes no sense at all; swapping the order of two user providers fixes the frontend but breaks the backend.
I would like to know what's wrong and how to fix this. Thank you!
I was stuck when I posted the question, but after a sleep the answer is found ;)
Turns out I came across an issue reported long ago:
https://github.com/symfony/symfony/issues/4498
In short,
The problem isn't about the configuration.
And it isn't about authentication neither.
It actually relates to how an authenticated user is refreshed after redirection. That's why the app is correctly authenticated as "user" on the redirect page, but not after that.
Here is the code when the framework refreshes the user (can be found in \Symfony\Component\Security\Http\Firewall\ContextListener):
foreach ($this->userProviders as $provider) {
try {
$refreshedUser = $provider->refreshUser($user);
$token->setUser($refreshedUser);
if (null !== $this->logger) {
$this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $refreshedUser->getUsername()));
}
return $token;
} catch (UnsupportedUserException $unsupported) {
// let's try the next user provider // *1
} catch (UsernameNotFoundException $notFound) {
if (null !== $this->logger) {
$this->logger->warning(sprintf('Username "%s" could not be found.', $notFound->getUsername()));
}
return; // *2
}
}
The above code shows how the framework loops through the user providers to find the particular user (refreshUser()). *1 and *2 are added by me. If a user provider throws an UnsupportedUserException, this means that the provider isn't responsible for the supplied UserInterface. The listener will then iterate to the next user provider (*1).
However, if what the user provider thrown is a UsernameNotFoundException, this means that the provider is responsible for the supplied UserInterface, but the corresponding account could not be found. The loop will then stop immediately. (*2)
In my question, the same user provider, \Symfony\Component\Security\Core\User\InMemoryUserProvider, is used in both frontend and backend environment. And InMemoryUserProvider is responsible for the UserInterface implemented by Symfony\Component\Security\Core\User\User.
In the frontend, "user" is in fact authenticated successfully. However, in the user refresh attempt,
The order of the user providers will be like this: backend in-memory provider, frontend in-memory provider.
So, backend in-memory provider will run first.
The backend in-memory provider believes it is responsible for the supplied UserInterface because it is also an instance of Symfony\Component\Security\Core\User\User.
But it fails to locate the "user" account (it only has the "admin" account).
It then throws a UsernameNotFoundException.
The refreshUser() routine won't bother to try with next provider because UsernameNotFoundException means that the responsible user provider is already found. Instead it stops trying and removes the authentication token.
This explains why the configuration won't work. Despite using a different user provider, the only way to work around this is to copy the framework's InMemoryUserProvider and User classes and change the refreshUser() method to check against the copied User class, so that the frontend and backend user provider uses different user classes and won't clash.