Allow access to single API without Authorization? - azure

I'm sure I'm probably missing something fairly basic, but is there a way to expose ApiController to be accessed without Authorization? Removing [Authorize] or adding [AllowAnonymous] doesn't seem to help.
namespace Backend.Controllers
{
[MobileAppController, Authorize]
public class RebuildLocalDatabaseCheckController : ApiController
{
[HttpGet, Route("api/LastLocalDatabaseRebuildRequest")]
[AllowAnonymous]
public JToken Get()
{
return JToken.FromObject(DateTimeOffset.Now);
}
}
}
This is for an Azure Mobile App that I've setup for a UWP app. I do want everything else to require authorization, and that part is working fine. I just want to expose this part without needing login from the user.

I have checked your code on my local side and it could work as expected.
For anonymous access, you need to remove the Authorize from your RebuildLocalDatabaseCheckController class for all actions or specify the AllowAnonymous for your specified action. For more details about custom API in azure mobile apps project, you could refer to adrian hall's book here.
Additionally, if you app has been deployed to azure mobile app, for allowing anonymous against your custom API, you need to disable App Service Authentication or enable it with Allow Anonymous requests (no action) as follows:
Additionally, here is a blog about Architecture of Azure App Service Authentication / Authorization, you could refer to it for better understanding of app service authentication / authorization.

Related

Azure Mobile App Service APIkey

I created an Azure Mobile App Service which is currently accessible 'Anonymously'
Anonymous access is enabled on the App Service app. Users will not be prompted for login.
To make it secure I can enable App Service Authentication which will ask users to log in
But this is not what I want - The data in this app is only accessed by Application without the need of each and every user to login to my app before using it.
So you might say, in this case, Anonymous access is fine but I want to restrict it with something at least like an API Key so I will have access to the API which my app can use to access the data to prevent random requests as anyone can just go and use Postman and start getting data without any authentication.
So in short, I don't want individual user authentication, but at least an API Key to ensure only requests made from my app are authenticated and nothing else.
I am using the following in my mobile app to create a connection and also doing Offline sync etc
MobileServiceClient client = new MobileServiceClient(applicationURL);
Any idea how do I do that?
FYI. My server side backend is in C#
Since you are using Azure Mobile Apps, for your requirement, you could leverage Custom Authentication for building your CustomAuthController to login and generate the JWT token for a specific user without user interaction. The core code snippet for logging would look like as follow:
MobileServiceClient client = new MobileServiceClient("https://{your-mobileapp-name}.azurewebsites.net/");
client.LoginAsync("custom", JObject.FromObject(new{Username="***",Password="***"}));
Note: As the above tutorial mentions as follows:
You must turn on Authentication / Authorization in your App Service. Set the Action to take when request is not authenticated to Allow Request (no action) and do not configure any of the supported authentication providers.
And you must explicitly add [Authorize] attribute for your controllers / actions which need to be authorized access. Details you could follow Authentication in the Backend.

How to get windows user name when enabling both windows authentication and anonymous authentication

I've built my api in .net core for the first time in core 2.0. The client is built using vs 2017 angular template.
My api is used even by other applications which may not be using windows authentication. For those functions I want to allow anonymous access. For this reason I've to enable both windows authentication and anonymous authentication.
But when enable both I know I cannot get windows user name. In that case how can get the windows user name?
The following code breaks when I enable anonymous authentication along with windows authentication.
[Route("current")]
public ADUser GetCurrentUser()
{
string accountUser = this.User.Identity.Name;
return new ADUser { Name = accountUser };
}
Can someone please help me how did they dealt the following situation. If not can someone tell me how to do the following things in .net core 2.0
Authenticate the users using windows authentication
Protect the api from being accessed by malicious user.
use some basic functions of the api even by anonymous user.
When using windows authentication I need to be able to get windows user name so I check my user, roles database to authorize them accordingly.
[Update]
As I said I know I get windows user name when I enable Windows Authentication and disable all other authentication types in IIS. But I am unable to access functions which I want anonymous users to be able to access even after using [AllowAnonymous].
I can also read from the following snippet that AllowAnonymous doesn't have any affect if only windows authentication is enabled.
When Windows authentication is enabled and anonymous access is disabled, the [Authorize] and [AllowAnonymous] attributes have no effect. If the IIS site (or HTTP.sys or WebListener server) is configured to disallow anonymous access, the request never reaches your app. For this reason, the [AllowAnonymous] attribute isn't applicable.
Thanks
Here's how I solved this:
IIS
Since you want to allow anonymous users to hit some endpoints of your API, you need to enable both anonymous authentication and Windows authentication.
As a side note, you're right saying that [AllowAnonymous] has no effect when only Windows authentication is enabled because IIS, which sits in front of your API, will reject anonymous requests.
ASP.NET Core authentication
Now that anonymous authentication is enabled, IIS will not try to authenticate requests by default, so without any further configuration, all requests will be anonymous as far as ASP.NET Core is concerned.
The answer to this is to indicate to ASP.NET Core that you want to try to run the Windows authentication process on every request. You can do this this way:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Other code omitted for brievity
// This sets the IIS authentication scheme as the default scheme
services.AddAuthentication(IISDefaults.AuthenticationScheme);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Other code omitted for brievity
// This includes the authentication middleware in the request pipeline
// It will try to authenticate every incoming request
app.UseAuthentication();
// MVC comes next, so the authentication will have taken place
// by the time your controller action is executed against the scheme
// used in AddAuthentication
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
MVC
There's now 2 possibilities in your controller:
The client is compatible with Windows authentication, so User.Identity.IsAuthenticated will return true
The client is not compatible with Windows authentication, so User.Identity.IsAuthenticated will fetch the value false
This means that you can either use the [Authorize] attribute on the specific actions that require authentication, or add the AuthorizeAttribute globally to the application and use [AllowAnonymous] on the actions that can be called anonymously.
Deploy your application to IIS and then Open the Authentication menu for the site.
Disable Anonymous and enable Windows Authentication
Add the following to the ConfigureServices method:
//using Microsoft.AspNetCore.Server.IISIntegration;
services.AddAuthentication(IISDefaults.AuthenticationScheme)
For the APIs or action controllers that you want to secure, decorate them with [Authorize] attribute, then you get the logged in user using HttpContext.User.Identity.Name. Use [AllowAnonymous] on actions that you want to allow access.
In case you want to secure and allow access on the same api, then you need to provide your own implementation of the Authorization filter.
For more details check this link

Adding additional claims to authenticated users in Azure Mobile App

I am in the process of learning the Azure Mobile App possibilities in Azure App Services and have a couple of questions in regards to authentication (and authorization). I use the Azure Mobile App Quickstart to learn the available functionality.
First question:
Do I understand it correctly that I can't implement custom authentication using the Microsoft.Azure.Mobile.Server.Login package as described in the section "How to: Use custom authentication for your application" of the article Work with the .NET backend server SDK for Azure Mobile Apps as I want to use the built-in Azure authentication providers (for authentication with Facebook, Google, etc.)?
I prefer configuration and using the built-in functionality over custom development when it comes to security ;-)
Second question:
I am currently trying to add some custom claims (e.g. a role claim read from an Azure SQL database based on the user's SID) to the users that successfully registered and authenticated in my Azure Mobile App.
What is the best way to accomplish that?
My idea was to add the claims in the Initialize method of the TableController like following and then check for the role using the [Authorize(Roles = "Test")] attribute.
Is there any reason why not to do it this way?
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
myapptestContext context = new myapptestContext();
DomainManager = new EntityDomainManager<TodoItem>(context, Request);
var claimsPrincipal = this.User as ClaimsPrincipal;
ClaimsIdentity ci = new ClaimsIdentity();
string role = "Test"; // get role from Azure SQL database based on user's SID
ci.AddClaim(new Claim(ClaimTypes.Role, role));
claimsPrincipal.AddIdentity(ci);
}
If you intend to use the built-in authentication providers, then you don't need to use the Microsoft.Azure.Mobile.Server.Login. The built-in providers (AAD, Facebook, Google, Twitter, MSA) will take care of all the details for you.
As far as custom claims go, I don't have any specific guidance. You could put it in the controller initialization, or you could add a piece of custom middleware which injects it, or even a callback in Global.asax. Whatever works best for you and your app.
There is a good article describing how to add custom claims to the Identity by using a custom token handler. In the handler the roles for the user are added as claims.
See here: https://blogs.perficient.com/microsoft/2016/05/how-to-add-custom-claims-to-azure-mobile-app-authentication/

How to implement Authentication Across MVC 5 Application and Seperate Web API Application

I am building an online application using AngularJS on the front-end, hosted in an MVC 5/Web API application (basically a single-page application). However I have a hard constraint: the application's data will be held in a private network. I have to build a second Web API application inside the private network that exposes the web application's functionality. Further, the user authentication needs to happen inside the private network API (so the private network API will act as the authentication provider), as this is where the user tables exist.
The app in the DMZ is basically going to act as a proxy to the web API in the private network. So every request received in an ApiController in the UI API will be calling the private network API, ideally passing the token on received in the initial request.
From an authentication perspective, this is what I need:
User navigates to the site, can see only certain pages (I want to use MVC filters in the view controllers to control access).
They will log in once with a username and password.
After login the user can navigate to application pages and as a result the pages will call into the DMZ API for data.
This DMZ's API controllers will be calling into the private network API.
Both APIs whould be able to identify and apply authorization on their controller methods, based on the user's credentials.
If I didn't have a need for the second tier of API I would just use the MVC Single User Authentication implementation, which provides support for both cookie (UI) and token (API) authentication.
Any help providing insight into how I can do a similar thing with the above scenario would be much appreciated. (I guess my requirement is a bit like Windows impersonation for the UI web app).
See below for a high level view of the static architecture:
You may want to look at Azure service bus relays, which are designed to bridged the corporate firewall and call on-premise APIs.
Your WebAPI service would authenticate against the service bus to be allowed to call your service through it. You can pass user credentials using a bearer token in the request.
I'm not sure, but you may need to change your backend service implementation to use WCF though. You can find an explanation of the use of relays in Microsoft Dynamics in this link.

how to build domain based Multi-tenant SaaS solution built using OWIN claims based authentication

I'm attempting to create a SaaS solution and i want each tenant of my application to have its own Access Control Service (ACS) server or identity server configuration, I plan on determining the current tenant by the subdomain currently being visited
eg tenant1.Myapp.com, tenant2.Myapp.com
I want to be able to have different tenant config for each tenant and i don't want each tenant to be aware of other tenants currently registered.
I will have custom branding for each tenant
public partial class Startup
{
private void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions() { LoginPath = new Microsoft.Owin.PathString("/Authentication/SignIn") });
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
MetadataAddress = "https://XXXXX.accesscontrol.windows.net/federationmetadata/2007-06/federationmetadata.xml",
Wtrealm = "urn:operations.web"
}
);
}
}
The above code works for a single tenant application but there is no way of knowing in advance which of the ACS identity providers to use for authentication.
Some of the tenants want to be able to login users using Google, Microsoft Account, Facebook
I see you are using ACS to enable multiple IPs in your application. That's a great first step though the ACS functionality is under process to be folded into the AAD.
In your case you need to download the json feed of all your IPs from the ACS and then filter it based on the information in the request headers that contains the subdomain name.
Mu blog post here takes you all the way to this point and then you need to go the rest of the way yourself.
http://magnusmartensson.com/mvc-application-using-owin-to-achieve-federated-authentication
A typical ACS json feed address looks something like this:
https://{mytenant}.accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=http%3a%2f%2flocalhost%3a7664%2f&reply_to=http%3a%2f%2flocalhost%3a7664%2f&context=&request_id=&version=1.0&callback=
When you get on that feed you will receive an array of your configured IPs in the ACS:
[
{"Name":"Windows Liveā„¢ ID","LoginUrl":"https://login.live.com/login.srf?wa=wsignin1.0&wtrealm=https%3a%2f%2faccesscontrol.windows.net%2f&wreply=https%3a%2f%2fSOMENAME.accesscontrol.windows.net%2fv2%2fwsfederation&wp=MBI_FED_SSL&wctx=cHI9d3NmZWRlcmF0aW9uJnJtPWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnJ5PWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJm0","LogoutUrl":"https://login.live.com/login.srf?wa=wsignout1.0","ImageUrl":"","EmailAddressSuffixes":[]},
{"Name":"Google","LoginUrl":"https://www.google.com/accounts/o8/ud?openid.ns=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0&openid.mode=checkid_setup&openid.claimed_id=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0%2fidentifier_select&openid.identity=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0%2fidentifier_select&openid.realm=https%3a%2f%2fSOMENAME.accesscontrol.windows.net%3a443%2fv2%2fopenid&openid.return_to=https%3a%2f%2fSOMENAME.accesscontrol.windows.net%3a443%2fv2%2fopenid%3fcontext%3dcHI9d3NmZWRlcmF0aW9uJnJtPWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnJ5PWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnByb3ZpZGVyPUdvb2dsZQ2&openid.ns.ax=http%3a%2f%2fopenid.net%2fsrv%2fax%2f1.0&openid.ax.mode=fetch_request&openid.ax.required=email%2cfullname%2cfirstname%2clastname&openid.ax.type.email=http%3a%2f%2faxschema.org%2fcontact%2femail&openid.ax.type.fullname=http%3a%2f%2faxschema.org%2fnamePerson&openid.ax.type.firstname=http%3a%2f%2faxschema.org%2fnamePerson%2ffirst&openid.ax.type.lastname=http%3a%2f%2faxschema.org%2fnamePerson%2flast","LogoutUrl":"https://www.google.com/accounts/Logout","ImageUrl":"","EmailAddressSuffixes":[]},
{"Name":"SOMENAME","LoginUrl":"https://login.windows.net/3c54a3bf-d2b0-4dae-bdd6-61d05145c8be/wsfed?wa=wsignin1.0&wtrealm=https%3a%2f%2fviewmybox.accesscontrol.windows.net%2f&wreply=https%3a%2f%2fviewmybox.accesscontrol.windows.net%2fv2%2fwsfederation&wctx=cHI9d3NmZWRlcmF0aW9uJnJtPWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnJ5PWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJm0","LogoutUrl":"https://login.windows.net/3c54a3bf-d2b0-4dae-bdd6-61d05145c8be/wsfed?wa=wsignout1.0","ImageUrl":"","EmailAddressSuffixes":[]},
{"Name":"Facebook","LoginUrl":"https://www.facebook.com/dialog/oauth?client_id=284082335104349&redirect_uri=https%3a%2f%2fviewmybox.accesscontrol.windows.net%2fv2%2ffacebook%3fcx%3dcHI9d3NmZWRlcmF0aW9uJnJtPWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnJ5PWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJmlwPUZhY2Vib29rLTI4NDA4MjMzNTEwNDM0OQ2&scope=email","LogoutUrl":"https://www.facebook.com/logout.php?access_token={0}&next={1}","ImageUrl":"","EmailAddressSuffixes":[]},
{"Name":"Martensson Consulting","LoginUrl":"https://login.windows.net/8e717ff8-8b9b-4185-b61c-aea1fd724035/wsfed?wa=wsignin1.0&wtrealm=https%3a%2f%2fviewmybox.accesscontrol.windows.net%2f&wreply=https%3a%2f%2fviewmybox.accesscontrol.windows.net%2fv2%2fwsfederation&wctx=cHI9d3NmZWRlcmF0aW9uJnJtPWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJmJnJ5PWh0dHAlM2ElMmYlMmZsb2NhbGhvc3QlM2E3NjY0JTJm0","LogoutUrl":"https://login.windows.net/8e717ff8-8b9b-4185-b61c-aea1fd724035/wsfed?wa=wsignout1.0","ImageUrl":"","EmailAddressSuffixes":[]}
]
Naturally you only want to use one of a couple of these IPs for each of your subdomains/tenants/customers. What you need to do is server side filter this feed and provide your login page with only the ones your customer accepts. If it's only one you might even want to redirect from your application straight to that one single option for customer sign in.
This requires you download the login sample page from the ACS and build your own custom version.
Hope this helps!

Resources