I have multiple restful API components implemented using ASP.NET Core. I am not using Event Driven Design or any messaging broker service.
I want to keep it simple, so
Let's say I have 3 restful independent components (with independent ASP.NET Core Projects) that are published to the same IIS in addition to the Identity server provider:
Navigation: that retrieve menus from its own database
Authorization: that deals with the permissions and security
Notifications
Identity Server: provides Jwt access tokens for authenticated users to authorize him access the apis.
Apart from the external communication from the client to the Apis where an API Gateway should handle all client requests. There are some sort of communication that is done internally. A good example is getting menus for the user:
The user gets an access token after successful log in
Then he requests the menus he can view, so a request is forwarded to Navigation API
Navigation API issues an internal request to Authorization API in order to check what permissions the user has to limit his access to certain menus.
Right Now, I am managing the communication by a common library called Service Proxies, which has all the api urls hard coded in cs file (which is just for trying the concept)
public static class Config
{
public static class ServiceURLs
{
public const string AuthorizationAPI ="http://localhost:port/api/Authorization/" ;
}
}
public class AuthorizationServiceProxy : IAuthorizationServiceProxy
{
//ServiceProxy is a custom class that issue http requests in order to get responses
private ServiceProxy _serviceProxy;
public AuthorizationServiceProxy(string accessToken)
{
_serviceProxy = new ServiceProxy(Config.ServiceURLs.AuthorizationAPI, accessToken);
}
public async Task<List<Permission>> GetUserPermissions()
{
var route = "GetUserPermissions";
var result = await
_serviceProxy.GetHttpResponseContentAsType<List<Permission>>(route);
return result;
}
AuthorizationProxy and all proxies will be just to issue a request from an API to another one.
How would an interprocess communication would be handled in my case?
Related
I have mu backend application in asp.net web api (frontend is angular 8 app)
i have method in controller:
[RoutePrefix("Payment")]
public class PaymentDeadlineController : ApiController
{
DKServiceClient DkService = new DKServiceClient();
SrvPartlyPayment PartlyPayment = new SrvPartlyPayment();
[Route("GetNotified")]
public void GetNotified()
{
DkService.SrvC_CPCheckIsActive();
}
}
How to prevent entering this method GetNotified() when someone opens browser and types http://HostedLocation/Payment/GetNotified in the url?
If you are looking to secure your API from unauthorized access,
You can add [Authorize] attribute in the web api controller and enable Authorization for your API in your startup.cs.
Your front end application can send request to API along with a token issued by your identity provider to API and get response,
while other anonymous users will not have token and hence cannot invoke your method using browser or any other tools like postman.
I want to access one of my web API endpoints within another web API. But need to skip authorization procedure only for this situation. It means i want to access mentioned endpoint without the access_token. But to access it by any client app (Mobile, Web) the access_token should be required. Is it possible?.
[HttpGet("{id:int}")]
[Authorize]
public async Task<IActionResult> Get([FromRoute] int id)
{
try
{
// some code
return Ok(true);
}
catch (Exception ex)
{
throw ex;
}
}
you need an API gateway project which contain authorization and your clients access this porject. then you can hide another projects behind the API gateway. with this scenario your webapi doen't need any authorization and they can call each other without authorization.
for more information about this approach see this:
Api gateway pattern
I have a test console app which I'm pointing at a local instance of Identity Server 3 to request an access token. The following code does this and returns my token fine (passing a single scope "scope.test.client").
static TokenResponse GetClientToken(string clientId, string clientSecret, string[] scopes)
{
var uri = new Uri(string.Concat(ID_BASE_URI, ID_URL_TOKEN));
var client = new TokenClient(
uri.AbsoluteUri,
clientId,
clientSecret);
return client.RequestClientCredentialsAsync(string.Join(" ", scopes)).Result;
I then use this token to call an API also running locally. This takes the TokenResponse obtained above and passed it to this method:
static void CallApi(string url, TokenResponse response)
{
try
{
using (var client = new HttpClient())
{
client.SetBearerToken(response.AccessToken);
Console.WriteLine(client.GetStringAsync(url).Result);
}
}
catch (Exception x)
{
Console.WriteLine(string.Format("Exception: {0}", x.Message));
}
}
The API (an ASP.NET WebApi project) uses an Owin Startup class to enforce bearer token authentication for all requests:
appBuilder.Map(baseApiUrl, inner =>
{
inner.UseWebApi(GlobalConfiguration.Configuration);
// Enforce bearer token authentication for all API requests
inner.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://identityserver/core",
ValidationMode = ValidationMode.ValidationEndpoint,
RequiredScopes = new[] { "scope.test.client" }
});
});
It also ensures all API requests are handled by a custom authorize attribute:
GlobalConfiguration.Configuration.Filters.Add(new DefaultApiAuthorizeAttribute());
Debugging this API, the first line in my overridden OnAuthorize method (in DefaultApiAuthorizeAttribute) is this:
var caller = actionContext.RequestContext.Principal as System.Security.Claims.ClaimsPrincipal;
If I break on this line I can see that actionContext.RequestContext.Principal is always null. However, I can see that ((System.Web.Http.Owin.OwinHttpRequestContext)actionContext.RequestContext).Request.Headers contains an Authorization header with the bearer token passed from my console app.
So it would seem that the API project is not authenticating the bearer token. Certainly the Identity Server logs suggest it isn't being hit at all after issuing the initial access token. So I'd appreciate your expert advice about why this might not be happening, or at least some pointers about where to look.
I suspect it might have something to do with SSL. Both sites are hosted locally under self-signed SSL certs, although Identity Server is configured to not require SSL and uses the idsrv3test.pfx development certificate for signing. I do have another test MVC web app which delegates authentication to the same IS3 instance which works fine locally, so I believe my IS3 instance is configured correctly.
You need to call UseIdentityServerBearerTokenAuthentication before you call UseWebApi. When you set up an OWIN Middleware Pipeline, the order is important.
In your case, Web API will be handling your requests before they get sent onto Identity Server (if they get sent on at all).
I imagine a range of possible issues could have the impact I described, but in my case I was able to find the cause by adding a diagnostics log to my consuming API. This led me to discover that the problem was an assembly conflict. The Owin middleware was looking for a Newtonsoft.JSON assembly with version 8.0.0.0 but my consuming API (actually running on top of a CMS intance) was using 7.0.0.0.
For anyone else who wants to find the answer fast, rather than spend hours tweaking configurations, here's the documentation that describes how to add this logging: https://identityserver.github.io/Documentation/docsv2/consuming/diagnostics.html
I have a web application composed of a gateway and several back-end services.
The gateway is a self-hosted OWIN application, and covers concerns like authentication, authorization, and routing of api calls to the backend.
I'm interested in using SignalR in one of my backend services to push data to the client. E.g. the user starts a long running query, and data is fed back to the client as it becomes available.
I managed to use the backplane from the scale-out article as a messaging mechanism (though it seems it wasn't designed for such messaging)
SignalR scaleout explanation
"Gateway" Hub code: (The logic is only for testing purposes)
public override async Task OnConnected()
{
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:8888/other/")
};
var result = await client.PostAsJsonAsync("signin", Context.ConnectionId);
await base.OnConnected();
}
Backend controller code
[HttpPost]
[Route("signin")]
public void PostSignin([FromBody]string id)
{
StartPing(id);
}
public async Task StartPing(string id)
{
var context = GlobalHost.ConnectionManager.GetHubContext<FrontendHub>();
int i = 0;
while (true)
{
i++;
context.Clients.Client(id).showMessage("num " + i);
await Task.Delay(1000);
}
}
However, this is a big enterprise application, and I don't want the gateway to have any dependency on the actual code of the backend services. But the example only works if a hub with the same name is defined in both the gateway and the backend service.
On one hand, I'm trying to avoid the need to place such specialized code in the gateway, on the other hand, I'd like to leverage the ability to use actual function names and parameters. I don't want a "master hub" with a single function.
Is there a way to do it?
Didn't end up doing it all, but the solution discovered later was to indeed use a "Master hub", but it doesn't actually need to have any functions at all.
The contract is between the backend service and the client application. Since everything in SignalR is loosely typed, it's enough that the client define some function on the hub, and the backend service invoke the same function on the hub. The hub doesn't actually need this function in its own code.
I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated