I've implemented an ASP.NET Web API app as an Azure App Service. It has an App Registration, everything works as expected. I can hit the API from a browser and see all the JSON it returns. Now what I want to do is ensure that nothing except one or more applications from a set list can actually get anything from this endpoint. The applications needing access will all be custom ones in my organization/tenant. With all the flexibility and options, I'm having a very hard time determining what I need to do to lock the API down in this way.
I was envisioning having some client secrets the API knows about, and let the authorized applications supply them. Other methods would certainly be acceptable.
I'm certain this must be a duplicate question, but due to the plethora of information out there, and the myriad techniques for running applications on Azure, I can't seem to find just the right solution for my simple case.
It sounds like you have implemented interactive browser redirect-based authentication on the API.
Instead, you should implement JWT authentication on the API.
Then in Azure AD you can define permissions that can be granted to client applications.
In that way you can control which app can do what.
https://joonasw.net/view/azure-ad-authentication-aspnet-core-api-part-1
https://joonasw.net/view/azure-ad-authentication-aspnet-core-api-part-2
https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent
Related
One Azure App service hosts a asp.net core API, another different Azure app service hosts a Web app. The web app can be accessed by end users that don't need to sign in (public). The web app calls the API. How can the API access can be restricted so that only the web app hosted in Azure can make calls to it, but end users cannot directly call the API end points, but the end users can still access the website (webapp)?
You asked a simple question that risks taking you down a rabbit hole. There are many ways to secure an API. The good ones require some thought.
On way is to involve a token server. The application and the token server share secrets. When application that wants to call an API, it is somehow redirected to the token server, and is granted a token. The session is redirected back at the API. The API checks with the token server that the token is authentic. If it is, the API serves the data, otherwise it fails.
This is an incredibly simplistic description of what really happens. Read everything in https://oauth.net/2/ for more details. Azure has mechanisms in the portal that can be used. https://identityserver4.readthedocs.io/en/latest/endpoints/token.html talks about how Identity Server could be used. There are other services of varying complexity and expense to do this. There are experts with varying rates that can help. I hope these couple links can get you started on your security journey.
you should be able to tweak the access restrictions of the app service to control the inbound access.
It allows to IP restrict/ Service tag based restrictions for an app service to accept traffic only from these entities.
I developed my Heroku app that exposes APIs only (no UI) and it works fine.
But how can I restrict the APIs to certain authorized/authenticated users only?
I absolutely need an authentication layer to protect the app APIs and prevent unauthorized accesses. A sort of login(user, psw) call to use before an external system can start invoking my API.
But I don't find any reference in the docs, it only says that these are the main security best practices:
Heroku SSL
Force the use of HTTPS
Trusted IP Range
Any idea?
That's something you'll need to implement at the application layer and not something that Heroku provides. At it's simplest you could implement basic auth in your app so that the user would pass them with their request, a more complex solution would involve user accounts and oauth etc etc.
You could implement all the authentication logic directly in your app.
Alternatively, take a look Auth0, which basically provides you with authentication and identity management as a service. You can easily add Auth0 to your Heroku app as a free add-on via the Heroku Elements marketplace.
They have lots of different use-cases and associated walk-throughs, and they offer a very generous free-tier.
From your requirements, it sounds like you might want to look at Auth0 Machine to Machine applications, using the OAuth2 Client Credentials Grant. With that, your external system(s) would basically need to authenticate with Auth0 using a Client Id and Client Secret (that you could generate in Auth0 and supply to them). Then, they would access your API with a JWT that you could easily validate in your app (Auth0 will provide you with generated code in many different languages for you to do that very easily). Your API will then reject requests without a valid JWT (by sending a "401 Unauthorized" response).
This may all sound a little intimidating at first, but it's really worth going through the relevant Auth0 "quickstart". They really go out of their way to try to make it as easy as possible!
We have a multi-instance Saas Application:
Each of our clients is given their own instance and their own subdomain for the site.
Our application (Web app & API) is protected by Azure, currently with the ADAL javascript libraries
We also have a second API for system-level integration that needs to be protected, currently using a second 'native' azure app, but this is likely incorrect and we want to consolidate
Our application reads and writes to the Azure AD both through the AzureAD Graph API and Microsoft Graph API (including password reset calls)
We're looking at Azure AD application configuration options and want to make sure we're building the most sensible and secure Azure AD Application. Here are some of the documentation we've been looking at:
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds
https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-compare
We want the application to be multi-tenant to ease configuration, and allow availability in the Gallery; but when looking into doing so we're left with some security questions.
A. Which application version to use
1) v1. Allows access to both Graph API. And as suggested by Microsoft we should use this when we're not concerned with Microsoft Accounts.
2) v2. When looking at the MS Graph API documentation it recommends using v2. Reportedly doesn't work for AzureAD Graph API? Allows the same app to be of multiple types (Web App/API and native), which we may or may not need to protect both our web api and our system api (which we're still trying to model).
B. How to manage the reply URL when our clients have different sub-domains?
I've noted the following options:
1) On the app registry, we add the reply urls for all of our customers. This seems okay because we only need to do it once, but feels odd. Is there a limit to the number of reply urls?
2) Have one reply url, but manage an external tool to route the responses to the correct instance, leveraging the state url parameter. Microsoft seems to be suggesting that in this link: https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/authenticate I'm not sure if ADAL allows us to set the state for a return subdomain url though. Is this approach common?
3) Is it possible for each ServiceProvider instance in our client's directories to configure the reply url to their own subdomain? I feel like this would be the cleanest approach, but I don't see documentation for it. It would be nice if we could set the replyURL programmatically as well.
C. How to manage authorization to the Graph APIs (AzureAD and Microsoft Graph)
I've noted the following options:
1) Use the client credential flow, with a single application key (used for all clients). As clients subscribe they will admin consent with our app to give the application permission to their directory. Of course we'd do our best to keep that key secure. But if for some reason it was compromised this would put all of our clients at risk, not just the one instance that was compromised.
2) Same as 1, but use a certificate instead of a secret key. I understand this could be a little more secure, but I don't see how it wouldn't suffer from the same issue as 1.
3) Instead of using application permissions, use delegated permissions with an admin user. This would be good, in that it inherently prevents one instance of our app from talking to the wrong directory. However changes to the administrator may interrupt service; and I think it is best audit-wise that our application is responsible for the changes it makes. (Also, do delegated permissions allow for password resetting? I know for app permissions you need to run powershell script to upgrade the application's directory role)
4) Is there some way for the service principal to generate a unique key for it's directory on creation? can this be handed back to our app programmatically? Perhaps during admin consent?
Really good questions. I'll try to answer each to the best of my knowledge, but if someone has other ideas, feel free to comment/add your own answer.
A. Which application version to use
v2 should allow you to call Azure AD Graph API. The documentation you linked shows an example of specifying Azure AD Graph scopes:
GET https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=2d4d11a2-f814-46a7-890a-274a72a7309e&scope=https%3A%2F%2Fgraph.windows.net%2Fdirectory.read%20https%3A%2F2Fgraph.windows.net%2Fdirectory.write
The main decision point if you should use v2 is: Do you need to support Microsoft accounts which are not in an Azure AD? If yes, you need to use v2. Otherwise there is no problem using v1 (well, lack of dynamic permissions).
Since you are using Azure AD Graph to modify things, I'm going to guess pure Microsoft accounts will not work for you. I would recommend sticking with v1.
v2 also has some limits: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-limitations
B. How to manage the reply URL when our clients have different sub-domains?
I could not find documentation on a limit for URLs. It could be that you can add however many you want. But I am not sure :)
If your subdomains look like this: https://customer.product.com, you can configure the reply URL as:
https://*.product.com
It will then allow any subdomain to be specified in the redirect_uri.
Though note that at the time of writing this, wildcard reply URLs are not supported in v2.
C. How to manage authorization to the Graph APIs (AzureAD and Microsoft Graph)
Using multiple keys makes no sense as they are all equal anyway :) Any of them could be used to call another tenant.
You can store the secret/certificate in an Azure Key Vault, and then use Azure AD Managed Service Identity to get it on app startup.
I would prefer using delegated permissions, but if the users of the app won't have the rights to do the things your app needs to do then that does not work.
I would just make sure it is not possible for a customer's instance to call to the APIs with another tenant id. And also make sure token caches are separated in such a way that it is not possible to get another tenant's access token (an in-memory cache on the instance would be good).
I'm making an iOS/Android app using Xamarin (not Xamarin.Forms, just regular Xamarin). I'm using the shared library set up rather than PCL. I want my app to call an Azure function but I'm unsure of the safest/best way to handle this. I have it set to "Function" for the "Authorization level". The test URL includes the "?code=..." portion in it. I was under the impression that if I put that in my C# code with the "code" value exposed that it was considered a bad idea from a security perspective.
I'm lost as to the safest/best way to deal with this. I've read that setting it in app.config is also a bad idea. I found some references for a web app that suggest using the connection strings that are available in the azure portal, but since this isn't a web app, I'm unsure of how I'd actually retrieve those values in my code (or if that's even possible).
So how would you suggest I handle setting the value for "code" so that I can call my function and avoid a security problem?
UPDATE: Providing more info as per request:
I'm using MSAL to authenticate my users with a B2C active directory. I already have that part working and have received a token authenticating the user.
I also just now enabled authentication in my functions.
I was under the impression that to call my function from my mobile client I had to make a new HttpRequestMessage. I'm unsure of then what I'd place in it to pass my token along.
Just to make sure I understand, your concern is about embedding secrets (the ?code=XXX value) in your iOS/Android app, correct? If so, yes, this is generally considered bad security practice. It's best to assume that anyone who can download your app will have the ability to discover these secrets and use them any way they want.
The recommended way to authenticate with a backend service, such as Azure Functions, from a mobile device is to use interactive authentication - i.e. some kind of OAuth flow. You can build it yourself, or you can use the built-in functionality of Azure Functions and Azure App Service to help you (Azure Functions is built on top of App Service). Here is a resource which might be useful:
https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-overview
https://contos.io/working-with-identity-in-an-azure-function-1a981e10b900#.vcjit3ntw
The API Key (code) is indeed not meant to be used by clients you distribute externally, so it shouldn't be used by your mobile app.
The most straight forward option here would be to use the built in App Service Authentication features with Azure Functions and implement an authentication flow in your app, which would allow you to securely authenticate the user.
Sharing more information about your scenario may help identify alternatives.
I have the following scenario:
1.- A web api project in Azure, that I want to secure using Azure AD (I don't mind Token, cookie, whatever, as far as it meets the entire scenario)
2.- An Azure web site in asp.net MVC, also secured by Azure AD. This website has to call the web api controller with SSO (I'm using same Azure AD in the entire scenario)
3.- Some JavaScript code running in a page in SharePoint Online, also calling the web api controller in any secure way (The Office 365 tenant is also using same Azure AD). If you don't know about SharePoint, let's say I have an SPA project where I can only use Javascript and html (no server side code).
Following some of the MS Azure AD samples and some blogs from Vittorio Bertocci I'm able to get the points 1 and 2 working fine, using OWIN and Oppen ID connect. However, seems impossible to achieve point 3. As I'm inside a page in SharePoint Online, I can only use javascript, and not any server side code. I'd like to get a valid token for the current user, that is already logged in SP, and remember that SP uses same Azure AD that web api site.
Can I call the Azure AD and get a valid token, just from client code?
I'm open to any possible solution. I can do whatever in the web api project. If you are thinking in a SharePoint app with an appPart, and the appPart calls the web api from server side code, I agree that will work, but it's an option that is not allowed at the moment :(
Many thanks.
I have similar needs. While waiting for a Microsoft sponsored solution we’re working on the following approach.
3) in Your solution (i.e. HTML page with JavaScript, hosted in SharePoint Online and running in Browser) will call Services in 1) (i.e. Web Api Service layer in Azure).
In Our case we only want to validate that the calls made from SharePoint Online (via users browser, i.e. JavaScript) originate from a correct Office 365 / SharePoint Online user in our tenant.
We are opting out of using the App Model as we only want some simple HTML / JavaScript pages in our Intranet and don’t want App Webs. The Web Api server side code is kind of our “Web Part” code behind.
Change to the solution after trying it out and having workable code:
The auth cookies are ReadOnly and cannot be used. Instead we have registered one metod in our service layer as App in SharePoint Online (via appregnew.aspx). That methods url (e.g. https://cloudservice.customer.com/api/authentication/token) is registered as App start page in the app manifest and is deployed to a site Collection.
Now we can call our App via https://customer.sharepoint.com/sites/devassets/_layouts/15/appredirect.aspx?instance_id={GUID} i a jQuery ajax call and parse the result. AppRedirect sends the correct SPAuthToken which we use in our service endpoint (i.e. App start page) to call back to SharePoint and check context.Web.CurrentUser. User email is then stored in Table Storage with a generated Token which we send back to the caller (i.e. the jQuery ajax call to app redirect).
That token is then used in all other service layer calls in order to be sure of who is calling our service layer and in some cases perform authorization in our service layer.
Note, You can use the same approach in order to store Refresh and AccessToken in your client and provide that in all calls to your service from your client and use those tokens in order to do App Calls back to SharePoint. This enables HTML UI in SharePoint host webs and server code using user context in Azure service layer.
To follow up, ADAL.js has recently been released, and the ability to use CORS with O365 APIs was recently added, enabling a scenario for script clients to communicate with services protected by Azure AD, such as your Web API.
http://www.andrewconnell.com/blog/adal-js-cors-with-o365-apis-files-sharepoint
UPDATE 2018:
This is now supported by SharePoint Online and the SPFx development model, and officially documented, for instance here
Consume enterprise APIs secured with Azure AD in SharePoint Framework
Being said that the work done meanwhile by Vittorio, Kirk, and their teams, but extending that also to Andrew that has delivered great samples, is awesome; that doesn't really fully reply the original question because one of the requirements is to don't run the component as Add-in Part.
If you try to use ADAL JS (which starts its own OAuth flow) hosting that directly in a SP page, that's not going to work, or anyway you can expect a weird behavior for the user (cause of client redirects happening on the browser).
The solution proposed by Peter Karpinski is interesting, and will work matching the requirements in the original question, but requires quite some complexity and additional management/resources.
This recent article provides an alternative solution similar to Peter's one, but requiring less 'extras' and somewhat simpler, also reusing user's SP identity.
Consuming Azure Hosted Web API from SharePoint Online using JavaScript and Office 365 identities
and doesn't either require the use of ADAL on the client side and the implementation of custom security provider / token issuer on the server side.
The identity (cookie) will be passed via properly handling CORS (documentation) on both sides.
However, as you can read in my comments to that blog, this won't work normally with IE due to its security zone implementation. You'll have to be sure you have control on IE security zones on the clients, or have an alternative solution specific for IE.
As of today AAD does not support the OAuth2 implicit flow (or OpenId Connect variants) hence you can't obtain a token from AAD using a user-agent (browser), regardless of whether you hit the wire handcrafting the protocol or using a library.
However keep an eye on future announcements, as this is an important scenario for us!
HTH
Cheers,
V.
update we now support the implicit flow on our server, and we released a library for helping you consume the new feature: http://www.cloudidentity.com/blog/2015/02/19/introducing-adal-js-v1/
Thank youi for r your patience!
The fact that you say you can use only HTML/JS let me guess you're having a SharePoint-hosted App.
Azure AD Authentication Library (ADAL) doesn't provide yet in this moment support for HTML5.
I've been looking since a while (almost one year) on how to implement something as you say; but I couldn't find any working solution, which doesn't make use also of some 'code-behind'.
I'd suggest you then to move to a Provider-hosted App, where you'll be able to have some C# code, and make use of ADAL to retrieve and reuse the OAuth token.
Also, I think is worth to look at this documentation page:
Choose patterns for developing and hosting your app for SharePoint
at section Match your hosting pattern with your development goals
thanks for your help.
Well, it's not a SP-Hosted App, but it's same scenario. It's just a SP page in SP Online, so I can only use JS code like in a SP-hosted app.
As I said in my question, I agree the Provider hosted app is likely the right (or at least, the unique) solution, but that means to build and app, deploy it, and add teh appPart manually to the page (is not easy to package in a WSP). So, this solution is quite hard, when you only want to make some AJAX calls and show some data.
However, after all that I've seen, I think we can't do anything else. I'm gonna wait some more days to see if someone know any weird workarround that could work, and if not, I'll mark your answer as valid.
Thanks again!