How to configure on-behalf-of authentication in multi-tenant environment? - azure-active-directory

I have a native client that calls a service I wrote-- that in turn calls the Graph API (using the original caller's credentials).
This is exactly like the 'onbehalfof' sample found here (my code fails the same way as the sample):
https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof
When logging in as a user from the same tenant as the service (tenant A), everything works fine (just like the onbehalf of sample). When logging in as a user from a different tenant (tenant B), I get an exception on this line in the service:
result = await authContext.AcquireTokenAsync(GraphResourceId, clientCred, userAssertion);
(this is line 153 from TodoListController.cs in the onbehalfof sample).
The exception is this:
AADSTS65001: The user or administrator has not consented to use the
application with ID 'de2fb28b-83f8-419d-9b00-3fbce0a60bf4'. Send an
interactive authorization request for this user and resource.\r\nTrace
ID: 6865c420-674a-4adf-a070-3d9b9c500200\r\nCorrelation ID:
7e088563-d7fe-4131-a05c-cbe04dbb2bbd\r\nTimestamp: 2017-03-29
22:56:58Z
The application id above refers to the service I wrote (which is the same line in the TodoListService in the onbehalfofsample).
I configured everything for multi-tenant authentication. But it's the additional call that my service is making to another service (Graph API) that's causing the problem. What additional configuration do I need to do in the Azure portal to make this work?

In the instructions written for the sample you linked above, they address this issue with the following section:
Configure known client applications
For the middle tier web API to be able to call the downstream web API,
the user must grant the middle tier permission to do so in the form of
consent. Because the middle tier has no interactive UI of its own, you
need to explicitly bind the client app registration in Azure AD with
the registration for the web API, which merges the consent required by
both the client & middle tier into a single dialog. You can do so by
adding the "Client ID" of the client app, to the manifest of the web
API in the knownClientApplications property. Here's how:
Navigate to your 'TodoListService' app registration, and open the manifest editor.
In the manifest, locate the knownClientApplications array property, and add the Client ID of your client application as an element.
Your code should look like the following after you're done:
"knownClientApplications": ["94da0930-763f-45c7-8d26-04d5938baab2"]
Save the TodoListService manifest by clicking the "Save" button.
My assumption is that because you are running into this problem, that you have not done this special configuration.
The other option you have is to explicitly request consent between the middle tier and the AAD Graph API. You can do this by having a tenant administrator 'login' and consent to your middle tier service. All you need to do is generate a login url with the middle tier App ID.
However, I strongly recommend you do it the documented way, since this will provide a better experience for your users.

It's working now. I had to make two changes to get it working.
First, on the service side switch to using "common" as the tenant. I had switched to common on the client but didn't realize you had to do this on the service side as well:
<add key="ida:Tenant" value="common" />
Second, change the GraphUserUrl on the service to the following URL:
<add key="ida:GraphUserUrl" value="https://graph.windows.net/me?api-version=1.6" />
The original URL in the sample didn't work (at least for users in another tenant).

Here's the consent dialog that appears when a user from another tenant logs in:
Consent Dialog

Here's my client manifest...
Client Manifest
...and my service manifest...
Service Manifest

Related

How to set up access to Azure blob storage from React app (deployed in Azure web app) with credentials from browser?

I got stuck on trying to access Azure blob storage from React app (thus from browser) with credentials.
And firstly I want to admit, that I am newbie in Azure, so maybe I misunderstood some basic concepts...
My current situation and goal:
I am developing React app (lets say MyReactApp). This app uses some files from Azure blob storage (lets say MyBlobStorage) -> it reads, creates and deletes blobs.
I started to develop it on my local and for this dev purpose I was connecting to MyBlobStorage with SAS - this worked perfectly.
MyReactApp is browser only, so it does not have any backend.
After finishing local development, I deployed it as Azure web app with SAS. What have I done:
created App service (lets say MyAppService)
register app in Azure Active Directory and use it as Identity Provider in MyAppService
After this the app works from Azure url perfectly too.
But my app on Azure should fulfill 2 conditions:
User has to log in with AAD account before access to MyReactApp
App itself must get rid of SAS (because it is not secure as it can be obtained from browser) and use some Azure credentials to connect to Azure blob storage
First condition - user log in:
I enabled "easy" logging in MyAppService -> Authentication and chose users, who can have access.
in Authentication section of app in AAD I set up Web type Redirect Uri as /.auth/login/aad/callback
Still everything works great - the user, who is assigned to the app, can log in and work with the app - so far so good, but now the problem comes
Second condition - I wanted to get rid of the SAS to access MyBlobStorage and use DefaultAzureCredentials:
I turned on managed identity for MyAppService and add it as Storage Blob Data Contributor for MyBlobStorage
I obtained user_impersonation and User.Read Api permissions for my app
I removed SAS and tried to add DefaultAzureCredentials to my code -> but it seems, that they can't be used in browser and only option is InteractiveBrowserCredentails
so I tried to use InteractiveBrowserCredentails like this:
this.interactiveBrowserCredential = new InteractiveBrowserCredential({
tenantId: "<appTenant>", // got from app registration on AAD
clientId: "<appClient>", // got from app registration on AAD
redirectUri: <MyAppServiceURi>/.auth/login/aad/callback // the same as in Azure AAD app,
});
this.blobSC = new BlobServiceClient(Constants.STORAGE_PATH, this.interactiveBrowserCredential);
My current result:
This shows login popup after getting to the page and after another signing in it results in error:
AADSTS9002326: Cross-origin token redemption is permitted only for the
'Single-Page Application' client-type.
I googled it of course and according to some answers I tried to change the Web type of redirect URI to SPA.
I tried it, but some other error showed up:
AADSTS9002325: Proof Key for Code Exchange is required for
cross-origin authorization code redemption.
Surprisingly this should be solved by changing from SPA to Web type...:) So I am trapped...
My expected result
In ideal world, I want to connect MyReactApp to MyBlobStorage without popup and with some secret credentials, just to say something like this.blobSC = new BlobServiceClient(Constants.STORAGE_PATH, credentials);
and be able to work with blobs.
Is it possible to access blob storage from browser without errors of course and ideally without popup, which needs another log in for user?
My complementary questions
Can I use somehow the logging info from the user (from his "easy" AAD logging)? I can get his info with GET call to /.auth/me, maybe it can be utilized, so I can use his info to access the blobs?
The solution should be working on localhost too (I tried to add http://localhost:3000/ to redirect uri, but without success), can it be done?
Thank you all, who read the whole story!

Azure AD Enterprise Application - Identify Caller Application

I have a REST API which uses Azure ADD App registration to allow other apps to call it.
In the Azure Portal, I have registered it as an Enterprise Application and also registered the consumer applications and assigned them Roles appropriately.
The authentication and RBAC works fine.
But the use case that I am working on requires me to identify and log the incoming request calling application's name (The one seen in the portal as 'Display Name', when we view the list of users and groups for an enterprise Application).
As advised in the internet, I am using some Identity related API to read the claims from the request header.
var provider = claimsUser.FindFirst("http://schemas.microsoft.com/identity/claims/identityprovider").Value;
var sid = claimsUser.FindFirst(ClaimTypes.NameIdentifier).Value;
OR
var sid = claimsUser.FindFirst("stable_sid").Value;
But this gives me a GUID value which I couldn't map to any of the consumers of the Enterprise Application.
The clients are all registered in the Azure portal.
In the Portal, I can see the apps in the "Users and Groups" section for the Enterprise application, with their appropriate roles.
In terms of usage, before making the call, the clients generate a bearer token based on the certificate that they get from Azure. The make the call with the bearer token attached to the request header. This bearer token is validated against the Azure AD, in the filters set before every controller..
What I want is to get are the details about this client who has made the call.. As per some repliers, and, to which I agree, the Guid that I get as part of the previous call mentioned above is for the actual user and not the app itself which is making the call.
Can anyone throw some light into it.. some code snippet will be of real help..
I'm not sure what authentication flow you are using, but SID is generally for a user that's logged in, not an application. if your client applications are using client id and secret, the token it returns that you send to the api should include the app registration guid. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#access-control-lists . So the appid and iss should give you the guid of the app registration. using this, you can make a call to graph api, to identify the display name of the app registration. https://learn.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http
If your app is a user login app, and you don't want to make a call to graph, the other option you could do as a workaround would be to create app roles and assign users to them but name the app roles with some convention that includes the app's display name. then the name could come through under roles claim.. https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
those are some options.. but other than calling graph or kinda working around to inject the name into a different claim of the token I'm not sure of any other method to get the "app registration's display name"

connect azure function to b2c

So, I created azure b2c directory, and created inside it application like https://github.com/Azure-Samples/active-directory-b2c-javascript-msal-singlepageapp, and I created azure function in general azure directory that suppose to read blob and return json file. Also I created custom login page for sign in.
I ran my program locally, and I can login, and instead of call API that uses in github, I call azure function and it works.
But now I want to secure access to function, so I make authLevel 'user' and try to make Authentication via Azure Active Directory.
And no mater how I make settings, or I can't connect because I don't have permissions, or I can't use function because I don't have permissions.
Also I get this error The client id ’/.auth/login/aad/callback' specified in the request is not registered in tenant ‘’.”
How should I connect function to b2c so only authorised users can have access to function response.
Setting up B2C authentication for your Azure Functions App is actually really easy:
Create Azure Functions App and write down the URL
E.g. https://myazurefunctions.azurewebsites.net (make sure to make it a HTTPS URL)
Configure your application in Azure Active Directory B2C:
Write down the Application ID
Add a reply URL for your Functions App,
adding the suffix /.auth/login/aad/callback. E.g.
http://myazurefunctions.azurewebsites.net/.auth/login/aad/callback
Get the Metadata Endpoint URL for your Sign-in policy
If you open the details of your sign-in policy, you'll find it right at the top. E.g.:
In your Functions App, on the bottom left select "Function app settings" and go to "Configure authentication":
Turn on authentication and select Azure Active Directory:
Select the advanced settings and enter the following values:
Client ID: The Application ID which you copied in step 2. a.
Issuer Url: The Metadata Endpoint URL from step 3.
Save your settings and you're done!
With the new "User flows (policies)" a few small changes must be made to the selected answer:
Perform Step-3 as follows to get the "Metadata Endpoint URL”:
a) Go to your B2C tenant and click on User flows (policies).
b) Select your login (or sign up sign in) flow and click on “Run user flow”.
c) Your "Metadata Endpoint URL” is displayed at the top of the new window – right beneath the ”Run user flow” heading.
Perform Step-4 and 5 as follows to configure “Authentication”:
a) Go to your function apps and click on your function app (NOT on one of your functions inside your function app).
b) Click on Platform features and then on Authentication / Authorization.
c) Turn on “App Service Authentication”. Select “Log in with Azure Active Directory” and then click on “Azure Active Directory – Configured (Advanced)”.
Continue with Step-6.

Azure Active Directory Web Application without login current user

I am following an older tutorial (https://code.msdn.microsoft.com/Write-Sample-App-for-79e55502) that shows how to create a web application that connects to an Azure Active Directory tenant using ADAL. There is a class library that contains DirectoryService classes that I believe does the work in retrieving AD user properties. I am wanting to create a login method for this project for security purposes, and to be able to identify what user is logged in to the application. Currently there is not a signin method that authenticates against AD by entering a username/password, so I am a little puzzled at how the app can retrieve user properties with just the AppId,Domain,and AppSecret in the Web.config without actually having someone login with either their AD creds or redirecting to login.microsoftonline/{tenantId}.....I do not know if I am making sense, but I want to be able to add a login method so a user is forced to login so it gets the claims for that specific user but if I am already using ADAL, can I also incorporate Owin?
There are two parts to your question -
1. How is this app working today, without asking end users to explicitly sign in
This sample is using Client Credential Grant, in which you don't need end users to sign in, but use the identity of an application itself to get the auth token and use it for further operations. As you mention yourself, it just needs AppId, Domain and App Secret from web.config. You can read all about it here - Client Credentials Grant
Related code to acquire token is available in MVCDirectoryGraphSample\Helpers\MVCGraphServiceHelper.cs file
AuthenticationContext authenticationContext = new AuthenticationContext(authString);
ClientCredential clientCred = new ClientCredential(ConfigurationManager.AppSettings["AppPrincipalId"],
2. How to add a login method to force users to sign in to your web application
You can start using something like Authorization Code Grant flow, instead of client credentials. Look here for documentation on different scenarios that Azure AD supports. Your case looks like a web application calling Graph API, described here
Exact code sample to do this is available here - Code Samples

Are there security concerns exposing the clientId and tenant in client side code when using adal/adal-angular.js

I'm in the process of implementing AAD single sign on in our application and we will be using the adal.js/adal-angular.js library with our MEAN stack application. Part of initializing the library is to call init() and provide the tenant and clientId
adalProvider.init(
{
tenant: "mycompany.onmicrosoft.com",
clientId: "05bdd8d7-XXXX-XXXX-XXXX-5f2769f8b9b6"
},
$httpProvider
);
for example.
If someone views the source and takes the tenant and clientId can they use that somehow in their own application maliciously?
Does AzureAD check the URL the request came from and block it if it's not the configured login url?
Seems as though the clientId is more like a public key but if the only 2 things needed for an app to trigger authentication with AzureAD is the tenant and clientId and those are exposed client side in source code that someone could use them to create a phishing site X or to grab id_tokens if the request is redirected back to their site X rather than the original site
Does Azure rely on the configured settings in the application setup and protect against this?
I'm still getting a grasp on the OpenID Connect and OAUTH 2.0 finer points so forgive me if this question has an obvious answer.
Adal.js uses the Implicit flow (as per OpenID connect / oAuth 2 specifications) and exposing the ClientID (and tenant id of AAD) doesn't pose any security risk.
While registering the Clients in Azure AD administration panel, we specify a Redirect URI for the client. This is the Application URL for which users will get redirected after successful authentication.
So even if a malicious client tries to use your clientid and tenant id, the users will be redirected back to the registered URI(which is your app) after authentication and not to the malicious site
In implicit flow the application doesn't collect any username / password, IDP/OP (i.e AAD) manages this part - so user credentials won't be compromised as well
**For other flow types (Authorization code, Client credentials,etc) we have something called client-password along with ClientID. This shouldn't be exposed to public clients.

Resources