I'm using the Symfony framework with the FOS User Bundle. I'm using the security context to determine which menu items and other items to display.
$securityContext = $this->get('security.context');
if ($securityContext->isGranted($report['Permission'])){
//add the menu item...
}
Is there any way to give a anonymous user a security context of 'ROLE_USER'? I've got logged in users working properly.
I tried adding the line:
role_hierarchy:
IS_AUTHENTICATED_ANONYMOUSLY: ROLE_USER
to my security.yml hoping this would do it, but apparently not. I've Googled around a little bit and read the documentation.
I imagine that:
if ($securityContext->isGranted($report['Permission'])
|| ($report['Permission'] === 'ROLE_USER' && $securityContext->is_anonymous()))
would work, but this feels like kind of a hack (and not very DRY)
Edit:
This is for an intranet site. I've got a table that contains names of reports. Some reports should be able to be seen by everyone, regardless of if they are logged in or not. Some reports require permissions to view. I don't want to create several hundred users when only a handful will need access.
If you are trying to give access to people to a given url why not simply authorize it this way ?
You have 2 method to achieve this: create a firewall authorization or role defined a url
1) Firewall autorization
firewalls:
test:
pattern: ^/ws // you url or schema url with regex
anonymous: true
2) url with a role defined access
access_control:
- { path: ^/given-url, roles: IS_AUTHENTICATED_ANONYMOUSLY }
// in app/config/security.yml
in both case, non authenticated user and authenticated user will have access to this url
By the way , if you want to test (in order to display some user variables) if a user is authenticated or not , just make your test in twig
{% if app.user is defined and app.user is not null %}
The user {{ app.user.username }} is connected.
{% else %}
No user connected
{% end %}
EDIT : Content based view : juste create a route for your action which would not match your firewall rules
Related
I have this scenario.
My site has a secured part. Security is, I think, correctly configured.
If I try to open a secured URL from browser, I am asked to type username and password.
Symfony profiler shows correctly user context after logon
The homepage (root route) is not secured (the profiler shows here the anonymous context)
Now the problem:
If, in the twig template of the homepage, I put something like this
{{ render(path('secured_route')) }}
the content of the secured route is rendered!
I expected to get some kind of exception or the login window!
Is this a bug or am I missing something?
When rendering a controller this way, you're bypassing the router, so securities related to routes are bypassed too.
The best you can do is to restraint your controller to logged-in users using the #Security annotation:
/**
* #Security("has_role('IS_AUTHENTICATED_REMEMBERED')")
*/
By using "render" from twig you are skipping the security checks related to routes, if you don't need to get the content in the anonymous context, you could check the role from Twig before rendering the controller, something like:
{% if is_granted('ROLE_USER') %}
{{ render(path('secured_route')) }}
{% endif %}
Here is my issue.
Situation:
I am trying to add some custom logic during user login. I could find to ways to do so:
hard way (but with a lot of control); building my own authentication provider, following this guidelines of the cookbook or this complementing publication of vandenbrand
easy way (exactly what I need ): use simple_form. simple_form is a key which has the same options as form_login, but for which I can define an "authenticator".
cookbook tuto I used can be found here
Issue
I had an existing and operational app/security.yml configuration with 'form_login' key.
secured_area:
pattern: ^/foo/user/secured/
form_login:
check_path: /foo/user/secured/login_check
login_path: /foo/user/login
I followed steps of the tutorial described above. therefore, my security.yml gets modified to:
secured_area:
pattern: ^/foo/user/secured/
#form_login:
simple_form:
authenticator: foo_authenticator
check_path: /foo/user/secured/login_check
login_path: /foo/user/login
when I try to access a page /foo/user/secured/target of the secured area, the firewall does its job: it catches the query and asks for credentials (via intermediary page /foo/user/login).
However, once right credentials input (and obviously validated), I keep staying on the same page. It does not redirect to the page /foo/user/secured/target I was asking for in the first place. There is no refreshing to trying to go to that page via new request: I remain stuck at login stage.
EDIT 1: here are the steps I identify based on logs and debugging:
1) user tries to access /foo/user/secured/target, for which you need to be identified at least with ROLE_USER to access
2) firewall intercepts this request, as it matches listened routes (app/config/security.yml):
secured_area:
pattern: ^/foo/user/secured/
3) it redirects toward login route
4) user fills in with username and password, and submits post
5) when form is received, a token gets created by createToken method of custom authenticater. It returns an object of class UsernamePasswordToken created with parameter username, password in clear, authenticater key: UsernamePasswordToken($username, $password, $providerKey)
6) token gets passed onto authenticateToken method de of authenticater object. this method compares clear password hash contained in token andd accessed through $token->getCredentials()) with hashed password in database.
7) authentication worked: we get redirected toward /foo/user/secured/target . token and user get serialized in session (ISSUE STARTS HERE: indeed, user clear password is erased so that it doesn't leave tracks in session, and getCredentials() will return empty string now).
8) while loading page, le firewall is activated. It detects user logged in, seems to want to check its token. Therefore, it calls authenticateToken.
9) authenticateToken tries to compare sha1($token->getCredentials()) to hashed password in database. comme $token->getCredentials() is empty, comparison fails. authenticateToken raises an exception.
10) raised exception triggers firewall redirection toward login page. There we are: stuck in infinite loop landing systematically on login page.
STOP EDIT 1.
Solution
Does anyone know why this change of behaviour between 'form_login' and 'simple_form'? Most of all, would you know a good way to fix this ? I guess authenticate method or custom authenticater should be slightly changed, but I am not yet confident enough with security to solve this elegantly.
Many thanks in advance.
Kind regards,
Wisebes
You have to use some string (not the object) from sample. Or implement __toString() for User entity.
NOT
return new UsernamePasswordToken($user, ...
USE
return new UsernamePasswordToken($user->getEmail() or whatever, ...
if you want to access to the page you was requesting, you could use any of the options that Symfony offers to you:
Redirecting after Login:
always_use_default_target_path (type: Boolean, default: false)
default_target_path (type: string, default: /)
target_path_parameter (type: string, default: _target_path)
use_referer (type: Boolean, default: false)
You could see the section of the book 'SecurityBundle Configuration ("security")'
http://symfony.com/doc/current/reference/configuration/security.html
I hope that this be useful for you.
Kind regards.
well, as I was not able to make it work fine, I created my own custom authentication provider. I hope the issue reported above will be fixed asap. If anyone has got an answer, I still am interested!
For other people facing the same issue, I recommend creating a custom authentication provider. You may even inherit from existing authentication provider, and therefore limit modifications to be done. All in all, you are able to add your custom logic with a limited amount of trouble that way.
I found this library for creating an ACL (access control list) for mongoose:
https://github.com/scttnlsn/mongoose-acl
It looks like a good module, but I'm a little confused on how to use it for my purpose.
I have a site where anybody (logged in or not) can visit a profile page, like example.com/users/chovy
However if the user 'chovy' is logged into this page, I want to give them admin privileges for editing the details of the account.
If the user is not 'chovy' or is not logged in, they would just see the read-only profile page for 'chovy'.
Can someone give me a concrete example of how I would do this?
That sounds so common, that I don't think you need an ACL. You will need to have sessions, and then you can change how the view looks based upon the current logged in user. An incomplete example would like like this:
// Assumes:
// - You set req.session.user when user logs in
// - The url route has a :name so you can do req.param() to get the name of the page being viewed
db.users.getCurrentUser(req.session.user, gotLoggedInUser)
db.users.getUserByName({name: req.param('name')}, gotUser)
And then pass this to the view, when you do a res.render():
var is_viewing_own_page = currentUser._id.toString() === loggedInUser._id.toString()
And then the view can do something like this (assuming jade):
- if (is_viewing_own_page)
div You are looking at your own page
- else
div You are viewing someone else's page
Is there a way I can store when was the last time a user logged in?
I'm using symfony2, and everything's working alright with the security configuration.
I've seen this Security and login on a Symfony 2 based project, which is a similar question, but it just doesn't fit my needs.
Is there any other solution?
You can create an AuthenticationHandler that Symfony will call when user login successfully, you can save the login time into a User entity property (supposing that you have this scenario).
First, create the success authentication handler:
namespace Acme\TestBundle\Handler;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\DependencyInjection\ContainerAware;
class AuthenticationHandler extends ContainerAware implements AuthenticationSuccessHandlerInterface
{
function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$token->getUser()->setLoginTime(new \DateTime());
$this->container->get('doctrine')->getEntityManager()->flush();
return new RedirectResponse($this->container->get('router')->generate('login_success'));
}
}
Then you need to register the authentication handler as a service in a configuration file, for example, src/Acme/TestBundle/resources/Config/services.yml
services:
authentication_handler:
class: Acme\TestBundle\Handler\AuthenticationHandler
calls:
- [ setContainer, [ #service_container ] ]
And configure the login form to use the created handler, check out your security.yml
form_login:
success_handler: authentication_handler
Obviously, for this to work, you need to have a User entity with a loginTime property and the corresponding setter. And you need to configure the login to use the User entity repository as user provider and the DaoAuthenticationProvider, as explained here: http://symfony.com/doc/current/book/security.html#loading-users-from-the-database.
A quite simple solution would be to implement FOSUserBundle in your application as each user entry in the database has (amongst other things) a "last_login" field.
I am developing an application using cakePHP v 1.3 on windows (XAMPP).
Most of the controllers are baked with the admin routing enabled. I want to secure the admin actions of every controller with a login page. How can I do this without repeating much ?
One solution to the problem is that "I check for login information in the admin_index action of every controller" and then show the login screen accordingly.
Is there any better way of doing this ?
The detault URL to admin (http://localhost/app/admin) is pointing to the index_admin action of users controller (created a new route for this in routes.php file)
Use the Authentication component. You can set it up just for admin routes with something like this:
// AppController::beforeFilter
function beforeFilter() {
if (isset($this->params['prefix']) && $this->params['prefix'] == 'admin') {
$this->Auth->deny('*');
...
}
}
Checking only in the index actions is pointless, that's just obscurity, not security. The AuthComponent will check permissions for every single page load.