Exception access Azure AD B2C using ADAL library for user management - xamarin.ios

Since Microsoft Graph API doesn't have the feature to manage B2C AD Users, from one of the docs we have been asked to use ADAL which required to create a special application in the Azure AD B2C tenant. Created an application key to provide API access from the xamarin.ios app.
AuthenticationContext authContext = new AuthenticationContext(authority);
credential = new ClientCredential(clientId, GraphClientSecret);
authResult = await authContext.AcquireTokenAsync(graphResourceUri, credential);
At the AcquireTokenAsync call we are getting an exception
AcquireTokenHandlerBase.cs: System.NullReferenceException: Object reference not set to an instance of an object at Microsoft.IdentityModel.Clients.ActiveDirectory.BrokerHelper.get_CanInvokeBroker () [0x0000c] in <786d1e888b334ad993ac80d2bc3b6e92>:0
at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<RunAsync>d__55.MoveNext () [0x00389] in <97581c6894a642ef95d008cded8ad4ac>:0
If I change that call to removing the credentials, I just get a login screen.
Packages used:
Sample was taken from Sample from Docs
Any help would be greatly appreciated.

You should NOT call the Graph API using Client Credentials from a native client application (such as a Xamarin/iOS app). This is a HUGE security hole. Client applications are inherently insecure, anyone can reflect the code and grab a hold of your client_id and client_secret which they can use to create/update/delete users in your Azure AD B2C tenant.
Your native client application should call a web API which would in turn call the Graph API. This web API (link to sample) is an API you build which has authorization logic to scope the user management operations.
Once user management in Azure AD B2C is supported via the Microsoft Graph and MSAL, you won't need this API and will be able to use delegated permissions (vs application permissions using client credentials) to have your native client application talk directly to the Microsoft Graph. In the interim, you'll have to stand up your own Web API as per the guidance above.

Related

Accessing MS Graph from API on behalf of user currently signed in to separate web client

I am developing an API(ASP.NET Core) which is accessed via separately hosted web client(React), both hosted on azure as app services.
Client app must have auth based on azure Ad(single tenant, preferably secured by azure auth based on aad).
When the user signs in to client the API must have access to MS Graph on behalf of user. Obviously both resources must be secured, I have tried using azure auth based on AAD on both app services, but I couldn't get a token to MsGraph in this approach with the token obtained from auth to ADD on API side.
Question is, how to avoid passing token to MsGraph with token for azure aad auth from client, and obtain token for msGraph based only on token from aad auth while having only one place for users to sign in and keep both app services secured?
I am using nugget for MsGraph on Api side to interact with MsGraph. I haven't found any sample that refers this specific case.
Scenario: Your application's Web API (protected by Azure AD) receives auth token from a client application (React) and needs to call a downstream Web API (Microsoft Graph) on behalf of the signed-in User.
Conceptual Documentation on Microsoft Docs: Your scenario exactly matches the OAuth 2.0 on-behalf-of flow as explained on Microsoft Docs for Azure AD here Service-to-service calls that use delegated user identity in the On-Behalf-Of flow
Code Samples:
Service to service calls on behalf of the user (From Azure-Samples on GitHub)
Calling a downstream web API from a web API on behalf of user (From Azure-Samples on GitHub)
Using Azure AD On-Behalf-Of flow in an ASP.NET Core 2.0 API (Not directly Microsoft samples, but from Joonas W's blog, who is an MVP)
Important Code
This is how you use the already passed in token to acquire a new token, with which to call the Microsoft Graph API, from your Web API, on behalf of the user.
Preparing the User Assertion:
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
Acquiring a token for Microsoft Graph:
result = await authContext.AcquireTokenAsync(graphResourceId, clientCred, userAssertion);
I ended up with using only Azure Ad + auth validation by code(no azure auth).
The API uses OBO flow, the client app uses implicit flow.
Basically two separate app registrations on aad, the client which has access_as_user permision to the api, and the other one for api which has permissions for MsGraph. You configure it in App registrations(preview)/API permissions. (For detailed guide follow examples below, start with the api)
For Web client I also used scopes: 'access_as_user', 'offline_access', 'openid' in the request for the token, added true for "oauth2AllowImplicitFlow" in manifest and redirect to the yourdomainname.azurewebsites.com, the rest of configuration similarly to the native client in example below.
Useful resources:
API:
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow
(I recommend testing with native client first to check if its set up correctly,
configuration of API will remain the same for separate web client)
Web client:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-implicit-grant-flow
This is solution which suits me at the moment, it might be possible to tailor it better.

How to login on Azure Portal using REST APIs

I plan to implement a C# app that will create Azure resources using REST APIs (API calls to Azure Resource Manager). When calling a REST API you have to authenticate by passing an authentication header "Authorization: Bearer yJ0eXAiOiJKV...".
How do I get this Bearer token? Looking online all that I found is having a Web App , you use its application_id. However i don't have any application and I don't want to create one.
I can replicate the calls that I intercept with Fiddler but I think that that is not the "recommended" way.
Have anyone faced this problem and has a solution?
Short answer: If you're developing a C# application that is going to use Azure REST APIs, then in order to get the bearer token for authentication you do need to have an Azure AD application registration (no way around that, as it's required for you to be able to authenticate using any of the supported OAuth 2.0 grant flows).
There are a few ways to make things more convenient for you though:
Use CLI to create a service principal for RBAC
From Azure Portal, open up the CLI by clicking on highlighted icon.
Now run below mentioned command
az ad sp create-for-rbac -n "MyTestSPForAzureRESTAPIs"
This does multiple things for you in a single command and provides a great way to get started with testing the REST APIs.
The created service principal is added as a "Contributor" to your Azure subscription. You can always go to Subscriptions > Your Subscription > Access control (IAM) and change that as per your requirements.
You get an application ID as well as Password/client secret that you can then use in C# code to get bearer token.
Sample output
NOTE: Since this approach gives you a client secret, you should use this only from server side applications (like a web API or Web App or Daemon service). Do NOT use client secrets from a desktop based app (like console app or WPF app) or SPA in a production scenario.
I say this because desktop based apps or SPAs are not secure enough to handle client secrets and there are other different authentication flows recommended for them. If your case happens to be any of those, look at delegated permissions from your Azure AD application where you can prompt an end user for credentials. Just comment on the answer and I can add more specific guidance around those.
Use Managed Identity in case of App Service or Azure Function
If you plan to host the C# application that you mention, using App Service or as an Azure Function, then you can make use of MSI. Even in this case an application will be created in Azure AD, but you don't need to do that or manage keys (change them regularly etc.). It's a great option, highly recommended if it suits your scenario.
Read here for more details: How to use managed identities for App Service and Azure Functions
If you just want to get the bearer token. I recommand that you could login in your account in the Azure API document. After we login then we could get the bearer token.
If we want to use code to get access token to access or modify resources, create an identity for the Azure AD application is required . This identity is known as a service principal. Then we can then assign the required permissions to the service principal.
How to registry an Azure AD application and assign role to the application, please refer to this document.
The following is demo code how to get the access token with applicationId and sercet key
public static async Task<string> GetAccessToken(string tenantId, string clientId, string clientSecretKey)
{
var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
ClientCredential clientCredential = new ClientCredential(clientId, clientSecretKey);
var tokenResponse = await context.AcquireTokenAsync("https://management.azure.com/", clientCredential);
var accessToken = tokenResponse.AccessToken;
return accessToken;
}

Azure Portal Mobile App Permissions

We just moved to Azure Portal and i created a Xamarin Cross-Platform app that gets authenticated via MSAL.
When i was building the app. it was registered on https://apps.dev.microsoft.com/, and the user was getting authenticated without any problems.
After testing, i registered it on our Azure Portal under app registration, gave it the required permissions as before, and updated the app ID in the code.
Now, i cant even go past my email page. I keep getting the message:"It looks like you're trying to open this resource with an app that hasn't been approved by your IT dept", even though the admin granted the permissions to the app. Not sure where to go from here. Any help appreciated.
Thanks in advance
When i was building the app. it was registered on https://apps.dev.microsoft.com/, and the user was getting authenticated without any problems.
apps.dev.microsoft.com is used to register the application for Azure AD v2.0, and you could leverage MSAL for authenticating users by using AD account or personal Microsoft account.
For the application registered on Azure portal, you need to use the ADAL library. Detailed tutorial about integrating Azure AD (v1.0) with your xamarin apps, you could follow here.
UPDATE:
Based on your scenario, for using MS graph via ADAL, you could create an app under your tenant and add the required delegated permissions to the Microsoft Graph API. The AcquireTokenAsync method would look as follows:
var authResult = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", clientId, returnUri, parent);
Moreover, for differences between app-only and delegated scopes permissions, you could follow here. Also, you could check differences between Microsoft Graph or Azure AD Graph.

Manage user from Azure AD B2C using AD Graph API - secure access

We are building a Xamarin Native mobile apps and using Azure AD B2C for authenticating users using their social logins.
We decided use MSAL native library (Xamarin) for authenticating using B2C. And our mobile app required to manage(full access) the signed-in user profile. Since this feature isn't available in MSAL we have decided to go with ADAL for the time being. Followed the instruction provided in the link below and the sample works. But I started experimenting by deleting the API access provided in the application (created in b2c tenant) and the ran the application with "Get-user" parameter. And the application is still able to get the users from AD. Not sure how secure is this thing?
Then deleted the application key from the B2c tenant application and ran the console application sample. And received an error AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.
Trace ID: cef09957-06bf-462e-a0c3-4ed6bae11e00
Correlation ID: afab126d-8694-479a-8a21-c12eb7cb176c
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet
Any Idea why this is happening. I would like to implement this on a xamarin.ios app and any guidance much appreciated.
The answer to this is very similar to the answer to your other question: Exception access Azure AD B2C using ADAL library for user management, which can be summarized as:
Azure AD B2C does not yet support delegated permissions to the Azure AD or Microsoft Graph. The correct way to work around this limitation at this time is to have your native client application call a web API (using MSAL) which would in turn call the Graph API (using ADAL). This web API is an API you build which has authorization logic to scope the user management operations.
Once user management in Azure AD B2C is supported via the Microsoft Graph, you won't need this API and will be able to use delegated permissions (vs application permissions using client credentials) to have your native client application talk directly to the Microsoft Graph. In the interim, you'll have to stand up your own Web API as per the guidance above.
UPDATE: the Azure AD v2.0 endpoint and Microsoft Graph API now support client credentials flow, so you can also use MSAL for your Microsoft Graph API calls. However if you need to call the Azure AD Graph, then you will still need to use ADAL.

Is there any alternative way to get azure clientID other then registering active directory?

var authenticationContext = new AuthenticationContext(activeDirectoryEndpoint + activeDirectoryTenantId);
var credential = new ClientCredential(clientId: clientId, clientSecret: clientSecret);
var result = authenticationContext.AcquireTokenAsync(resource: windowsManagementUri, clientCredential: credential).Result;
I have this chunk of code which does generate token, is there any other way to get clientID and Client Secret , without using azure active directory app registration?
The way you acquire the token following the OAuth 2.0 Authorization Framework which enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf. .
We can integrate with any platform which support OAuth 2.0. For example, if you want to integrate with Azure AD, you need to register the app on Azure then use this app's property to integrate with Azure AD to acquire the token. Same as Google, Fackbook etc.
More detail about OAuth 2.0 Authorization Framework, you can refer here.
If you're willing to use Powershell, you can use the Azure AD v2.0 cmdlets. This allows you to create an app in your tenant, and will return the AppID.
The specific cmdlet you'll want to checkout:
https://learn.microsoft.com/en-us/powershell/azuread/v2/new-azureadapplication

Resources