I am new to IdentityServer and am having a little trouble setting this up.
For reasons I won't go into here I can't use ASP.NET Identity or EntityFramework. I have a custom database for users that I need to authenticate against so I took the samples and tried to switch out the InMemoryUsers for a custom persistence store.
Here is my ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer(options =>
{
options.AuthenticationOptions = new IdentityServer4.Configuration.AuthenticationOptions
{
};
})
.AddInMemoryClients(Clients.Get())
.AddInMemoryScopes(Scopes.Get())
.SetTemporarySigningCredential();
services.AddMvc();
services.AddTransient<ISignInService, SignInService>();
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<IUserService, UserService>();
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddTransient<IProfileService, ProfileService>();
}
I know this method is imperfect as I am still testing some things, but when I run the application I get this error:
System.InvalidOperationException
No storage mechanism for grants specified. Use the 'AddInMemoryStores' extension method to register a development version.
Obviously I don't want to use in memory stores for a production implementation, but I am not sure what I need to do to fix this.
AddInMemoryStores does not have the best name. It actually adds the store for all the transient data that relates to issued materials/tokens.
We use it in production sometimes because a lot of the time we don't really need to persist this data to disk, and we don't use long lived tokens.
Take a look at what the extension method does here and look at what the IPersistedGrantStore contract looks like to get a better idea.
Related
I have an ASP .NET Core project integrated with Sentry:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseSentry(options =>
{
options.Dsn = Environment.GetEnvironmentVariable("SENTRY_DSN");
options.Debug = true;
});
});
}
I can see all exceptions being logged as Issues in Sentry. I cannot see however, any transactions logged, even if I make plenty of REST API calls.
According to Sentry's documentation, this setup should be sufficient.
Sentry's performance monitoring features are opt-in and need to be enabled separately. In addition to calling UseSentry as you showed, you should also do the following to capture transactions:
Configure the sample rate by setting the TracesSampleRate in either the call to UseSentry or in your appsettings.json file. For example, options.TracesSampleRate = 1.0 will send traces for 100% of your transactions. This is fine for dev/test, but in production you will likely want to use a much lower rate such as 0.2 (20%).
Optionally, you can also set a TracesSampler function that can be used if you have more complex logic for deciding whether to sample or not.
Configure automatic instrumentation by calling UseSentryTracing in the Configure section of your Startup class. Add this after UseRouting, which should already be there. This adds Sentry's tracing middleware to the ASP.NET Core pipeline to collect traces from each request and response.
If desired, you can add custom instrumentation around other parts of your code, by creating additional transactions and spans.
Also, just FYI, if you're planning on using the SENTRY_DSN environment variable, then you don't need to also set options.Dsn in code. It will be picked up automatically.
I am experimenting with a gRPC service and client using proto files. The advice is to use gRPC client factory integration in .NET Core (https://learn.microsoft.com/en-us/aspnet/core/grpc/clientfactory?view=aspnetcore-3.1). To do this you register the client derived from Grpc.Core.ClientBase that is generated by the Grpc.Tools package, like this:
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddGrpcClient<MyGrpcClientType>(o =>
{
o.Address = new Uri("https://localhost:5001");
});
})
My understanding is that MyGrpcClientType is registered with DI as a transient client, meaning a new one is created each time it is injected, but that the client is integrated with the HttpClientFactory, allowing the channel to be reused rather than be created each time.
Now, I would like to use protobuf-net.grpc to generate the client from an interface, which appears to be done like this:
GrpcClientFactory.AllowUnencryptedHttp2 = true;
using var http = GrpcChannel.ForAddress("http://localhost:10042");
var calculator = http.CreateGrpcService<ICalculator>();
If I am correct in thinking that channels are expensive to create, but clients are cheap, how do I achieve integration with the HttpClientFactory (and so reuse of the underlying channel) using protobuf-net.grpc? The above appears to create a GrpcChannel each time I want a client, so what is the correct approach to reusing channels?
Similarly, is it possible to register the protobuf-net.grpc generated service class with the below code in ASP.Net Core?
endpoints.MapGrpcService<MyGrpcServiceType>();
(Please correct any misunderstandings in the above)
Note that you don't need the AllowUnencryptedHttp2 - that's just if you aren't using https, but: you seem to be using https.
On the "similarly"; that should already work - the only bit you might be missing is the call to services.AddCodeFirstGrpc() (usually in Startup.cs, via ConfigureServices).
As for the AddGrpcClient; I would have to investigate. That isn't something that I've explored in the integrations so far. It might be a new piece is needed.
The Client Factory support not exists, and works exactly like documented here except you register with the method
services.AddCodeFirstGrpcClient<IMyService>(o =>
{
o.Address = new Uri("...etc...");
});
I have a base abstract context which has a couple hundred shared objects, and then 2 "implementation" contexts which both inherit from the base and are designed to be used by different tenants in a .net core application. A tenant object is injected into the constructor for OnConfiguring to pick up which connection string to use.
public abstract class BaseContext : DbContext
{
protected readonly AppTenant Tenant;
protected BaseContext (AppTenant tenant)
{
Tenant = tenant;
}
}
public TenantOneContext : BaseContext
{
public TenantOneContext(AppTenant tenant)
: base(tenant)
{
}
}
In startup.cs, I register the DbContexts like this:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
Then using the autofac container and th Multitenant package, I register tenant specific contexts like this:
IContainer container = builder.Build();
MultitenantContainer mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);
mtc.ConfigureTenant("1", config =>
{
config.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
});
mtc.ConfigureTenant("2", config =>
{
config.RegisterType<TenantTwoContext>().AsSelf().As<BaseContext>();
});
Startup.ApplicationContainer = mtc;
return new AutofacServiceProvider(mtc);
My service layers are designed around the BaseContext being injected for reuse where possible, and then services which require specific functionality use the TenantContexts.
public BusinessService
{
private readonly BaseContext _baseContext;
public BusinessService(BaseContext context)
{
_baseContext = context;
}
}
In the above service at runtime, I get an exception "No constructors on type 'BaseContext' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'". I'm not sure why this is broken....the AppTenant is definitely created as I can inject it other places successfully. I can make it work if I add an extra registration:
builder.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
I don't understand why the above registration is required for the tenant container registrations to work. This seems broken to me; in structuremap (Saaskit) I was able to do this without adding an extra registration, and I assumed using the built in AddDbContext registrations would take care of creating a default registration for the containers to overwrite. Am I missing something here or is this possibly a bug in the multitenat functionality of autofac?
UPDATE:
Here is fully runable repo of the question: https://github.com/danjohnso/testapp
Why is line 66 of Startup.cs needed if I have lines 53/54 and lines 82-90?
As I expected your problem has nothing to do with multitenancy as such. You've implemented it almost entirely correctly, and you're right, you do not need that additional registration, and, btw, these two (below) too because you register them in tenant's scopes a bit later:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
So, you've made only one very small but very important mistake in TenantIdentitifcationStrategy implementation. Let's walk through how you create container - this is mainly for other people who may run into this problem as well. I'll mention only relevant parts.
First, TenantIdentitifcationStrategy gets registered in a container along with other stuff. Since there's no explicit specification of lifetime scope it is registered as InstancePerDependency() by default - but that does not really matter as you'll see. Next, "standard" IContainer gets created by autofac's buider.Build(). Next step in this process is to create MultitenantContainer, which takes an instance of ITenantIdentitifcationStrategy. This means that MultitenantContainer and its captive dependency - ITenantIdentitifcationStrategy - will be singletons regardless of how ITenantIdentitifcationStrategy is registered in container. In your case it gets resolved from that standard "root" container in order to manage its dependencies - well, this is what autofac is for anyways. Everything is fine with this approach in general, but this is where your problem actually begins. When autofac resolves this instance it does exactly what it is expected to do - injects all the dependencies into TenantIdentitifcationStrategy's constructor including IHttpContextAccessor. So, right there in the constructor you grab an instance of IHttpContext from that context accessor and store it for using in tenant resolution process - and this is a fatal mistake: there's no http request at this time, and since TenantIdentitifcationStrategy is a singleton it means that there will not ever be one for it! So, it gets null request context for the whole application lifespan. This effectively means that TenantIdentitifcationStrategy will not be able to resolve tenant identifier based on http requests - because it does not actually analyze them. Consequently, MultitenantContainer will not be able to resolve any tenant-specific services.
Now when the problem is clear, its solution is obvious and trivial - just move fetching of request context context = _httpContextAccessor.HttpContext to TryIdentifyTenant() method. It gets called in the proper context and will be able to access request context and analyze it.
PS. This digging has been highly educational for me since I had absolutely no idea about autofac's multi-tenant concept, so thank you very much for such an interesting question! :)
PPS. And one more thing: this question is just a perfect example of how important well prepared example is. You provided very good example. Without it no one would be able to figure out what the problem is since the most important part of it was not presented in the question - and sometimes you just don't know where this part actually is...
Net Core policy authorization, however it is looking very static to me. Because in the Enterprise Application, there is an often need for new roles which will need new policies (as far as i understand) or if you want to implement new type of policy specific for certain client. For example if we are building an CMS which will be driven by those policies, we will want, each client to be able to define hes own. So can this new policy base mechanism be more dynamic or, it's idea is entire different?
thanks :))
I always recommend that people take a look # the least privilege repo as it has some great examples of all the various approaches one can take with the new ASP.NET Core Authentication and Authorization paradigms.
Can this new policy base mechanism be more dynamic?
Yes, in fact, it is more dynamic than the previous role-based concepts. It allows you to define policies that can be data-driven. Here is another great resource for details pertaining to this. You can specify that an API entry point for example is protected by a policy (for example), and that policy can have a handler and that handler can do anything it needs to, i.e.; examine the current User in context, compare claims to values in the database, compare roles, anything really. Consider the following:
Define an entry point with the Policy
[Authorize(Policy = "DataDrivenExample")]
public IActionResult GetFooBar()
{
// Omitted for brevity...
}
Add the authorization with the options that add the policy.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("DataDrivenExample",
policy =>
policy.Requirements.Add(new DataDrivenRequirement()));
});
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
Then define the handler.
public class MinimumAgeHandler : AuthorizationHandler<DataDrivenRequirement>
{
protected override void Handle(
AuthorizationContext context,
DataDrivenRequirement requirement)
{
// Do anything here, interact with DB, User, claims, Roles, etc.
// As long as you set either:
// context.Succeed(requirement);
// context.Fail();
}
}
Is the idea entirely different?
It should feel very similar to the previous concepts that you're accustomed to with auth8 and authz.
The accepted answer is still quite limiting. It doesn't allow for dynamic values at the Controller and Action level. The only place a custom value could be added is in the requirement when the policy is added. Sometimes you need more fine grain control over the authorization process. A very common scenario is permission based security. Each controller and action should be able to specify the permissions required to access them. See my answer here for a more powerful solution that lets you use custom attributes to decorate your controllers and actions with any information you need while doing authorization.
I'm moving a Web Api 2 project to MVC 6, since Microsoft is merging the two APIs in ASP.NET 5. In my WebApi project I had a custom Attribute Filter class that would authenticate, authorize and prevent transaction replays using a combination of public key, private key and HMAC authentication (basically, doing this with some tweaks to fit into my project).
Now in MVC6, as far as I understand I must stop using anything in the Microsoft.Web.Http namespace and instead use Microsoft.AspNet.Mvc. So I have done that, but the Microsoft.AspNet.Mvc.Filters doesn't seem to have any equivalent of Web Api 2's IAuthenticationFilter.
This is a problem for me because my customer AuthenticationFilter implemented all of IAuthenticationFilter, with all the logic in there. More importantly, it was using the Context to temporarily store the public key of the account, so my controller could access it to load up the account in turn.
So my question is, what is the proper way to filter requests in MVC6, using an Authentication Filter-like class to intercept the requests and return the appropriate status codes? I can't find any article that goes specifically in these details (they all tend to cover MVC5).
I know it's an older question, but hopefully someone (maybe even yourself) might find value in the answer.
MVC6 does in fact have an alternative. You have an
public abstract class AuthorizationFilterAttribute :
Attribute, IAsyncAuthorizationFilter, IAuthorizationFilter, IOrderedFilter
which basically tells you, that you can create your custom class, derive it from this (namespace of all of these interfaces, btw, is Microsoft.AspNet.Mvc.Filters and that should be it. You can either decorate the action with it, or you can do this in Startup.cs, to apply to all actions:
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc(options =>
{
// add an instance of the filter, like we used to do it
options.Filters.Add(new MySpecialFilter());
});
services.AddTransient<LogFilter>();
}
If you want to use a bit more logic in the filter (e.g. my LogFilter above) which is instantiated through DI, you need to use either Service Filters or Type Filters.
You can now decorate the actions with [ServiceFilter(typeof(LogFilter))] or use o.Filters.Add(new ServiceFilterAttribute(typeof(LogFilter))); in the Startup.cs file. But keep in mind, to do this you need to register the type with the DI container, like I did above with the .AddTransient<>() call.
IAuthenticationFilter is no more and IAuthorizationFilter simply does not replace it in MVC 6
Reason: authentication is NOT EQUAL to authorization.
Therefore IMO the authentication filter should stay available!