Using Microsoft.AspNetCore.Identity (.net 7 at time of writing), the default security stamp validation is not done anymore if I use a custom CookieAuthenticationEvents. Configuring the SecurityStampValidatorOptions has no effect either.
Why is this happening and what can be done to enable the security stamp validation?
program.cs
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.ConfigureApplicationCookie(options =>
options.EventsType = typeof(CustomCookieAuthenticationEvents)
);//this prevents securityStampValidation from occurring.
//set a small interval between validations so we can debug
builder.Services.Configure<SecurityStampValidatorOptions>(o => o.ValidationInterval = TimeSpan.FromSeconds(10));
builder.Services.Configure<SecurityStampValidatorOptions>(o => o.OnRefreshingPrincipal = c =>
{
//breakpoint here is hit if ConfigureApplicationCookie(options.EventsType) is NOT set
return Task.FromResult(0);
});
builder.Services.AddScoped<CustomCookieAuthenticationEvents>();
CustomCookieAuthenticationEvents.cs is an empty class for now
public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{ }
This behavior should be documented as it falls between two products.
The doc says
Events: The Provider may be assigned to an instance of an object created by the application at startup time. The handler calls methods on the provider which give the application control at certain points where processing is occurring. If it is not provided a default instance is supplied which does nothing when the methods are called.
EventsType: If set, will be used as the service type to get the Events instance instead of the property.
Fine, but let's not be misleaded by the events definition, as it is part of the namespace Microsoft.AspNetCore.Authentication.Cookies which is not the Identity namespace.
Instead, let's look at the code for IdentityServiceCollectionExtensions, which, among other things, does for AddIdentity
.AddCookie(IdentityConstants.ApplicationScheme, o =>
{
o.LoginPath = new PathString("/Account/Login");
o.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
})
So the cookie Events is set when adding Identity, and when we add our custom options.EventsType = typeof(CustomCookieAuthenticationEvents), the Events property is dismissed.
By looking at this code, we see that OnValidatePrincipal is the only event that is set, so we shouldn't have other unexpected missing functionalities. We also see that a static class is used to call the validation, so we can copy that into our CustomCookieAuthenticationEvents.
public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
public async override Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
await SecurityStampValidator.ValidatePrincipalAsync(context);
//optional custom code
}
}
Related
We are transitioning from Xamarin.Forms to .Net MAUI but our project uses Prism.Unity.Forms. We have a lot of code that basically uses the IContainer.Resolve() passing in a collection of ParameterOverrides with some primitives but some are interfaces/objects. The T we are resolving is usually a registered View which may or may not be the correct way of doing this but it's what I'm working with and we are doing it in backend code (sometimes a service). What is the correct way of doing this Unity thing in DryIoC? Note these parameters are being set at runtime and may only be part of the parameters a constructor takes in (some may be from already registered dependencies).
Example of the scenario:
//Called from service into custom resolver method
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", IObjectWithData)
};
//Custom resolver method example
var resolverOverrides = new List<ResolverOverride>();
foreach(var parameterOverride in parameterOverrides)
{
resolverOverrides.Add(parameterOverride);
}
return _container.Resolve<T>(resolverOverrides.ToArray());
You've found out why you don't use the container outside of the resolution root. I recommend not trying to replicate this error with another container but rather fixing it - use handcoded factories:
internal class SomeFactory : IProductViewFactory
{
public SomeFactory( IService dependency )
{
_dependency = dependency ?? throw new ArgumentNullException( nameof(dependency) );
}
#region IProductViewFactory
public IProductView Create( int productID, IObjectWithData objectWithData ) => new SomeProduct( productID, objectWithData, _dependency );
#endregion
#region private
private readonly IService _dependency;
#endregion
}
See this, too:
For dependencies that are independent of the instance you're creating, inject them into the factory and store them until needed.
For dependencies that are independent of the context of creation but need to be recreated for each created instance, inject factories into the factory and store them.
For dependencies that are dependent on the context of creation, pass them into the Create method of the factory.
Also, be aware of potential subtle differences in container behaviours: Unity's ResolverOverride works for the whole call to resolve, i.e. they override parameters of dependencies, too, whatever happens to match by name. This could very well be handled very differently by DryIOC.
First, I would agree with the #haukinger answer to rethink how do you pass the runtime information into the services. The most transparent and simple way in my opinion is by passing it via parameters into the consuming methods.
Second, here is a complete example in DryIoc to solve it head-on + the live code to play with.
using System;
using DryIoc;
public class Program
{
record ParameterOverride(string Name, object Value);
record Product(int productID);
public static void Main()
{
// get container somehow,
// if you don't have an access to it directly then you may resolve it from your service provider
IContainer c = new Container();
c.Register<Product>();
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", "blah"),
};
var parameterRules = Parameters.Of;
foreach (var po in parameterOverrides)
{
parameterRules = parameterRules.Details((_, x) => x.Name.Equals(po.Name) ? ServiceDetails.Of(po.Value) : null);
}
c = c.With(rules => rules.With(parameters: parameterRules));
var s = c.Resolve<Product>();
Console.WriteLine(s.productID);
}
}
Realms.Exception.RealmInvalidTransactionException: Cannot modify managed objects outside of a write transaction
I was using Ream .Net SDK 10.13 and recently updated it to 10.19.0. After, the update I am frequently getting the above error.
Here is an example of how I am using it in my Xamarin Forms project
public class TestClass: RealmObject
{
//Class properties are defined
// as per the realm docs, proper attributes
//are added for Kets and mapping
}
Now in some class/view models, where I have an instance of the TestClass injected through the constructor
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
var realm = Realms.Realm.GetInstance();
await realm.WriteAsync(async()=>{
// setting property of the TestClass
item.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
The above method call gives an exception. Above code is modified as per the new version.
The below code was as per the older version which was working fine but it started giving the same exception after the update
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
await item.WriteAsync(async i =>{
// setting property of the TestClass
i.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
I tried many ways to resolve this issue but none is working.
Any Suggestions/Help will be highly appreciated.
I'm using GraphQL on a .NET core website/controller. The schema is quite large, such that the constructor takes about a second to run. I couldn't have that kind of overhead on every request, so I created the schema as a singleton, shared between all requests.
public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
{
var executionOptions = new ExecutionOptions {
Schema = this.Schema, // dependency injected singleton
/* ... */
};
// ...
executionOptions.FieldMiddleware.Use(next => context =>
{
return next(context).ContinueWith(x=> {
var result = x.Result;
return doStuff(result);
});
});
var result = await new DocumentExecuter().ExecuteAsync(executionOptions).ConfigureAwait(false);
// ...
}
This worked most of the time, but it caused random problems with the middleware. Sometimes the middleware would start running twice for each element, which would usually cause an error the second time the middleware ran.
Looking at the source, it appears the middleware is being applied to the schema during the life cycle of a request, and then somehow rolled back at the end I guess? At least I'm assuming that's how the public void ApplyTo(ISchema schema) member is being used, although I'm not sure how the "rollback" part was happening.
This gave me an idea of how to solve the problem by pulling the middleware out of the view and put it in the schema constructor, like this:
public class MySchema : Schema
{
public MySchema()
{
this.Query = new MyQuery();
this.Mutation = new MyMutation();
var builder = new FieldMiddlewareBuilder();
builder.Use(next => context =>
{
return next(context).ContinueWith(x=> {
var result = x.Result;
return doStuff(result);
});
});
builder.ApplyTo(this);
}
}
So now the middleware is baked directly into the schema when the singleton is constructed, and the controller doesn't have to do anything.
This appears to have completely solved the problem. I'm not sure if there are other things in graphql-dotnet that mutate the schema during the request life cycle. If anyone knows of any other problems that might occur with a singleton schema I'd love to hear it!
I'm using logging to Console output, that built-in to .Net Core framework.
Here initialization of the logger:
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(new LoggerFactory()
.AddConsole());
Also for logging I'm using Microsoft.Extensions.Logging.LoggerExtensions class with methods Log...
Here an example of logging in my App:
_logger.LogInformation(eventId, "Action is started.");
Where _logger is instance of ILogger<T> class and initialized in the class constructor with built-in dependency injection.
As result of calling of the above method Console output shows following string:
info: NameSpaceName.ClassName[eventId] Action is started.
I would like to display date-time in the Console output, that points to time, when the Log method is executed, but it seems that Log.. methods don't contain any methods that allow to display date time.
Does it exist some method or additioanl classes-formatters that allow to display the action datetime in console output without passing it to the method as part of the message?
The feature was added into version 3 of the Microsoft.Extensions.Logging.Console(here is the pr). You can activate this with setting the TimestampFormat:
new ServiceCollection()
.AddLogging(opt =>
{
opt.AddConsole(c =>
{
c.TimestampFormat = "[HH:mm:ss] ";
});
})
Example in .NET 5 (ASP.NET Core):
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(options =>
{
options.AddSimpleConsole(c =>
{
c.TimestampFormat = "[yyyy-MM-dd HH:mm:ss] ";
// c.UseUtcTimestamp = true; // something to consider
});
});
// ...
}
Output example:
[2020-12-13 12:55:44] info: Microsoft.Hosting.Lifetime[0] Application is shutting down...
For ASP.NET Core, you might prefer to use configuration file appsettings.json over wiring it directly into the code.
{
"Logging": {
"Console": {
"TimestampFormat": "[yyyy-MM-dd HH:mm:ss] "
}
}
}
This works out of the box, provided that Host.CreateDefaultBuilder() is invoked in Program.cs
Built-in .NET Core console logger doesn't log date-time. Track this issue to get more details. The easiest workaround is:
logger.Log(LogLevel.Information, 1, someObj, null, (s, e) => DateTime.Now + " " + s.ToString());
I wrote a custom console logger to automatically log the timestamp and do other useful tricks:
[2017.06.15 23:46:44] info: WebHost[1] Request starting HTTP/1.1 GET http://localhost:6002/hc
I am building an ASP.NET 5 (vNext) site that will host dynamic pages, static content, and a REST Web API. I have found examples of how to create middleware using the new ASP.NET way of doing things but I hit a snag.
I am trying write my own authentication middleware. I would like to create a custom attribute to attach to the controller actions (or whole controllers) that specifies that it requires authentication. Then during a request, in my middleware, I would like to cross reference the list of actions that require authentication with the action that applies to this current request. It is my understanding that I configure my middleware before the MVC middleware so that it is called first in the pipeline. I need to do this so the authentication is done before the request is handled by the MVC controller so that I can't prevent the controller from ever being called if necessary. But doesn't this also mean that the MVC router hasn't determined my route yet? It appears to me the determination of the route and the execution of that routes action happen at one step in the pipeline right?
If I want to be able to determine if a request matches a controller's action in a middleware pipeline step that happens before the request is handled by the controller, am I going to have to write my own url parser to figure that out? Is there some way to get at the routing data for the request before it is actually handled by the controller?
Edit: I'm beginning to think that the RouterMiddleware might be the answer I'm looking for. I'm assuming I can figure out how to have my router pick up the same routes that the standard MVC router is using (I use attribute routing) and have my router (really authenticator) mark the request as not handled when it succeeds authentication so that the default mvc router does the actual request handling. I really don't want to fully implement all of what the MVC middleware is doing. Working on trying to figure it out. RouterMiddleware kind of shows me what I need to do I think.
Edit 2: Here is a template for the middleware in ASP.NET 5
public class TokenAuthentication
{
private readonly RequestDelegate _next;
public TokenAuthentication(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
//do stuff here
//let next thing in the pipeline go
await _next(context);
//do exit code
}
}
I ended up looking through the ASP.NET source code (because it is open source now!) and found that I could copy the UseMvc extension method from this class and swap out the default handler for my own.
public static class TokenAuthenticationExtensions
{
public static IApplicationBuilder UseTokenAuthentication(this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes)
{
var routes = new RouteBuilder
{
DefaultHandler = new TokenRouteHandler(),
ServiceProvider = app.ApplicationServices
};
configureRoutes(routes);
routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(
routes.DefaultHandler,
app.ApplicationServices));
return app.UseRouter(routes.Build());
}
}
Then you create your own version of this class. In my case I don't actually want to invoke the actions. I will let the typical Mvc middleware do that. Since that is the case I gut all the related code and kept just what I needed to get the route data which is in actionDescriptor variable. I probably can remove the code dealing with backing up the route data since I dont think what I will be doing will affect the data, but I have kept it in the example. This is the skeleton of what I will start with based on the mvc route handler.
public class TokenRouteHandler : IRouter
{
private IActionSelector _actionSelector;
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
EnsureServices(context.Context);
context.IsBound = _actionSelector.HasValidAction(context);
return null;
}
public async Task RouteAsync(RouteContext context)
{
var services = context.HttpContext.RequestServices;
EnsureServices(context.HttpContext);
var actionDescriptor = await _actionSelector.SelectAsync(context);
if (actionDescriptor == null)
{
return;
}
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
if (actionDescriptor.RouteValueDefaults != null)
{
foreach (var kvp in actionDescriptor.RouteValueDefaults)
{
if (!newRouteData.Values.ContainsKey(kvp.Key))
{
newRouteData.Values.Add(kvp.Key, kvp.Value);
}
}
}
try
{
context.RouteData = newRouteData;
//Authentication code will go here <-----------
var authenticated = true;
if (!authenticated)
{
context.IsHandled = true;
}
}
finally
{
if (!context.IsHandled)
{
context.RouteData = oldRouteData;
}
}
}
private void EnsureServices(HttpContext context)
{
if (_actionSelector == null)
{
_actionSelector = context.RequestServices.GetRequiredService<IActionSelector>();
}
}
}
And finally, in the Startup.cs file's Configure method at the end of the pipeline I have it setup so that I use the same routing setup (I use attribute routing) for the both my token authentication and mvc router.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//Other middleware delcartions here <----------------
Action<IRouteBuilder> routeBuilder = routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
};
app.UseTokenAuthentication(routeBuilder);
//Middleware after this point will be blocked if authentication fails by having the TokenRouteHandler setting context.IsHandled to true
app.UseMvc(routeBuilder);
}
Edit 1:
I should also note that at the moment I am not concerned about the extra time required to select the route twice which is what I think would happen here since both my middleware and the Mvc middleware will be doing that. If that becomes a performance problem then I will build the mvc and authentication in to one handler. That would be best idea performance-wise, but what I have shown here is the most modular approach I think.
Edit 2:
In the end to get the information I needed I had to cast the ActionDescriptor to a ControllerActionDescriptor. I am not sure what other types of actions you can have in ASP.NET but I am pretty sure all my action descriptors should be ControllerActionDescriptors. Maybe the old legacy Web Api stuff needs another type of ActionDescriptor.