I would like to know the correct way of enforcing SSL for all calls to my Nancy API. My current (C#) implementation is:
public abstract class NancyHttpsModule : NancyModule
{
public NancyHttpsModule(string baseUrl) : base(baseUrl)
{
this.RequiresHttps();
}
}
This seems to work with 403 Forbidden on the Non-SSL port.
Is there a better way to do this? (Without using IIS redirects like this article.)
You can add a BeforeRequestHook to ispect and issue a redirect. Create a startup task in your project, you do not need to hook it, Nancy will pick it up. (pseudo code follows):
public class AlwaysUseHttps : IApplicationStartUp
{
public void Initialize(IPipelines pipelines)
{
pipelines.BeforeRequest.AddItemToSTartOfPiepline(RedirectIfNotHttps);
}
private static Response RedirectIfNotHttps(NancyContext context)
{
//return null if it is already https
//else, do a redirect as shown here: https://github.com/NancyFx/Nancy/blob/master/src/Nancy/Security/ModuleSecurity.cs
}
}
Related
I have an httphandler like this:
public class MyProxy : IHttpHandler
{
public MyProxy() { }
public void ProcessRequest(HttpContext context)
{
//do something
}
}
I want to be able to inject a service (KeyVaultService) so I can move some app settings that are sitting in the web.config to the key vault. However, when I inject the KeyVaultService the MyProxy is no longer hit. I'm assuming this is how httpHandlers work, so why is this and is there some way round this (both generally and specifically for a KeyVaultService)? For this case could I create SecretClient?
I am migrating a web API from .net Framework to .net Core. The old version was able to ignore the Authorize Attribute on the controller if the app was running on a private server. Here is the code for that. I know .net core 3.1 does not offer Custom AuthorizeAttributes. That is not my question.
// A custom AuthroizeAttribute
public class ConditionalAuthorizeAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext httpContext)
{
if (environment_private())
return true;
else
return base.IsAuthorized(httpContext);
}
private bool environment_private()
{
// code that will tell you if you are in your dev environment or not
return Properties.Settings.Default.PrivateServer;
}
}
// How it was called from the controller
[ConditionalAuthorize(Roles = "MyRole")]
[Route(...)]
// More code for controller
I just need a simple way to authorized all requests when running the project on our private server (which is determined by a variable in appSettings.json). I have tried policies, but I face the following difficulties:
1) I couldn't pass the variable in the configuration from the controller to a parameterized authorize attribute.
2) I couldn't inject the configuration into a parameterized authorize attribute.
This effectively eliminated my ability to follow this guide in any way: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-2.2
This leads to my question: How can I use a value from appSettings.json to override whether the request checks a role or not?
After a lot of research, I found a way to do it using TypeFilterAttribute. Essentially, it's the same way of doing it (using a custom attribute to filter all requests and check the condition within the custom attribute) except I used .net Core-supported methods.
In case you are trying to solve this same issue, here are the exact steps to my solution.
Add two files, "YourAttributeNameAttribute.cs" and "YourFilterNameFilter.cs".
In the "YourAttributeNameAttribute.cs" file, the code is as follows:
public class YourAttributeNameAttribute : TypeFilterAttribute
{
public YourAttributeNameAttribute(string role) : base(typeof(YourFilterNameFilter))
{
Arguments = new object[] { role };
}
}
The code in "YourFilterNameFilter.cs":
public class YourFilterNameFilter : IAuthorizationFilter
{
private readonly string Role;
public YourFilterNameFilter(string role)
{
Role = role;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var configuration = context.HttpContext.RequestServices.GetService<IConfiguration>();
// If private server, ignore roles
if (private_server_logic_here)
return;
var user = context.HttpContext.User;
// Check role if on public server
if (!user.IsInRole(Role))
{
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Unauthorized);
return;
}
}
}
The code for the controller:
[YourAttributeName("role_name")]
[Route("api/my_route")]
[HttpGet]
I trying to experiment with Specflow. So I am writing functional tests for a REST API and have created a couple of step definitions, say CreatePersonStepDefinitions and GetPeopleStepDefinition
Those extend CommonStepDefinition, which provides things like:
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)Response.StatusCode);
}
This is to be able to run scenarios like
Given I am retrieving all people
And an invalid API key is given
When I make the call
Then the response HTTP code should be 200
And the API response code is 104
And the API call didn't take more than 200 milliseconds
So there are several common steps between step definitions. I understand that I cannot do this as Steps are global. What I wanted to ask is whats the best way (i.e. best practise) to achieve this without duplicating the same steps in every step definition.
Thanks
Because steps are global you don't need to duplicate them in every step definition, you can just use them in ALL features, and specflow will call them.
If your real question is how do I share the ApiKey and Response between my features steps and my common steps there are a few ways but what I would recommend is to use the context injection approqach from the link. I would create context objects and pass these to your step classes. Specflow has a simple DI framework which will do this automatically (most of the time) for you.
I would create something like this:
public class SecurityContext
{
public string ApiKey {get;set;}
}
public class ResponseContext
{
public IHttpResponse Response{get;set;}
}
[Binding]
public class CommonSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public CommonSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
securityContext.ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)responseContext.Response.StatusCode);
}
}
public class MyFeatureSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public MyFeatureSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
///Then in your feature steps you can use the Api key you set and set the response
}
you might even consider not having Common steps as this get just be a big bucket for everything that is not feature specific, but what we usually do is to break the step classes into something like SecuritySteps which would just take the SecurityContext and ResponseSteps which would just take the ResponseContext
i have some services on ServiceStack and use SignalR in this project.
And now, i would like to secure hub connection (access only for authenticated users), but i use ServiceStack framework authentication.. (not asp.net authentication) and ServiceStack's sessions (write AuthUserId ih this session and authentication flag).
So, when user trying connect to the hub -- hub must to check authentication...
(yes, i can request Cookies from Hub (method OnConnected, for example), but SignalR check authentication in Authorize Attribute - and i must do it in this class (not in hub)
(http://www.asp.net/signalr/overview/signalr-20/security/hub-authorization)
So, i create class
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class AuthorizeMyAttribute : AuthorizeAttribute
{
protected override bool UserAuthorized(System.Security.Principal.IPrincipal user)
{
//... how can i request Cookies? / or may be can access for ServiceStack session...
// and return true or false
}
}
What can i do for it?
Thanks!
AuthorizeAttribute has two more virtual methods:
AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
http://msdn.microsoft.com/en-us/library/microsoft.aspnet.signalr.authorizeattribute(v=vs.118).aspx
The default implementations of both methods call UserAuthorized with the request's IPrincipal.
AuthorizeHubConnection is passed an IRequest directly.
In AuthorizeHubMethodInvocation, you can access the IRequest object from the IHubIncomingInvokerContext like so: hubIncomingInvokerContext.Hub.Context.Request.
I still struggled with this for some time trying to get the ServiceStack.Web.IRequest from the SignalR.IRequest so I could use ServiceStack's functions to request the session to see if the user had been auth'd. In the end I gave up and got the cookies from SignalR. I hope the following code snippet helps someone else nagivate this.
public class AuthorizeAttributeEx : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
{
return IsUserAuthorized(request);
}
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
return IsUserAuthorized(hubIncomingInvokerContext.Hub.Context.Request);
}
protected bool IsUserAuthorized(IRequest thisRequest)
{
try
{
// Within the hub itself we can get the request directly from the context.
//Microsoft.AspNet.SignalR.IRequest myRequest = this.Context.Request; // Unfortunately this is a signalR IRequest, not a ServiceStack IRequest, but we can still use it to get the cookies.
bool perm = thisRequest.Cookies["ss-opt"].Value == "perm";
string sessionID = perm ? thisRequest.Cookies["ss-pid"].Value : thisRequest.Cookies["ss-id"].Value;
var sessionKey = SessionFeature.GetSessionKey(sessionID);
CustomUserSession session = HostContext.Cache.Get<CustomUserSession>(sessionKey);
return session.IsAuthenticated;
}
catch (Exception ex)
{
// probably not auth'd so no cookies, session etc.
}
return false;
}
}
I need to create rest style web service with one of the methods conforming to this type of URI.
api/v1/{controller}/{device}/registrations/{id}
public class DevicesController : ApiController
{
public void Get(string device, string id)
{
}
}
Seems like I'm missing something out there, any ideas on how to handle this?
Figured this out, must have been doing something wrong before. This seems to work fine.
routes.MapHttpRoute("PassApi",
"api/v1/{controller}/{device}/registrations/{id}",
new { controller = "Devices" });