I'm building an app with silex and I'm using the built-in SecurityServiceProvider and I'm trying to use the rememberme service and I'm looking at the documentation and there a option called token_provider but symfony doesn't really state if that is a string or if its an instance of an object.
any help will be appreciated.
This parameter is a service id of a token provider to use. Services id are strings (then Symfony looks for the class in the DIC, Silex does the same) so you need to declare a FQDN of your token provider class. By default Symfony uses the Symfony\Component\Security\Core\Authentication\RememberMe\InMemoryTokenProvider class
If you want to create your own (probably you won't), you can take a look at how Doctrine Project programed this service by implementing the TokenProviderInterface.
Related
In a nutshell I'm in the process of upgrading a .NETStandard 2.1 app to .NET 6. Plus upgrading the various libraries accordingly, in particular MassTransit v5 to v8, and AutoFac 4.9.4 to 6.4.0.
This is a multi-tenant application where one instance is shared by multiple tenants, and each tenant has their own database.
The upgrade has gone well apart from one snag. The application uses the, no longer available, AutofacReceivedEndpointExtensions to setup the Tenant details in the Consumer, and I am struggling to find a way to replicate the functionally it provides.
Below is the key bit of code.
config.ReceiveEndpoint(host, azureBusConfig.QueueName, endpoint =>
{
ConfigureConsumer<MyConsumer>(endpoint, componentContext);
});
private static void ConfigureConsumer<TConsumer>(IServiceBusReceiveEndpointConfigurator endpoint, IComponentContext componentContext, Action<IConsumerConfigurator<TConsumer>> configure = null)
where TConsumer : class, IConsumer
{
endpoint.Consumer(componentContext, configure, configureScope: (container, context) =>
{
var tenantName = context.Headers.Get<string>("tenant");
var userId = context.Headers.Get<int>("userId");
container.RegisterInstance(new NamedTenantInfoProvider(tenantName, userId)).As<ITenantInfoProvider>();
});
}
The endpoint.Consumer method as shown is no longer provided.
The ITenantInfoProvider interface is injected into various constructors in the application e.g., to setup the dbContext for a tenant to point to the correct database.
public interface ITenantInfoProvider
{
string GetTenantName();
int? GetUserId();
}
There are two implementations of the ITenantInfoProvider. The NamedTenantInfoProvider which is used to set the Tenant from the received message, above.
There is also a RequestTenantInfoProvider, that gets the Tenant from the HttpRequest. e.g. via api call.
The RequestTenantInfoProvider is registered as follows
builder.RegisterType<RequestTenantInfoProvider>()
.As<ITenantInfoProvider>()
.InstancePerLifetimeScope();
So, what should happen is that the RequestTenantInfoProvider is injected into the constructors by default, but when a message is being consumed the NamedTenantInfoProvider instance is injected instead.
I have tried to register the NamedTenantInfoProvider as per the RequestTenantInfoProvider. Then inject an IEnumerable into the constructors. And set the Tenant in the consumer.ConfigureConsumer on the Named instance. Then use which ever instance has a Tenant set in the code. However, the NamedTenantInfoProvider instance is set after it is required in the other constructors e.g., dbContext.
The only way I can get the application to fully work is to hardcode a Tenant name in the NamedTenentInfoProvider class.
I was hoping that someone has already refactored some similiar code to replace the endpoint.ConfigureConsumer call and can advise a solution.
It may be that I'm missing a bit of knowledge regarding how scoping works with the Microsoft Dependency Injection/MassTransit configuration. Note: I didn't write the original application, and this is my first dabble with Mass Transit as well.
MassTransit v8 (and onward) only support IServiceCollection, which is part of Microsoft.Extensions.DependencyInjection. Third-party containers are no longer directly supported.
There is a Scoped Filter sample that might help you understand how scopes work with MSDI. The token concept is similar to that used by developers injecting "tenant info" into consumers.
I am trying to implement key rollover in IdentityServer but it seems the keys are only configured during startup.
The Crypto docs say that I should use AddValidationKeys. I can find out how to use them during startup in the startup docs and that works perfectly fine.
Is it possible to use AddValidationKeys during runtime to handle key rollover so I do not have to restart the service to roll over the keys?
It should be possible, but not out of the box. Identity Server 4 is extremely extensible and in regards to signing keys, it uses ISigningCredentialStore to retrieve the configured token signing keys. By default, it looks like it just injects and returns whatever you configure in the Startup.
You will need to create your own implementation of ISigningCredentialStore and add it to the DI. Identity Server 4 should then use the store to dynamically retrieve keys at runtime based on your business logic.
public class CustomSigningCredentialsStore : ISigningCredentialStore
{
public Task<SigningCredentials> GetSigningCredentialsAsync()
{
// Your business logic to retrieve signing keys at runtime
}
}
Before Symfony 3.3 it was allowed to set a mocked service onto the container. Now with 3.3 a deprecation warning is thrown because the service is already pre-defined.
What is the new standard way to overwrite an existing or pre-defined service in the container to set a mocked service for a functional test?
E.g. in our case we set a new entity manager with a new mocked connection pointing to a cloned database for testing.
$container->set('doctrine.orm.entity_manager', $testEm);
Setting the "doctrine.orm.entity_manager" pre-defined service is deprecated since Symfony 3.3 and won't be supported anymore in Symfony 4.0.
I had the very same problem just a few days ago and I wrote a library to trick Symfony's DIC: https://github.com/TiMESPLiNTER/proxy-mock
The idea is to override the service in the config_test.yml with a "proxy" from the original service class which redirects all the calls to a mock which then can be set dynamically in the test case.
# config_test.yml
services:
timesplinter.proxy_mock.factory:
class: timesplinter\ProxyMock\ProxyMockFactory
acme.api.client:
factory: 'timesplinter.proxy_mock.factory:create'
arguments: ['Acme\AppBunde\Services\ApiClient']
This will override the service defined in the original service.(xml|yml) with a proxy of it.
In the test case you can then do something like this:
// Your container aware test case (this exmaple is for PHPUnit)
$mock = $this->getMockBuilder(ApiClient::class)->disableOriginalConstructor()->getMock();
$container->set('acme.api.client')->setMock($mock);
With this your test will run against the mock you provide using the setMock() method.
The library is very new so some feature may be missing. If you use it and miss something please provide a pull request with the desired feature.
Is there a way to access the configuration parameters in config.yml from the model layer? From the controller I can use $this->container->getParameter('xyz'). But how can it be done from a class in the Model layer?
In symfony2 Entities are designed as POPOs, meaning that they shouldn't really have access to anything outside of their scope.
If you need some config option in one of your entities, consider passing it as a parameter from the controller like so:
$entityName->methodName($param1, $this->container->getParameter('xyz'));
This could (will) break DIC pattern, but you could use a singleton class to "globalize" what you need.
To feed your globals, use bootmethod from Bundle class (where you can access DIC stuff hence configuration).
Or more simple, add a static field to your Entity.
Quick & dirty solution, don't abuse it ;-)
You can use Dependency Injection and add your model to your services.yml file, and like every other service you make you can provide other services as constructor parameters. The only downside is you call $derp = $this->get("your_service_name"); instead of $derp = new Derp();.
For example:
# src/Derp/LolBundle/Resources/config/services.yml
services:
derp:
class: \Derp\LolBundle\Entity\Message
arguments: [#service_container]
#service_container is a service found using php app/console container:debug. It will function identically to $this->container in your controllers and it is provided to the constructor of your class. See here for more information on how to use service containers.
As previously mentioned they are POPOs (Plain Old PHP Objects) and the previous method of dependency injection is poor choice simply because you will have to remember to provide your model entity with the same object every time you use it (which is a hassle) and Symfony2 services are a way to mitigate that pain.
I'm building a site that relies quite heavily on a third party API so I thought it would make sense to package up the API wrapper as a service, however I'm starting to find instances where it would be useful to have access to it outside of a controller such as in an entity repository.
Also related to that is it would be useful to be able to get access to config values outside of a controller (again such as in an entity repository).
Can anyone tell me if this is possible and if not is there a suggested approach to doing this kind of thing?
thanks for any help
The Symfony distribution relies heavily on dependency injection. This means that usually, dependencies are injected directly into your object via the constructor, the setters or via other means (like reflection over properties). Your API wrapper service is then a dependency for other objects of your application.
That being said, it would be rather difficult to inject this service in an entity repository's constructor because it already requires some other parameters and I think it would not be possible to inject them because of the way we request the repository for an entity.
What you could do is to create another service which will be responsible of doing the work you were about to do in the entity repository. This way, you will be able to inject the entity manager, which will be used to retrieve the entity repository, you custom service and also another service holding your configuration values (There are other ways to share configuration values).
In my use case, I use a Facebook helper service that wraps Facebook API calls. This service is then injected where I need it. My entity repository is only responsible of doing database calls so it receives only the arguments it needs and not the whole dependency. Thus, it will not receive the helper but rather only the arguments needed to do a request, for example, a Facebook user id. In my opinion, this is the way to do it since I think the entity repository should not have dependencies on such helper objects.
Here a small example using YAML as the configuration:
# app/config/config.yml
services:
yourapp.configuration_container:
class: Application/AcmeBundle/Common/ConfigurationContainer
# You could inject configurations here
yourapp.api_wrapper:
class: Application/AcmeBundle/Service/ApiWrapperService
# Inject other arguments if needed and update constructor in consequence
yourapp.data_access:
class: Application/AcmeBundle/Data/Access/DatabaseAccessService
arguments:
entityManager: "#doctrine.orm.entity_manager"
apiWrapperService: "#yourapp.api_wrapper"
configuration: "#yourapp.configuration_container"
# Application/AcmeBundle/Common/ConfigurationContainer.php
public ConfigurationContainer
{
public function __construct()
{
// Initialize your configuration values or inject them in the constructor
}
}
# Application/AcmeBundle/Service/ApiWrapperService.php
public ApiWrapperService
{
public function __construct()
{
// Do some stuff
}
}
# Application/AcmeBundle/Data/Access/DatabaseAccessService.php
public DatabaseAccessService
{
public function __construct(EntityManager $entityManager, ApiWrapperService $apiWrapperService, ConfigurationContainer $configuration)
{
...
}
}
The at sign (#) in the config.yml file means that Symfony should inject another service ,having the id defined after the at sign, and not a simple string. For the configuration values, as I said previously, there is other means to achieve the same goal like using parameters or a bundle extension. With a bundle extension, you could define the configuration values directly into the config.yml and your bundle would read them.
In conclusion, this should give you the general idea of injecting services. Here a small list of documentation on the subject. Alot of links use the XML service definition instead of the YAML definition but you should be able to understand them quite easily.
Symfony Official DI
Fabien Potencier's articles on DI
Richard Miller's articles on DI (Check in his blog for the other DI articles)
Take note that the configuration I'm giving is working for Beta1 of Symfony2. I didn't update yet to Beta2 so there could be some stuff not working as they are in the Beta2 version.
I hope this will help you defining a final solution to your problem. Don't hesitate to ask other questions if you want clarifications or anything else.
Regards,
Matt
I would wrap this kind of behavior in a Symfony service(like a manager).
i would not inject any parameters or logic into the entity repositories, as they should mainly be used to fetch data using object manager queries.
I would put the logic in the services and if the service , require a database access it will call the entity repository to fetch data.