How to access azure digital twin API using Service Principal? - azure-active-directory

My use case is whenever i get a trigger from Cosmos DB in Azure functions, need to interact with Azure digital twin APIs without any human interaction.
From the below link, I understood we can use service principal to achieve it.
Is it possible to configure Azure Digital Twins API access for a Daemon App?
But I don't know how to authenticate service principal with digital twin APIs.
1)What type of authentication is required and how the flow will be?
2)If it is Oauth2, what is the grant type and scope for accessing digital twin?
Thanks in advance.

There is an (almost) undocumented way to use the Digital Twins API without an On-Behalf-Of flow. I use it for automated tasks to manipulate the contents of ADT or to give certain applications read-only view of the data. It all starts with a role assignment. See this snippet from the YAML that I use to provision my ADT instance when I first make it.
- roleId: 98e44ad7-28d4-4007-853b-b9968ad132d1 # Space Administrator
objectId: abcd1234-5556-44a2-1234-402dbd999619 # Service Principal object ID
objectIdType: ServicePrincipalId
tenantId: 1234567-8901-2345-abcd-123456789 # Azure subscription tenant
The ServicePrincipalId object type is described on this page but is never mentioned in any of the samples again. This snippet gives Space Administrator rights to a service principal. You can then use a client secret to retrieve an access token that will allow you access to ADT. When making an app registration for ADT in your Azure Active Directory, go to Certificates & Secrets and make a new client secret.
The next step is to retrieve the objectId of the Service Principal, this is not the objectId of the application registration. When you go to the Overview tab of your App Registration you can copy the Application ID and perform the following command in the cloud console:
az ad sp show --id {the id you copied}
This will show a lot of details about your Service Principal including the objected. Copy this as well.
Almost there, to retrieve an Access Token you need 4 things:
Authority: https://login.microsoftonline.com/{your tenant id}
ClientId: The application id of your app registration.
ClientSecret: The client secret you created.
DigitalTwinsAppId: This is always 0b07f429-9f4b-4714-9392-cc5e8e80c8b0
Retrieving the Access Token in .NET Core
var authContext = new AuthenticationContext({Authority});
var clientCredential = new ClientCredential({ClientId}, {ClientSecret});
var result = await authContext.AcquireTokenAsync({DigitalTwinsAppId}, clientCredential);
return result.AccessToken;
Add that to your headers (HttpClient example below) and you are good to go!
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);

1)What type of authentication is required and how the flow will be?
As the post you have referred to, you should use OAuth 2.0 On-Behalf-Of flow.
The main flow is here: Call Digital Twins from a middle-tier web API.
2)If it is Oauth2, what is the grant type and scope for accessing
digital twin?
You can refer to this sample:
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
And for scope, it should be the digital twin API you want to access. (eg. spaces, devices, users or sensors). See API summary.

Related

Delete document from CosmosDB using Azure Data Factory

My Azure Data Factory has private endpoint connection to CosmosDB and authenticates using System Assigned Managed Identity. The goal is to delete document from CosmosDB using https://learn.microsoft.com/en-us/rest/api/cosmos-db/delete-a-document called from web activity.
I created web activity in Data Factory and put the required headers following those documents
https://learn.microsoft.com/en-us/rest/api/cosmos-db/common-cosmosdb-rest-request-headers
https://learn.microsoft.com/en-us/rest/api/cosmos-db/access-control-on-cosmosdb-resources?redirectedfrom=MSDN
DELETE web activity:
I am using Azure Cosmos DB RBAC so my authorization header looks like this:
type=aad&ver=1.0&sig=token-from-oauth
To get a token I was following this post
https://medium.com/analytics-vidhya/azure-data-factory-retrieve-token-from-azure-ad-using-oauth-2-0-9a3ed3f55013
but I don't know where can I get the client_secret. I found my ADF in AAD under enterprise application so I guess client_id is application Id but there is no client secret to be found there.
get token web activity:
First obvious question is where can I find this client_secret?
The second one is why is this token needed at all? Why can't it just use managed identity for authenticating the request?
Where can I find this client_secret?
Go to azure active directory -> Inside mange go to app registration(if you not created a app registration create it ) -> Go to registered app -> Certificate & Secretes.
Why is this token needed at all? why can't it just use managed identity for authenticating the request?
Managed identities are a way to simplify the authentication process for applications running in Azure, but they do not apply to all scenarios when calling external APIs that require authentication. In these cases, you need to obtain an access token from Azure AD using a client secret.
I reproduce same thing in my environment. Follow below approach.
URL:https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token
Scope : https://cosmos.azure.com/.default
Body: grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>&scope=scope : https://cosmos.azure.com/.default
After execution of web1 activity you will get like this bearer token:
Inside Web2 activity provide valid URL as per below syntax:
https://{databaseaccount}.documents.azure.com/dbs/{db-id}/colls/{coll-id}/docs/{doc-id}
Add dynamic content at header part as shown in the image:
Authorization: Bearer #{activity('Web1').output.access_token}

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.

Retrieving Emails from Office365 using OAuth2.0

I am looking for a complete Step-by-step to accomplish the following objective. I have been looking around and trying many, many ways, but not one of them works.
Objective: using C# .net core code (in Azure Functions) connect to a shared mailbox of Office 365 to retrieve emails [with date filter] to do some processing, then move that email from Inbox into another folder (Processed). I want to use MailKit (or something similar
that is free and has MIT license) to retrieve, load and parse the emails.
What I have done, but of course, I can be way off…
In Azure Active Directory, I have created an App Registration
In API Permissions, I have added and granted (I am an admin) a lot of permissions (everything I guess may be related to this, from
Email, to IMAP, SMTP, POP, Application, User and a bunch of other permissions.
In Certificates & Secrets, I created a client secret and recorded the secret (Value)
From Overview, I recorded the Client ID, Tenant ID, etc.
Code (I tried several variation of this…)
string[] scopes = {"https://graph.microsoft.com/.default" }
/*
for scopes, I have also tried:
“https://graph.microsoft.com/IMAP.AccessAsUser.All”
“https://outlook.office.com/IMAP.AccessAsUser.All”
*/
var authority = authority + tenant;
/*
for authority, I have also tried:
“https://login.microsoftonline.com/“
“https://login.microsoftonline.com/common”
“https://login.microsoftonline.com/oauth2”, etc…
*/
var client = ConfidentialClientApplicationBuilder
.Create(clientID)
.WithClientSecret(secret)
.WithAuthority(new Uri(authority))
.Build();
/* Fails every time! */
CancellationToken cancellationToken = default;
var authResult = await app.AcquireTokenForClient(scopes)
.ExecuteAsync(cancellationToken);
/* MailKit to retrieve emails… */
/*
any step-by-step code using MailKit to
accomplish the Objective would be much appreciated.
*/
Firstly, you should not use this method to get the access token.
var client = ConfidentialClientApplicationBuilder
.Create(clientID)
.WithClientSecret(secret)
.WithAuthority(new Uri(authority))
.Build();
This method is using client credential flow which is not supported to use IMAP.AccessAsUser.All delegated permission.
This method mentioned by jstedfast is using Interactive provider. The interactive flow is used by mobile applications (Xamarin and UWP) and desktops applications to call Microsoft Graph.
So if configuring "http://localhost" as a Public client (mobile & desktop) redirect URI for your application doesn't work, I don't think you could implement it in the C# .net core Azure Function app. Azure Function app doesn't support login interactively within it. You can only use it in a console app.
But there are 2 workarounds which allow you to get the user access token for Microsoft Graph.
Implement Username/password provider to generate the client and access token. But it is using ROPC flow which is not recommended by Microsoft. See details on Warning tip.
Configure additional Login Params in App service to get the access token to call Microsoft Graph. Please refer to CONFIGURING AN APP SERVICE TO GET AN ACCESS TOKEN FOR AAD GRAPH API. The key point is changing the additionaloginparams to the following [“response_type=code id_token”, “resource=https://graph.microsoft.com”]. Related official document here.

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"

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