Symfony2, Security, registration and isEnable error - security

Guys there is a description about how to make 'isEnabled' (active\inactive account) on registration.
http://symfony.com/doc/current/cookbook/security/entity_provider.html#forbid-inactive-users
But there is NO description how to get this error on login action. For example I have working properly registration where user account default is inactive. After user login how can I get "inAcitve" if account is not activated by email link?

Is pretty easy: you can create a service that will act as a event listener
# app/config/config.yml
services:
your_bundle_name.login_listener:
class: FQN\Of\Your\Bundle\Class\Listener
tags:
- { kernel.event_listener, security.interactive_login}
tags part is there because, on bootstrap of your application, kernel will "attach" certain type of events to your service and will call a method on that service each time this event is raised.
So kernel.event_listener is there because every event listener have to be tagged that way (follow it as a "rule") and security.interactive_login will be fired as a user succesfully log in.
Your class could be something like
//omitting class declaration on purpose
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
$user = $event->getAuthenticationToken()->getUser();
if (!$user->isActive()) {
//do the proper action to display the error
}
}

Related

Unable to accept the permission prompt on Actions on Google

I am trying to get permissions for location and name for my app.
Here is my index.js - link
It seems to be stuck in a loop :-
Here are my intents on API.AI :-
The event actions_intent_PERMISSION needs to be attached to an Intent that will be called after the user authorizes the information to be sent. The handling for it in the webhook needs to read the information given and save it or do something with it immediately.
Your code is looping because the code that is processing the request_permission action is, itself, requesting permission:
function requestPermission(app){
const permissions = [
app.SupportedPermissions.NAME,
app.SupportedPermissions.DEVICE_PRECISE_LOCATION
];
app.askForPermissions('To pick you up', permissions);
}
So you will need:
A new intent
that has actions_intent_PERMISSION set for the event
that has a new action string associated with it
and maps to a new function that handles the information that the user has consented to.

Subscription model using symfony3

I'm trying to set up a subscription site using symfony. I want to be able to offer say 3 articles free to users with ROLE_USER but then direct them to a subscribe option if they want to view more articles. I'm having trouble figuring out how to implement this with the security system.
I suspect I'll need a custom voter. Is that the route I should be looking? Then perhaps a custom access.denied.handler as well.
I'm mostly unsure about how to implement this using voters. Is that the way to go?
If they will need to login (as you talk about Roles then they will probably need) then you can do it with request listener and de-increment number of free articles on every article page load (or if you want to allow refreshing article page without touching limit again then you will need to implement some storage for user-read-articles and disable free reading after opening 3 different articles by user).
You need to implement request event listener (read more about events here: http://symfony.com/doc/current/components/http_kernel/introduction.html#the-kernel-request-event):
<?php
namespace App\AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class FreeReadingListener
{
/**
* #param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
// don't do anything if it's not the master request
return;
}
// check if loaded route is article route
// check if user can read articles for free (can be as some kind flag) - if can't then redirect to subscriptions page
// log user article read
// if user used limit - switch free reading flag on user
}
}
services.yml
services:
app_bundle.listener.free_reading:
class: App\AppBundle\EventListener\FreeReadingListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Listener docs: http://symfony.com/doc/current/cookbook/event_dispatcher/event_listener.html

Logged in user can only access 1 page?

Using Orchard 1.6 Iv created a new role 'FactoryWorker'. When this user logs in from the front end I want them to be navigated to one page only.
OrchardLocal/System/ManufacturedProducts
I have set this page to be a print screen of the order details so the factory worker will know what products to get ready for ship out & they wont be able to navigate as no menu appears, but also need the other pages blocked incase the user decides to enter the URL of a page they arnt allowed access to.
This is the only page I want this particular user to be able to access(after they login), and I have added a logout button, which logs out the user and returns them to the home page.
So iv been looking through editing a role, with permissions and content etc...but this all seems to be applying to forms and content in general. where the user can access any content type etc...
So can someone advise me on how to do this?
thanks for any replies
UPDATE
I forgot to mention that this is not a content type, item or part I am talking about.
I have created my own controller & View & VM which is accessible from the dash board (using the AdminMenu, which brings the admin user to OrchardLocal/System/ManufacturedProducts)
I have looked at Orchard.ContentPermissions Feature but it only seems to allow me to 1)Grant permissions for others or 2)Grant permission for own content
any ideas?
You can use a Request Filter, (I do not know if it is the best way) :
FilterProvider – defines the filter applied to each request. Resembles the way default ASP.NET MVC action filters work with the difference that it’s not an attribute. All FilterProvider objects are injected into the request pipeline and are applied to all requests (so you need to check if the current request is suitable for your filter at the beginning of an appropriate method).
From : http://www.szmyd.com.pl/blog/most-useful-orchard-extension-points
So you could implement something like this
public class Filter : FilterProvider, IAuthorizationFilter {
private readonly IAuthenticationService _authenticationService;
public Filter(IAuthenticationService authenticationService) {
_authenticationService = authenticationService;
}
public void OnAuthorization(AuthorizationContext filterContext) {
//If route is the restricted one
if (filterContext.HttpContext.Request.Url.AbsoluteUri.Contains("OrchardLocal/System/ManufacturedProducts")) {
//Get the logged user
IUser loggedUser = _authenticationService.GetAuthenticatedUser();
if (loggedUser == null)
return filterContext.Result = new HttpUnauthorizedResult();
//Get the Roles
var roles = loggedUser.As<IUserRoles>().Roles;
if (!roles.Contains("FactoryUser")) {
//User is not authorized
return filterContext.Result = new HttpUnauthorizedResult();
}
}
}
}
Note: Untested code!
EDIT: Also you could invert the logic and check if the logged user has the role 'FactoryUser' and restrict its access to every page except the one they should see.
Your module can create a new permission (look at one of the permissions.cs files for examples), then create a role that has only that permission. Have your controller action check that permission (again, many examples found by finding usage of the permissions defined in one of the permissions.cs).
You can use the Content Permissions module. Using this module you can attach a content item permission part to a content type. This part allows you to choose which roles can see the content when you create it.

Can a Domain Event return feedback information up to the UI layer?

I'm still fairly new to DDD applications. I'm reading Eric Evan's "Domain Driven Design" and have read Employing the Domain Model Pattern by Domain Events Salvation by Udi Dahan...
One thing I can't make out though is how should information about the successful or unsuccesful completion of Domain Events be returned as feedback to the user (i.e. UI Layer)?
For example, we could have the following Application Layer code:
// Application Layer
public void SubmitOrder(OrderData data)
{
var customer = GetCustomer(data.CustomerId);
var shoppingCart = GetShoppingCart(data.CartId);
customer.Purchase(shoppingCart);
}
// Domain Model
public class Customer
{
public void Purchase(ShoppingCart cart)
{
// something done with the cart...
DomainEvents.Raise(new CustomerPurchaseCompleted() { Customer = this, ShoppingCart = cart });
}
}
Now let's say we have the following event handler that sends a confirmation email to the customer if the customer has an email address specified.
public class CustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email != null) {
// send email to args.Customer
}
else {
// report that no email will be sent...
}
}
}
My question is: How should I "bubble up" a feedback message to the UI layer saying that no email will be sent because the customer doesn't have an email set?
The options as I see them today are along the lines of:
Have the UI layer check if the Customer has an email and react accordingly with a message. This seems bad since the UI would be aware that an email is supposed to be sent, which is a application level information.
Throw a UserHasNoEmailException when no email is present and catch that information somewhere. That's really bad because exceptions should not be used to return information, plus it's not a fatal error and should not abort other handlers...
Have SubmitOrder() return some List<FeedbackMessage>. This would require changing the Purchase() and DomainEvents.Raise() methods to also return this list. This leads to the Domain Model knowing what the UI should of should not display...
Neither of these three options seems really good and practical. So how do DDD experts do it?
Thanks.
Another option you have is to implement another event handler which is specifically responsible for notifying the UI that a customer doesn't have an email address. So where CustomerPurchaseCompletedHandler doesn't send an email, this handler would notify the UI. This handler would be part of the UI layer. A good way to notify the UI would be to inject an event aggregator into this handler:
public class NotifyingCustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public IEventAggregator Events { get; set; }
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email == null) {
// notify UI
this.Events.GetEvent....
}
}
}
Overall, this is essentially approach 1. True, the UI layer is now aware that an email is to be sent, however the UI has to have that knowledge regardless because it needs to render a message stating that no email is to be sent. Display a message is a UI concern and by leaving the handler implementation as part of the UI layer you keep it as such. The problem with this approach is that you are checking whether the customer has an email twice. Additionally, the sending of an email is not directly tied to the UI notification.
Another option is to introduce another event to indicate that a purchase was completed for a customer that doesn't have an email. The UI could then subscribe to this event. The downside of this approach is that you are creating an event specifically for a UI requirement not to express domain knowledge.
Events should not report feedback. Events ARE feedback.
In this case the Email is a business requirement. So the customer.Purchase(shoppingCart); should really throw an exception if the email has not been specified.
But let's say that the actual email delivery fails. What I usually do is to create a domain model which I use for notifications. so I do this:
var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);
Which in turn would generate a NotificationCreated event which can be picked up by the UI.

Symfony2 Login and Security

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.

Resources