How to access a Symfony service that is used by a client request in a web test case? - symfony

I have an application that relies on third party services. In order to make sure that the application works properly, I want to mock the third party services and make sure that the application is working as expected.
This requires that I am able to configure the mock services before creating the requests. However, I am unable to do so.
Consider the following code:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
//..
class MyTest extends WebTestCase
{
public function testSignupLink()
{
$container = static::createClient()->getContainer();
// This returns a different instance from the one used by the client request
$service = $container->get('third-party-service');
$service->setErrorState(MockService::SOME_ERROR_STATE);
// ...
// The request creates a new instance of the $service internally which doesn't have the error state that was set above
$client->request('POST', '/abc/1');
}
}
The 'abc' controller relies on a service that I can't access. When I access the service from the container, I get a different instance from the one that is used by the client request.
Is there any way to handle this?

If I correctly understood you, here is what you need:
https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer

Related

Understanding SignalR- Hubs, Dependency Injection, and Controllers

I've been pouring through documentation and forums trying to understand SignalR but I'm pretty stuck.
What I'm trying to achieve is, in a chat application: store messages outside of the Hub so that each time a user joins the chat, they can see all messages that had been sent before they joined.
So it seemed like an external class was the way to do that so I got that working with dependency injection
In ChatHub.cs
namespace SignalRChat.Hubs
{
public class ChatHub: Hub
{
public IChatStorage _chatStorage;
public ChatHub(IChatStorage chatStorage)
{
_chatStorage = chatStorage;
}
// and so on
And I have a method in ChatHub to send a message to chatStorage, but I'm confused on how to send back a list of all messages from chatStorage to ChatHub, or even to JavaScript. It seemed like a Controller was the way to do that but I'm not sure how to call the controller's methods:
namespace SignalRChat.Controllers
{
public class ChatController: Controller
{
private IHubContext<ChatHub> _hubContext;
public ChatController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
public void Send(List<Message> messages)
{
// to do: something where chatStorage calls this method, then this
// method uses _hubContext.Clients.All.SendAsync
// But, how do I even call Send()???
}
}
}
Fundamentally I just don't understand how to wire everything up. SignalR is just really confusing.
I get how the simple server Hub and client JavaScript relationship works. But, then with dependency injection I don't get why
public ChatHub(IChatStorage chatStorage)
{
_chatStorage = chatStorage;
}
works. I didn't change any code to say like new ChatHub(new IChatStorage). Microsoft's docs even say that SignalR only calls default Hub constructors.
In Startup.cs nothing seems to specify that I want to call ChatHub with a new chatStorage:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
services.AddSingleton<IChatStorage, ChatStorage>();
services.AddSingleton<ChatController>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// omitted some default code
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<ChatHub>("/chatHub");
});
}
So first question, how does that work? How does it know to pass an argument to the ChatHub constructor? I understand the services.AddSingleton part, just not how that gets "wired up".
Same thing with a controller class. How does the program know to pass an IHubContext object into its constructor? Where do you specify that?
Finally, how would you go about making this setup work? Current I'm trying to communicate from ChatHub->chatStorage->ChatController->ChatHub. And to do that I'm trying to pass a reference to chatController in chatStorage.
Not sure if it's clear what I'm asking. If anything I'm looking for a clear explanation on how these concepts all work together, rather than a specific solution to my code.
Thank you!
So first question, how does that work? How does it know to pass an argument to the ChatHub constructor? I understand the services.AddSingleton part, just not how that gets "wired up".
When SignalR instantiates your hub instance (the framework controls this, you don't), it will resolve any dependencies specified in your Hub's constructor. This is part of the dependency injection system that's part of .NET (as mentioned in the comments).
Same thing with a controller class. How does the program know to pass an IHubContext object into its constructor? Where do you specify that?
Same idea, but you didn't have to wire up IHubContext, that's something that AddSignalR does.
Finally, how would you go about making this setup work? Current I'm trying to communicate from ChatHub->chatStorage->ChatController->ChatHub. And to do that I'm trying to pass a reference to chatController in chatStorage.
It's not exactly clear to me what you want the interaction to be between the client and the server to both the hub and the controller.
What I'm trying to achieve is, in a chat application: store messages outside of the Hub so that each time a user joins the chat, they can see all messages that had been sent before they joined.
Going back to this original statement I can ask a few clarifying questions:
When the user writes a message in the chat room, are you calling the hub or a controller action (REST API)? That will determine where you need to inject the IChatStorage type. Once you receive a message, you'll stash the message in IChatStorage.
When the user joins the chat, they'll make a call to the server to retrieve all messages. This call will return messages stored in IChatStorage.
Assuming you want to use the hub for everything, you would expose methods on the hub do accomplish this. If you wanted to use REST API calls from the client, then you would use the controller.

Symfony multicompany application

I need to set up several parameters after user authentication.
We have a db with with oauth2 clients.
When one of them got access token and is trying to get access to protected API I need to identify the client (which is easy since access_token is bound to particular client) and define several application parameters (actually I need to load a specific file parameters.yml depends on the client).
My questions is:
How can I hook to event when user is authenticated?
How can I load a particular parameters.yml and make it relevant after user authenticate ?
Thank you!
When user is successfully authenticated, you can write a listener which listens to SecurityAuthenticationEvents::AUTHENTICATION_SUCCESS.
The public method of the listener should look like this:
public function onAuthenticationSuccess(AuthenticationEvent $event)
{
/**
* #var User $user
*/
$user = $event->getAuthenticationToken()->getUser();
// ...
return;
}
I believe you can use YamlFileLoader for that. Of course you can create a service class to read the contents from yaml files and provide them to different services in your app. I would not try to mix them with regular parameter / config files.

spring-cloud with RestTemplate//Ribbon/Eureka - retry when server not available

I managed to successfully get my RestTemplate client discover remote service using Eureka and forward calls to it using Ribbon as described in the documentation.
Basically, it was just a matter of adding the following annotations of my Application class and let the magic of Spring-Boot do the rest:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableDiscoveryClient
(PS: you noticed I'm using spring-cloud:1.0.0-SNAPSHOT-BUILD and not 1.0.0.M3 - but this doesn't seem to affect my problem).
When two service instances are started, the rest-template client successfully load balance requests between the two. However, the client won't fallback to the second instance if the first is stopped before the Eureka load balancer notices, instead an exception is thrown.
Hence my question: is there a way to configure the RestTemplate/Ribbon/Eureka stack to automatically retry the call to another instance if the one selected the first place is not available? Zuul proxy and feign clients do this "out of the box" so I believe the library holds the necessary features...
Any idea/hint?
Thx,
/Bertrand
The RestTemplate support on its own does not know how to do any retrying (whereas the Feign client and the proxy support in Spring Cloud does, as you noticed). I think this is probably a good things because it gives you the option to add it yourself. For instance, using Spring Retry you can do it in a simple declarative style:
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
(and add #EnableRetry to your #Configuration). It makes a nice combination with #HystrixCommand (from Spring Cloud / Javanica):
#HystrixCommand
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
In this form, every failure counts towards the circuit breaker metrics (maybe we could change that, or maybe it makes sense to leave it like that), even if the retry is successful.
I couldn't get it to work with both #HystrixCommand and #Retryable, regardless of order of annotations on #Configuration class or on #Retryable method due to order of interceptors. I solved this by creating another class with the matching set of methods and had the #HystrixCommand annotated methods delegate to the corresponding #Retryable method in the second class. You could probably have the two classes implement the same interface. This is kind of a pain in the butt, but until order can be configured, this is all I could come up with. Still waiting on a real solution from Dave Syer and the spring cloud guys.
public class HystrixWrapper {
#Autowired
private RetryableWrapper retryableWrapper;
#HystrixCommand
public Response doSomething(...) {
return retryableWrapper.doSomething(...);
}
}
public class RetryableWrapper {
#Autowired
private RestTemplate restTemplate;
#Retryable
public Response doSomething(...) {
// do something with restTemplate;
}
}

Implementing Authorization in a Self Hosted SignalR Server accessed from Web

I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated

How can I get my WCF Service constructor called?

I'm currently trying to get my head around WCF services for an ASP.NET dev environment, and I believe that I'm doing well save for one thing that has me stumped.
Basically, I've got a WCF service set up (let's take the default, with an added constructor):
public class MyService : IMyService
{
public MyService() { /* blah */ }
public DoWork() { /* blah */ }
}
The IMyService interface defines the DoWork() method as an [OperationContract], as it should.
So I've got this service referenced in another project (let's say a [Unit] Test Project), via Add Service Reference on the VS2010 UI. This creates a reference to a MyServiceClient which exposes my WCF service methods, as it should.
However, when I do this in my test project:
ServiceReference.IMyService service;
service = new ServiceReference.MyServiceClient();
... the MyService() constructor does not get called, basically because I'm instantiating a MyServiceClient, not a MyService per se.
How do I go about getting that constructor called? I'm planning to use that for initialization purposes (perhaps grabbing a layer in a tiered implementation, for example?).
That constructor will be called on the server when you make your request from the client.
Creating a "reference" to a web service (and then using the client classes) is very different to referencing a regular .DLL. All of your service code will run on the server-side, but not until the service is invoked...
The only way for the server-side constructor to be called for each request is to set the InstanceContextMode to PerCall (in the ServiceBehavior attribute).

Resources