connect azure function to b2c - azure-active-directory

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.

Related

How do I check if the user from a non-Graph Azure AD token is a member of an email distribution list in an APIM policy

Have an API in Azure API Management (APIM).
The API operation validates a JWT generated by Azure Active Directory (AAD) using a scope from a backend app registration (the scope is NOT User.Read). Note: client id is another app registration which is an authorized app of that backend scope.
After the JWT is validated, am I able take that token, extract user info out of it and verify if the user is part of a email distribution list (DL)? If so, how to do it within an APIM policy?
I am aware of MS Graph APIs. Using Postman I can confirm the DL is listed in the tenant's groups and can get its group ID. I can also confirm the user is a member of the group. The bit I'm stuck with for Graph API is that it needs a different token to the one supplied by the client application (due to he scopes being from different domains custom app registration vs graph) and I'm stuck at this point. Should I make the client app also get a graph token and pass it in a separate header, or is there way to orchestrate things from within APIM or something else?
The non-APIM part of this solution is provided by a Microsoft article. I've summarised those and combined with the APIM parts in the following steps:
In Azure, create a new Azure App Registration (note the client id for later)
Under "Certificates and secrets", add a client secret (note the secret for later)
Under "API Permissions", add a new MS Graph Application Permission (can be User.Read.All, Group.Read.All, GroupMember.Read.All depending on your situation). MS Graph's "groups" includes both AD groups and Distribution Lists (DL). Note: don't use Delegated permission.
Application permissions allow the authorized app to enquire about any user/group. You will need an Azure Admin to Grant Admin Consent for the App Registration to have the chosen Application Permission.
Now in Azure APIM, go to your API and edit the inbound policy.
Validate the JWT from the user making the call (See validate-jwt or newer validate-azure-ad-token) to ensure the User is authorized to call this API.
Extract the oid claim from the JWT (this is the user ID I'll use for the graph call) and save it in a variable using set-variable policy
Add a send-request policy request an auth token for MS Graph using client-credentials flow (this is when you'll need the client id and secret from earlier App registration). Note: secrets should be stored in a secure store like KeyVault but that is outside the scope of this answer.
Extract the access_token field from the JSON response body and put it in a variable using set-variable policy.
Create another send-request policy, but this time to the MS Graph endpoint. For User.Read.All permission you'd use /users/<userIdFromJwtOidClaim>/memberof/<groupId>. MS Graph v1.0 API Reference, and pass the access_token in the Authorization header using <set-header> element.
A status code of 200 indicates the user is a member of the group. IIRC A status code of 403 indicates the user isn't a member of the group.
Use a choose policy to perform logic depending on the user's group membership.
Use return-response policy to send a response back to the user.

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"

user does not exists in the tenant directory error when calling microsoft graph api

I'am trying to call microsoft graph api, I have did the instructions by microsoft documnets as bellow:
1- app registration in azure portal
Supported account types : all microsoft account users
2- calling 'https://login.microsoftonline.com/',tenant_id,'/oauth2/v2.0/authorize' by these parameters:
client_id <- #Application Id - on the azure app overview page
client_secret <-# the secret key for my app from azure portal
scope <- 'https://graph.microsoft.com/.default'
grant_type <- 'password'
username <- 'XXX#outlook.com'
password <- # the user password
tenant_id <-# tenant id for my app from azure portal
but it has this error:
AADSTS50034: The user account {EmailHidden} does not exist in the <tenant_ID> directory. To sign into this application, the account must be added to the directory.
I have registered my app by the same account that I passed through api.
I want to call my todo list from the graph.
based on #MdFaridUddinKiron's response I added some more explanation:
I think something in my domain in azure is wrong, these are some screenshot of it:
1- it shows "common" for endpoints, what should I use? "common" or my tenant:
2- my app authentication tab has some differences, is it important?
3- My domain overview page is look like this:
4- user is added in my active directory 5- user application page:
6- user assigned role:
I tested microsoft graph api successfully by the same user in the graph explorer, I am getting confused how the authentication flow must be.
I just want to call my own todo tasks
As per your comment, please follow the detail steps:
Make sure email you are trying to get token with is exists in azure ad
user list which showed below in details.
https://login.microsoftonline.com/YourTenant.onmicrosoft.com/oauth2/v2.0/token
client_id:b603c7be_Client_id_e61f925
scope:https://graph.microsoft.com/.default
client_secret:NpmwO/KDJ_client_secret:NpmwO_W0kWf1SbnL
username:tenentUser.onmicrosoft.com
password:YourUserPassword
grant_type:password
See the screen shot:
I am getting token as expected
Step: 1
Step: 2
Step: 3
Step: 4
Filter your user from your azure active directory user list as shown below.
Note:
Requested token user must be a tenant user for example YourUser#Yourtenant.onmicrosoft.com
User password must be correct that you are suing to token request.
Make sure your user belong to azure portal on your tenant
Your Client Id belongs to that tenant
Application secret is valid or not expired.
Update:
What should I use? "common" or my tenant?
It depends if you have many tenant in that case you can use common.
For example user need not to remember specific tenant they would
automatically redirected to specific tenant as per the credentials
they given.
For more information you could refer Official document
Feel free to share still you are having problem.

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

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

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

Resources