Files.ReadWrite.Selected microsoft graph api permission - how it works - onedrive

i am trying to understand how Files.ReadWrite.Selected permission provided here in https://graph.microsoft.io/en-us/docs/authorization/permission_scopes works.
can someone explain it in layman term.
i have a web app which uses microsoft v2 endpoint and generates the token, i have given the permission as
Scope = "openid email profile offline_access https://graph.microsoft.com/Files.ReadWrite.Selected",
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = SettingsHelper.ClientId,
Authority = String.Format(CultureInfo.InvariantCulture, SettingsHelper.Authority, "common", "/v2.0"),
Scope = "openid email profile offline_access https://graph.microsoft.com/Files.ReadWrite.Selected",
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false
},
}
i want to know how this scope works, is it like i need to go to one drive and first select particular folder and if my app tries to read that folder, then it works. can i create file in selected folder using the same scope

This scope isn't useful for Microsoft Graph. The scope exists to support the Office 365 File Handlers feature and isn't designed to be used for applications who want API access to files. For those scenarios, you need to use Files.ReadWrite to get access to the user's files.
I'll log a bug to have the description of these permissions updated to be more clear about the indented use case.

Related

Microsoft Graph API: Can MS Graph access mail boxes without individual Id/passwords?

Can MS Graph access mail boxes without individual Id/passwords?
Our organization is considering some mail box automation using MS Graph. However the concern has been expressed that it would expose all mail boxes emails.
Worst case (i.e. clever hacker using scripts only): Is there any way scripting with MS Graph one could access mail boxes without individual Id/passwords? What would be the biggest exposure if they had for one mailbox that has nothing delegated to it?
Thanks!
For Ms graph api, it provides the ability to manage the account/group/mail account/event/calender/... And if we need to use the graph api, we have to create an Azure AD application with the application credential(basically, the client_secret). And the Azure AD app should have enough API permission, for example, we give permission User.ReadWrite.All, then we can use graph api to manage users in this tenant via this Azure AD app. When we add permission Mail.ReadWrite, then we can manage email account.
For api permission, there are 2 kinds of permissions, one for delegate, another for application. When we give delegate api permissin, we need to sign in with your own account(e.g. user1#xx.onmicrosoft.com, and this account had license for mail) first, then we can use ms graph api to list all the mail messages for your account.
But when we give application api permission, we don't need to sign in first, we can directly call graph api, and list all the mail messages for any user account which has mail license in your tenant.
Let's go back to your question, if script can access mail boxes without individual Id/passwords. My answer is yes. But I have to get The Azure AD application & client secret, then this app must have enough api permission, like application permission for Mail.ReadWrite, Mail.Send, and I need to know your email address/account. When I get all these information, I can access the mail boxes. Here's an sample.
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "aad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var messages = await graphClient.Users["{email_address/user_account/user_id}"].Messages
.Request()
.Select("sender,subject")
.GetAsync();

What's the best way of web api authentication to Microsoft Graph to access emails in the service account mailbox?

I am trying to figure out which way would be better for my application. I need to perform an automatic email import triggered from ASP.NET Core Web API using Microsoft Graph mailbox access. According to the documentation, there are two options to go for:
Get access on behalf of the user (https://learn.microsoft.com/en-us/graph/auth-v2-user?view=graph-rest-1.0)
Get access without the user (https://learn.microsoft.com/en-us/graph/auth-v2-service?view=graph-rest-1.0)
As the import is automatically triggered by Azure Function timer I do not want to open a popup for the user credentials. So I considered to go with the second option and create a service user to do this, but then I saw a point about Admin consent in the documentation and I got a bit confused. Does this mean that if nobody is going to accept the app rights to access emails it will not be able to do so? What would be easier/preferred way to implement this kind of functionality?
--Does this mean that if nobody is going to accept the app rights to access emails it will not be able to do so?
no, that means after admin consent the api permission, then you can access any users' emails in your tenant.
--What would be easier/preferred way to implement this kind of functionality?
as you said that you are using Azure timer function to to auto import the mails, so you shouldn't get access to graph api on behalf of a user, you have to access the api on behalf the application.
But you have to check if the graph api you want to call support being accessed on behalf of the application. Let's see this api. You may notice that it supports Application api permission.
Then pls note that you have to using client credential flow to generate access token to call the graph api, you can't use other flows. Here's sample code for using client credential flow with graph SDK to call graph api.
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_appid";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var inboxMessages = await graphClient.Users["user_id"]
.MailFolders["inbox"]
.Messages.Request().GetAsync();

Why do my queries work in Microsoft Graph Explorer but not in my client app (MVC C#)?

I am attempting to learn more about Microsoft Graph and have made extensive use of the Microsoft Graph Explorer site. I am now attempting to transfer a pair of queries from Microsoft Graph Explorer to an MVC C# app but I am receiving the following error message:
"AADSTS65001: The user or administrator has not consented to use the application with ID '' named 'My App'."
The following query works just fine in Microsoft Graph Explorer:
https://graph.microsoft.com/v1.0/servicePrincipals/[resourceID]/appRoleAssignedTo?$select=appRoleId,principalId,principalDisplayName,principalType,resourceId,resourceDisplayName
The following C# equivalent throws the error:
var appRoleAssignedTo = await graphClient.ServicePrincipals[resourceId].AppRoleAssignedTo
.Request()
.Select("appRoleId,principalId,principalDisplayName,principalType,resourceId,resourceDisplayName")
.GetAsync()
.ConfigureAwait(false);
The Microsoft Graph Explorer site indicates the following four permissions must be consented by the app administrator:
"Application.Read.All", "Application.ReadWrite.All", "Directory.Read.All", "Directory.ReadWrite.All".
These permissions have been consented as required.
I am trying to automate these queries so that I can incorporate them into my app. Any assistance is greatly appreciated.
I think you may forget to grant api permission, or setting delegate api permission but using client credential flow to call the api.
when we use Microsoft Graph Explorer to call graph api, it require us to sign in with the microsoft account first, then we can call the api, this means we are using delegate api permission to call the api.
So I want to double confirm with you that if you has a sign in progress before you call the api, if not, then the failure should be the expected behavior. If you don't want to sign in before calling graph api, you need to grant application api permission and using client credential flow like code below to call this api:
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_appid";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
If you has a sign in progress before calling the api, then I suggest you to check if you've grant the api permission, if you want to give application api permission, you also need to click this button.

How can I delete Azure B2C users directly from my app?

I'm building an ASP .Net Core web App. I use Azure ADB2C for user authentication and I would like to have an admin user, which could delete other users. I can delete users from Azure Active Directory via Azure portal, but I would like to do it directly from the app. I have created an admin account in my Active Directory tenant, and gave it global administrator permissions.
I tried to use Graph API, but I can't get it to work. I created an IAuthenticationProved according to instructions on this website:
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS.
Then I created GraphServiceClient and tried to delete user (https://learn.microsoft.com/en-us/graph/api/user-delete?view=graph-rest-1.0&tabs=csharp), but I got error:
System.AggregateException: 'Returning 0 accountsts and 0 broker accountsdata provider for login.microsoftonline.com. Success? True.)'
AuthenticationException: Code: authenticationChallengeRequired
Message: Authentication challange is required.
My code looks like this:
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("<My Client ID>")
.WithRedirectUri("<My Redirect Uri>")
.WithClientSecret("<My Client secret>")
.Build();
List<string> scopes = new List<string>();
scopes.Add("https://graph.microsoft.com/User.ReadWrite.All");
scopes.Add("https://graph.microsoft.com/Directory.ReadWrite.All");
AuthorizationCodeProvider authProvider = new AuthorizationCodeProvider(confidentialClientApplication,scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
graphClient.Users[<UserId>]
.Request()
.DeleteAsync()
.Wait();
Could you tell me what I'm doing wrong? Or maybe there is some other way to do it? Thank you in advance!
Your approach to use Graph API is the way to go. But the problem you are facing there is because your selected auth provider (AuthorizationCodeProvider) is not matching with the scope needed here to delete user. Looking at your code, you want 'Authorization Code' flow which means it would need a delegated scope. As mentioned in permission requirement for delete user, the 'Delegated' scope needed to delete user is Directory.AccessAsUser.All which I don't see in the code snippet you shared.
Additionally, suggest you a quick read to Choose a Microsoft Graph authentication provider based on scenario.
NOTE: To add the required delegated permission, the application registration must be either of the first two types types shown below. The third option won't give you that.
For the above you will be able to add Directory.AccessAsUser.All delegated permission.

Missing Claims from within the IdentityServer Website, including all samples

I am sure this is down to a lack of understanding.
I am trying to access the currently-logged in users claims, within an IdentityServer instance. I am finding that any claims I provide the user are only available to the setup clients, and not the IdentityServer itself.
My issue can be replicated by using any of the quick start samples provided by the IdentityServer4 team (QuickStart Samples)
I am building a site that will provide authentication, using IdentityServer4, and also provide some interface screens to manage your own profile. To facilitate this I will need access to the claims from within the IdentityServer site.
If we look at the test users on the quick starts, we have this user:
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password",
Claims = new List<Claim>
{
new Claim("name", "Alice"),
new Claim("website", "https://alice.com")
}
},
We can see it has 2 claims; name and website.
Within the login controller, I also add another claim, just before signing in (by way of experimenting)
user.Claims.Add(new Claim("given_name", "bob"));
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.SubjectId, user.Username, props);
When the QuickStart site and the MVC Client are running, I can successfully log in. The Secure page then shows me the claims below (after enabling AlwaysIncludeUserClaimsInIdToken)
However, if i visit the Grants section of the IdentityServer4 Quickstart, and inspect the current User I see an entirely different set of claims, shown below:
How, within IdentityServer4 Quickstart, can i access the same list of claims that were returned in the ID Token?
My specific reason is i will be storing an Active Directory UPM as one of the claims and will need access to this when the user is within any secure page in our Identity Server.
Ok - after a day of playing around, I realized there were other overrides for the HttpContext.SignInAsync() method.
Before, I had this - as per tutorial
await HttpContext.SignInAsync(user.SubjectId, user.Username, props);
Changing this to
await HttpContext.SignInAsync(user.SubjectId, user.Username, props, user.Claims.ToArray());
Gives me exactly what i was looking for.
Leaving this here on the off chance others have the same issue.