Adding additional claims to authenticated users in Azure Mobile App - azure

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/

Related

How to add Azure Authentication to my current web application which is using API as well?

So my project has got a two asp.net projects. One is for showing date(User Interface) and the another one is API(for background processes like login, database calls and etc.). Right now my app has Username and Password feature to login. I have setup a startup class in my API which authenticates the user and pass the user token. Now I want to add a feature to login through Azure portal.
Can anyone suggest me a good practice in this situation? Like I don't want to change my code and just add a feature. Should I make changes in API or Web or Both? Meanwhile I was reading about expose api in app registration. Will it be appropriate to use it just for login purposes?
Azure AD supports OAuth2, OIDC and SAML. See more information here. It is probably best to introduce the mechanism through the API first, since it would apply to the frontend as well (though slight modifications may be required there as well).

Azure B2C Logout implementation in ASP.NET Core?

I'm working on a project that requires a B2C implementation and it's my first time using or even hearing about it so bear with me. How do I implement logging out or session invalidation with this Azure service?
I got the sign in and up policy working, but currently I can't find any documentation on how to implement logging out other than this https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-user-flow, which I don't understand for the life of me.
What's the easiest and best practice way of implementing B2C sign out functionality with an ASP.NET Core web app. Help is much appreciated. I don't have any code to offer because not one thing I've tried has worked. I understand that in older version you could just call a tenant customised URL to logout off a session, but I can't find this documented anywhere and I can't tell whether it's legacy or not.
Add an account controller to get more control
https://learn.microsoft.com/en-us/azure/active-directory-b2c/enable-authentication-web-application-options#add-the-account-controller
Then add the sign out path in account controller
[HttpGet("{scheme?}")]
public async Task<IActionResult> SignOutAsync([FromRoute] string scheme)
{
scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
return SignOut(properties,CookieAuthenticationDefaults.AuthenticationScheme,scheme);
}
This document explains how to send a sign out request manually:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/openid-connect#send-a-sign-out-request

Allow access to single API without Authorization?

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.

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!

Service Stack authentication

? - Is it possible to have multiple authentication providers within the same MVC 4 hosted service stack web services, we will have multiple endpoints utilizing internal and external services that require differing levels/types of authentication.
I need initially to implement a couple of custom providers to suit our our needs so that depending on the URL a different authentication provider is utilized, so far I have only found examples of providing a single custom authentication provider.
Yes. You can use multiple providers. Then you could have different roles for different resources (urls) to manage your internal vs external levels.
Take a look at the https://github.com/ServiceStack/SocialBootstrapApi example project. This example has a lot of different authentication providers. Each auth provider resolves to the path /auth/{provider} where provider is resolved using the IAuthProvider.Provider property of your custom providers and the build in providers.
You will need to register each auth provider you want to use.
//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(
() => new CustomUserSession(), //Use your own typed Custom UserSession type
new IAuthProvider[] {
new CredentialsAuthProvider(),
new TwitterAuthProvider(appSettings),
new FacebookAuthProvider(appSettings),
new DigestAuthProvider(appSettings),
new BasicAuthProvider(),
new GoogleOpenIdOAuthProvider(appSettings),
new YahooOpenIdOAuthProvider(appSettings),
new OpenIdOAuthProvider(appSettings),
}));
Then you can login by hitting the different urls like
/auth/facebook
/auth/twitter

Resources