Connecting to exchange online using Microsoft Graph APIs through a Demon application - azure-active-directory

I'm trying to connect to exchange online and do certain operations with the emails using Microsoft Graph API 1.0 and this is all done in a demon program. I'm using Client Credential workflow for authentication, below is the small piece of code
AuthenticationContext authenticationContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, azureEndPoint, tenant));
ClientCredential clientCredential = new ClientCredential(clientId, clientSecret);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientCredential);
But for this code to return the authentication token I have to get Application Permissions to the azure app id against microsoft graph api. The caveat here is if the permission is granted, the application id will have access to read emails of all users in the organisation and due to this reason tenant admin has strictly refused to grant the permission.
I tried my luck with consent framework but that requires user intervention to enter his/her id and password which is not possible in case of a demon program. I read few blogs like below but they all end up entering the user id password to get to the redirect url which defeats the whole demon thing https://blogs.msdn.microsoft.com/exchangedev/2015/01/21/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow/
Is there any way I can give read/write access to azure application id for specific email ids in the tenant? Or alternatively any smart way to somehow get to the mailbox without user intervention?
Thanks in advance,
Vivek

You can only use app permissions with client credential grant flow.
To access only specific users' emails, you'd have to do a different approach.
This does require each user to consent individually.
Have the users login to your app, require consent for access to their email.
Upon returning to your app, acquire a refresh token and store it securely.
A refresh token is user-specific.
Then in your daemon service you acquire an access token for each user using their refresh token.
If the acquire fails because the refresh token has been invalidated,
the user will need to be notified to login again.

This is now resolved as microsoft has introduced a new concept of limiting application permissions to specific mailboxes or set of mailboxes using Group Policies. Check here https://learn.microsoft.com/en-us/auth-limit-mailbox-access

Related

Can't access to power bi api from ROPC

I try to get reports from power bi api. There is app with permissions, enter image description here. My request enter image description here. If i insert "openid" to scopes or any of Microsoft Graph scopes, request return access token. This token dont let me access to reports. If i insert "Report.Read.All" or any of Power BI scopes, i recieve invalid_grant error: 'The user or administrator has not consented to use the application with ID named 'Интеграция с Битрикс24'. Send an interactive authorization request for this user and resource.'. Request from error message was send was sent by me many times. enter image description here. Please tell me what could be the mistake. What setting could I forget?
need to insert full url scope in request body to access power bi token. https://analysis.windows.net/powerbi/api/Report.Read.All instead of Report.Read.All
I could help you with an alternative where you can update the Graph Client to a Newer version. The admin of the subscription can grant the consent through the portal as shown below from Home > App > API Permissions.
We have done the following steps:
Using the following Steps:
Revoke all admin consent.
Remove all permissions
Add removed permissions back.
Grant admin consent.
Here is the Microsoft Document which you can refer to : Construct the URL for granting tenant-wide admin consent

Unable to Send email using microsoft Graph API using delegated permission with Username and Password provider

I am trying to send email using UserNamepassword provider with delegated permission but getting error as below
AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '00000003-0000-0000-c000-000000000000'. Trace ID: 66ecbe3d-56d1-4850-8310-dd33cb8d3900 Correlation ID: b2f61146-44d3-4997-ab99-5370bbac6b04
When I tried with Application permission with send.mail, I am able to send email as any user.
but as per the company restrictions i need to send email using delegated permission.
How to achieve this as error is with respect to Multi factor authentication as MFA has been enabled on our account.
IPublicClientApplication publicclientapplication = PublicClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.Build();
UsernamePasswordProvider authprovider = new UsernamePasswordProvider(publicclientapplication, scopes);
await graphServiceClient.Me
.SendMail(email, false)
.Request().WithUsernamePassword("Username", passwordstring(stringpassword))
.PostAsync();
Please help here with options.
If the user has multi-factor authentication (MFA) enabled, then you can’t use username/password to obtain tokens, because ROPC flow does not support MFA, according to the documentation:
If users need to use multi-factor authentication (MFA) to log in to
the application, they will be blocked instead.
The easiest way is to use the auth code flow, which supports users with MFA enabled to log in to the application. When using this flow, you need to log in to the user to obtain the authorization code, and then use the authorization code to redeem the access token.

az account get-access-token - fails to fetch token in user's context

I have a user managed identity, for which I want to generate a token
I tried in user's context
az login
az account get-access-token --resource "<client-id of user managed identity>"
I get the error
Get Token request returned http error: 400 and server response: {"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID '04b07795-8ddb-461a-bbee-02f9e1bf7b46' named 'Microsoft Azure CLI'. Send an interactive authorization request for this user and resource.
Regarding the above error, I have come across threads which suggest to add Azure CLI as preAuthorizedApplication. However I did not find this managed identity in App RegistrationsI did find an entry in `Enterprise Applications, but did not find how to pre-authorize Azure CLI here.
I tried to achieve the same in a non-user context
az login --service-principal -u <capp-id> -p <client-secret> --tenant <tenant-id>
az account get-access-token --resource "<client-id of user managed identity>"
This works.
Why does the command fail in user context? How can I make it work?
Managed Identities do not have app registrations, only a service principal (aka enterprise app).
The way you are trying to use them is not the way they are meant to be used in my opinion.
The second one working is actually just the feature of Azure AD that allows an application using the client credentials flow (client id + secret) to acquire a token for any app in the tenant.
The token won't have any permissions though, so it wouldn't be valid if you are doing authorization correctly.
You usually don't want to use the managed identities as token targets, only for acquiring tokens.
So if you need to protect an API, you'd need an app registration, where you can then allow Az CLI to call it.
You can also define application permissions and allow applications using client credentials flow to access the API with proper authorization.

Azure client credentials grant oath not working in hybrid setup for Graph Mail API access

In hybrid setup if client credentials grant type is used to get token and if that token is used to get on-prem user messages (https://graph.microsoft.com/v1.0/users('onpremuser#onpremdomain.com')/messages/) using graph api it fails by providing UnknownError.
When debugged on IIS logs error shown was "This token profile 'V1S2SAppOnly' is not applicable for the current protocol." error_category="invalid_token".
However if authorization code grant or resource owner password credential (ROPC) grant if used to obtain token , we were able to get messages of on prem user using graph API.
Have attached screenshot of token for both. How to make client credentials grant work for on-prem user messages access using graph API (in hybrid setup) ?
Update
Update i went and edited web.config of rest in Exchange server to have V1S2SAppOnly in profiles. After that previous error is gone and new error is seen.
Bearer+client_id="00000002-0000-0ff1-ce00-000000000000",+trusted_issuers="00000001-0000-0000-c000-000000000000#ea6064aa-d6fc-48d3-abb8-1728e1f39e0b",+token_types="app_asserted_user_v1+service_asserted_app_v1",+error="invalid_token" 2000008;reason="The+token+should+have+valid+permissions+or+linked+account+associated+with+partner+application+'00000003-0000-0000-c000-000000000000'.";error_category="invalid_grant"
I think the problem is with the aud claim, i.e. the audience for token.
For the first token that you have shared
aud value is 00000002-0000-0000-c000-000000000000. This is the resource Id for Azure AD Graph API and not Microsoft Graph API. For Microsoft Graph API, you should be using https://graph.microsoft.com or Id 00000003-0000-0000-c000-000000000000
this token is probably the one where you used client credentials grant, as there isn't any user claim
For the second token that you have shared
aud value is https://graph.microsoft.com which is correct
this token is acquired in context of a user name anoop so I guess this is the one which is working for you.
What you want is:
Application with Client credentials => Graph API => Local Exchange.
This scenario isn't supported out-of-the-box, but you can however tell your local exchange server to accept those tokens. See this answer https://stackoverflow.com/a/56131954/639153
In a nutshell, you need to change the authentication config of your front-end exchange servers to accept client credentials from the graph api. By default only delegated credentials are supported, and these settings are not documented on the exchange side.
Warning, we tested these settings, and it's working but not supported by Microsoft
This is the blog where I've found the answer to your question. https://blog.thenetw.org/2019/05/13/using-client_credentials-with-microsoft-graph-in-hybrid-exchange-setup/

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

Resources