How to use ActionFilter on Prometheus mapPath in standard .Net Web API? - asp.net-web-api

I want to filter the range of client IPs who can route to Prometheus metrics.
So in startup I have
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}
And this is my custom actionFilter class
public class IpFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
string clinetIP = GetClientIpAddress(actionContext.HttpContext.Items["MS_HttpRequestMessage"] as HttpRequestMessage);
if (IpAllowed(clinetIP))
base.OnActionExecuting(actionContext);
}
But I have no idea how to use IpFilter since it cannot be use as an attribute on a controller action.
I tried to use it by adding a middleware using owin but the next.Invoke doesn't work properly
public void Configuration(IAppBuilder app)
{
app.Map("/metrics", metricsApp =>
{
metricsApp.Use<TestIpMid>(deniedIps);
metricsApp.UsePrometheusServer(q => q.MapPath = "/metrics");
});
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}
and this is the middleware:
public class TestIpMid : OwinMiddleware
{
private readonly HashSet<string> _deniedIps;
public TestIpMid(OwinMiddleware next, HashSet<string> deniedIps) : base(next)
{
_deniedIps = deniedIps;
}
public override async Task Invoke(IOwinContext context)
{
var ipAddress = context.Request.RemoteIpAddress;
if (_deniedIps.Contains(ipAddress))
{
context.Response.StatusCode = 403;
return;
}
await Next.Invoke(context);
}
}
please help me :'(

this solution worked for me but other ways I was thinking of didn't work
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var config = new HttpConfiguration();
var allowedIps = ProtectedSettings.Read(ProtectedSettings.protheusIpWhitelist).Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
app.Use(async (Context, next) =>
{
var ipAddress = Context.Request.RemoteIpAddress;
if ((!allowedIps.Contains(ipAddress)) && Context.Request.Path.Value == "/metrics")
{
Context.Response.StatusCode = 403;
return;
}
await next.Invoke();
});
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}

Related

HttpContext.Session.GetString("string"), Randomly I get Session has not been configured for this application or request exception

Not everytime but some time i get error while i try to get HttpContext.Session.GetString("userid");
I am using .Net core 2.2
Below is my session helper code
public static class SessionHelper
{
private static HttpContext _context = null;
public static void SetCurrentContext(HttpContext context)
{
_context = context;
}
public static string UserID
{
get
{
try
{
return _context.Session.GetString("userid");
}
catch
{
return "";
}
}
set
{
_context.Session.SetString("userid", value);
}
}
}
Below in my middleware configuration in Configure method startup.cs
app.UseSession();
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "sameorigin");
await next();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseMvcWithDefaultRoute();
Below is my ConfigureServices code of startup.cs
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(60 * 30);
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest;
//options.IOTimeout = TimeSpan.FromSeconds(60 * 30);
});
services.AddMvc()
.AddSessionStateTempDataProvider();

Rollbar logs not working in .Net(core) 5.0

I have .Net core 5.0 api and I'm trying to add logs but somehow its not working. below is my setup.
public void ConfigureServices(IServiceCollection services)
{
ConfigureRollbarSingleton();
services.AddControllers();
services.AddDbContext<AfterSchoolContext>(options => options.UseSqlServer(connectionString: connectionString, m => m.MigrationsAssembly("AfterSchoolHQ")));
services.AddScoped<IRepositoryWrapper, RepositoryWrapper>();
// Automapper Configuration
services.AddAutoMapper(typeof(Startup));
services.AddHttpContextAccessor();
services.AddRollbarLogger(loggerOptions =>
{
loggerOptions.Filter =
(loggerName, loglevel) => loglevel >= LogLevel.Trace;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "AfterSchoolHQ", Version = "v1" });
});
}
private void ConfigureRollbarSingleton()
{
RollbarLocator.RollbarInstance
// minimally required Rollbar configuration:
.Configure(new RollbarConfig(rollbarAccessToken) { Environment = rollbarEnvironment })
// optional step if you would like to monitor
// Rollbar internal events within your application:
.InternalEvent += OnRollbarInternalEvent
;
// Optional info about reporting Rollbar user:
SetRollbarReportingUser("007", "jbond#mi6.uk", "JBOND");
}
And here is my controller.
public class TestController : ControllerBase
{
private readonly IRepositoryWrapper _repositories;
private readonly Rollbar.ILogger _logger;
private readonly IMapper _mapper;
public TestController(Rollbar.ILogger logger, IMapper mapper, IRepositoryWrapper repositories)
{
_mapper = mapper;
_logger = logger;
_repositories = repositories;
}
[HttpGet("GetByID")]
public IActionResult GetById(int id)
{
try
{
if (id <= 0)
return new NotFoundResult();
_logger.Info("test"); //I'm trying to add a log from here
var request = _repositories.GetById(id: id);
if (request == null)
return new NotFoundResult();
return new OkObjectResult(_mapper.Map(source: request));
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
It gives me error that 'unable to resolve service for type Rollbar.ILogger'. I don't even see a way in any docs to handle this cases. any help would be really appreciated.
Make sure you are using Rollbar.NetCore.AspNet Nuget package v5.0.0-beta and newer. For example: https://www.nuget.org/packages/Rollbar.NetCore.AspNet/5.0.4-beta
and follow this instructions:
https://docs.rollbar.com/docs/v5-integrating-with-aspnet-core-2-and-newer
If that does not help, please, open an issue at:
https://github.com/rollbar/Rollbar.NET/issues
I'll follow up there...

Open app from another app with Xamarin.Forms and MvvmCross UWP

Opening app from another app can be done like:
public async Task<bool> LaunchUriAsync(string objectNumber)
{
var option = new LauncherOptions();
option.UI.PreferredPlacement = Placement.Right;
option.DesiredRemainingView = ViewSizePreference.UseMore;
return await Launcher.LaunchUriAsync(buildObjectAccessUri(objectNumber), option);
}
private static Uri buildObjectAccessUri(string objectId)
{
return new Uri(String.Format("{0}://{1}/{2}", "myapp", "data", objectId), UriKind.Absolute);
}
in a Command I do:
await MyLauncherService.LaunchUriAsync("whatever");
and in opened application I have a custom start
public class CustomAppStart : MvxAppStart
{
protected override async Task NavigateToFirstViewModel(object hint = null)
{
// hint here is type of `Windows.ApplicationModel.Activation.ProtocolActivatedEventArgs`
}
}
Seems that object hint is type of Windows.ApplicationModel.Activation.ProtocolActivatedEventArgs
The App.xaml.cs of UWP project:
sealed partial class App
{
public App()
{
InitializeComponent();
}
}
public abstract class UwpApp : MvxApplication<Setup<Core.App>, Core.App>
{
private ILoggerService mLoggerService;
public UwpApp()
{
UnhandledException += (sender, args) =>
{
mLoggerService = Mvx.IoCProvider.Resolve<ILoggerService>();
if (mLoggerService == null)
{
return;
}
mLoggerService.Fatal("Unhandled exception!", args.Exception);
};
DebugSettings.BindingFailed += (sender, args) => Debug.WriteLine(args.Message);
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
mLoggerService = Mvx.IoCProvider.Resolve<ILoggerService>();
if (mLoggerService == null)
{
return;
}
foreach (var ex in args.Exception.Flatten().InnerExceptions)
{
mLoggerService.Error(ex.Message + " StackTrace:" + ex.StackTrace);
}
args.SetObserved();
};
Suspending += OnSuspending;
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
}
protected override void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
deferral.Complete();
}
}
Why I got that ?
I expected to be string ...
Where is the mistake ?
I'm using latest version of xamarin and mvvm cross
In your MvxApplication you can override GetAppStartHint to process the object coming into that method and return a string as you expect.
Something like:
public abstract class UwpApp : MvxApplication<Setup<Core.App>, Core.App>
{
protected override object GetAppStartHint(object hint = null)
{
// process hint
//return string
}
}

JWT Token from postman never hits the controller with Authorize attribute

Trying to understand how JWT works for asp.net core application. I use a ASP.NET MVC Core application template.
My StartUp.cs cotains configuration for JWT Token :
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
//options.EventsType = typeof(AuthenticateCustomEvent);
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
And my login controller contains code to return token on successfull validation of the user this returns a token as shown below
Once i recieve the token i make a call to a controller with [Authorize] attribute applied to it with the bearer token from PostMan the controller never gets hit ? Am i missing something ?
My below solution is bit different, but this solution will help you to deal with custom auth implementation, you can implement a different type of auth for the different type of users. You require to create a class AuthorizationRequiredAttribute under your API project, this class will inherit ActionFilterAttribute class to filter each API request. you can filter all HTTP methods (GET, POST, PUT, DELETE...etc), and can implement your own authorization logic for specific HTTP method.
ActionFilterAttribute.cs
using BillSyatemCore.Common.Constants;
using BillSyatemCore.Services.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
namespace BillSyatemCore.Handlers
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
private IConfiguration _config;
public AuthorizationRequiredAttribute(IConfiguration config)
{
_config = config;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
try
{
if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
as JwtSecurityToken;
var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
{
if (expireDate < DateTime.Now)
{
context.Result = new UnauthorizedResult();
}
}
else
{
//You may filter post,put,delete etc request here.
}
}
else
{
context.Result = new NotFoundResult();
}
}
catch (Exception ex)
{
context.Result = new BadRequestResult();
}
base.OnActionExecuting(context);
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//JWT
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build());
});
}
Controller.cs
using BillSyatemCore.Models.Authentication;
using BillSystemCore.Transporter;
using Microsoft.AspNetCore.Mvc;
namespace TestProject.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
public class UserTypeController : Controller
{
private readonly IAuthTransporter _authTransporter;
public UserTypeController(IAuthTransporter authTransporter)
{
_authTransporter = authTransporter;
}
[HttpPost("save"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
public IActionResult Save([FromBody] UserType userType)
{
return Ok(_authTransporter.UserTypeServices.Save(userType));
}
}
}

MassTransit's ISendObserver is not observing

I have a consumer that is also publishing a response back to the bus. I can get an IReceiveObserver wired up and working on the bus, but I haven't been able to get either an ISendObserver or IPublishObserver running. I have confirmed with RabbitMQ management console that the messages are being published correctly.
class Program
{
static BusHandle _BusHandle;
static void Main(string[] args)
{
InitLogging();
InitStructureMap();
InitBus();
System.Console.WriteLine("Starting processing, ENTER to stop...");
System.Console.ReadLine();
System.Console.WriteLine("See you later, alligator!");
StopBus();
}
static void InitBus()
{
var busCtrl = ObjectFactory.Container.GetInstance<IBusControl>();
var recObserver = ObjectFactory.Container.GetInstance<IReceiveObserver>();
var sendObserver = ObjectFactory.Container.GetInstance<ISendObserver>();
busCtrl.ConnectReceiveObserver(recObserver);
busCtrl.ConnectSendObserver(sendObserver);
_BusHandle = busCtrl.Start();
}
static void StopBus()
{
_BusHandle.Stop();
}
static void InitLogging()
{
XmlConfigurator.Configure();
Log4NetLogger.Use();
}
static void InitStructureMap()
{
ObjectFactory.Initialize(x => {
x.AddRegistry<MyTestConsoleRegistry>();
x.AddRegistry<MyTestRegistry>();
});
}
}
public class MyTestConsoleRegistry : Registry
{
public MyTestConsoleRegistry()
{
var rabbitURI = ConfigurationManager.AppSettings["rabbitMQHostUri"];
var queueName = ConfigurationManager.AppSettings["massTransitQueue"];
For<IBusControl>(new SingletonLifecycle())
.Use("Configure IBusControl for MassTransit consumers with RabbitMQ transport",
ctx => Bus.Factory.CreateUsingRabbitMq(cfg => {
cfg.UseJsonSerializer();
cfg.PublisherConfirmation = true;
var host = cfg.Host(new Uri(rabbitURI), rabbitCfg => { });
cfg.ReceiveEndpoint(host, queueName, endpointCfg => {
endpointCfg.LoadFrom(ctx);
});
})
);
For<IReceiveObserver>().Use<MassTransitObserver>();
For<ISendObserver>().Use<MassTransitObserver>();
// ...snip...
}
}
public class MyTestRegistry : Registry
{
public MyTestRegistry()
{
ForConcreteType<MyTestConsumer>();
// ...snip...
}
}
public class MassTransitObserver : IReceiveObserver, ISendObserver
{
// Does nothing for now, just trying to wire it up...
public Task ConsumeFault<T>(ConsumeContext<T> context, TimeSpan duration, string consumerType, Exception exception) where T : class
{
return Task.CompletedTask;
}
public Task PostConsume<T>(ConsumeContext<T> context, TimeSpan duration, string consumerType) where T : class
{
return Task.CompletedTask;
}
public Task PostReceive(ReceiveContext context)
{
return Task.CompletedTask;
}
public Task PreReceive(ReceiveContext context)
{
return Task.CompletedTask;
}
public Task ReceiveFault(ReceiveContext context, Exception exception)
{
return Task.CompletedTask;
}
public Task PreSend<T>(SendContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task PostSend<T>(SendContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task SendFault<T>(SendContext<T> context, Exception exception) where T : class
{
return Task.CompletedTask;
}
}
public class MyTestConsumer : IConsumer<MyTestMessage>,
// for testing only:
IConsumer<MyTestResponse>
{
readonly IDoSomething _DoSomething;
public TestConsumer(IDoSomething doSomething)
{
_DoSomething = doSomething;
}
public Task Consume(ConsumeContext<MyTestResponse> context)
{
// For testing only...
return Task.CompletedTask;
}
public async Task Consume(ConsumeContext<MyTestMessage> context)
{
var result = await _DoSomething(context.Message.Id);
var resp = new MyTestResponseMessage(result);
await context
.Publish<MyTestResponse>(resp);
}
}
Given this code, the IReceiveObserver methods are getting called, but the ISendObserver methods are not.
I'm new to MassTransit, I expect this is probably a straightforward issue.
EDIT: A unit test using NUnit and Moq, doesn't use StructureMap. I believe this properly illustrates what I'm seeing.
[Test]
public void TestSendObserver()
{
var bus = CreateBus();
var busHandle = bus.Start();
var sendObs = new Mock<ISendObserver>();
sendObs.Setup(x => x.PreSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()))
.Returns(Task.FromResult(0))
.Verifiable();
sendObs.Setup(x => x.PostSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()))
.Returns(Task.FromResult(0))
.Verifiable();
using (bus.ConnectSendObserver(sendObs.Object)) {
var pubTask = bus.Publish(new TestMessage { Message = "Some test message" });
pubTask.Wait();
}
busHandle.Stop();
// Fails, neither PreSend nor PostSend have been called
sendObs.Verify(x => x.PreSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()), Times.Once());
sendObs.Verify(x => x.PostSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()), Times.Once());
}
IBusControl CreateBus()
{
return MassTransit.Bus.Factory.CreateUsingRabbitMq(x => {
var host = x.Host(new Uri("rabbitmq://localhost/"), h => {
h.Username("guest");
h.Password("guest");
});
});
}
public class TestMessage
{
public String Message { get; set; }
}

Resources