I am trying to retrieve a list of users from an azure security group, however i am having trouble with this, as i do not know the best possible and easy way to do this in c#. Any help/direction and sample code would be grateful.
To retrieve list of users from an azure security group, make sure to grant the below API permission:
Please try using the below script by Jason Pan in this SO Thread like below:
public async Task<JsonResult> sample()
{
var clientId = Your_Client_ID;
var clientSecret = Your_Client_Secret;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = Your_Tenant_ID;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
try
{
var members = await graphClient.Groups["Your_Group_ID"].Members.Request().GetAsync();
return Json(members);
}
catch (Exception e)
{
return Json("");
throw;
}
}
You can use Microsoft Graph restful web APIs to access microsoft cloud resources .
It has api endpoints for groups , users etc.
In your case you can use list groups endpoint to fetch the groups.
https://learn.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0
Related
I am just starting in with Azure and my first attempt is using the Graph client API for a simple data display. In simple terms, I want to get the Teams status of an employee and display it on a form in some graphical way.
I am trying to be as basic as can be so when I tried to download the sample I did not want the UWP project, just basic winform (console would work at the moment). I did borrow from the project and got something to compile but I get the error:
MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.
This is the full code and I am obviously missing something...what? This is an App that should be able to access the Graph API for a get user read and a getPresence call to show current status with the nee to have a use log in. I can see that Graph Explorer has a token and looking at postman set up there is some way to do this without a interaction, but none of the documentation is clear. I'll continue to pok at this and maybe see if I can get postman to work which might help, but behind the scene's access is not clear to me.
public partial class Form1 : Form
{
//Set the scope for API call to user.read
private string[] scopes = new string[] { "user.read" };
private const string ClientId = "my client id";
private const string Tenant = "my tenant id";
private const string Authority = "https://login.microsoftonline.com/" + Tenant;
// The MSAL Public client app
private static IPublicClientApplication PublicClientApp;
private static string MSGraphURL = "https://graph.microsoft.com/v1.0/";
private static AuthenticationResult authResult;
public Form1()
{
InitializeComponent();
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId).WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient").Build();
callMe();
}
private async void callMe()
{
// Sign-in user using MSAL and obtain an access token for MS Graph
GraphServiceClient graphClient = await SignInAndInitializeGraphServiceClient(scopes);
// Call the /me endpoint of Graph
User graphUser = await graphClient.Me.Request().GetAsync();
Console.WriteLine(graphUser.Id);
var graphu2 = await graphClient.Users["my email address"].Request().GetAsync();
}
private async Task<GraphServiceClient> SignInAndInitializeGraphServiceClient(string[] scopes)
{
GraphServiceClient graphClient = new GraphServiceClient(MSGraphURL,
new DelegateAuthenticationProvider(async (requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await getToken(scopes));
}));
return await Task.FromResult(graphClient);
}
public async Task<string> getToken(string[] scopes)
{
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(Authority)
.WithLogging((level, message, containsPii) =>
{
Console.WriteLine($"MSAL: {level} {message} ");
}, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
.Build();
IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
IAccount firstAccount = accounts.FirstOrDefault();
try
{
authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
Console.WriteLine($"MsalUiRequiredException: {ex.Message}");
authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
.ExecuteAsync()
.ConfigureAwait(true);
}
return authResult.AccessToken;
}
Apologies but I'm going to ignore your code and break it back to something that's a lot more simple.
using Azure.Identity;
using Microsoft.Graph;
namespace StackoverflowAnswer
{
internal class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
var tenantId = "YOUR_TENANT_ID";
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
try
{
string[] scopes = { "https://graph.microsoft.com/.default" };
ClientSecretCredential clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
GraphServiceClient graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var users = await graphClient.Users.Request().GetAsync();
foreach (var user in users)
Console.WriteLine(user.UserPrincipalName);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
A lot of the above code was taken from the following documentation as once you've authenticated, the rest of the SDK is much the same. It can be tricky in points though depending on the specific nature of what you want to do ...
https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/docs/tokencredentials.md
This also helps ...
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
Also make sure that you've assigned the desired API permissions to the app in the Azure Portal ...
... and also make sure you've set a client secret for your app. If you have a client ID then you've clearly already gotten that far ...
https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
Update
Now, in relation to working with the Presence API, this is a little more tricky.
Although it appears to, the Presence API doesn't support application permissions. There is an application permission for it but put simply, it doesn't work. This user voice link provides insight on that.
https://techcommunity.microsoft.com/t5/microsoft-365-developer-platform/graph-api-presence-should-support-application-permissions/idi-p/2276109
So what you need to do is apply the delegated permissions to your registered application.
Because of that, you need to use a UsernamePasswordCredential rather than a ClientSecretCredential in your code and replace it when instantiating the GraphServiceClient.
UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredential("<USERNAME>", "<PASSWORD>", tenantId, clientId);
Further to that, you'll need to make sure that the user in question has granted access to use that permission. If it was a user facing app, then they'd log in and be presented with the question to approve the permissions that you have set but because it's not, you need to go to the Enterprise Applications section in Azure AD, find your app, go to Permissions and press the Grant admin consent button for your tenant.
Someone may have a better approach than the above but it's the only way I could find to do it. It will mean if someone knows the client ID and how to authenticate, they can then execute the same API's as you.
Anyway, that will then allow you to get the presence of all users in your organisation.
I need to query get a single user details through Microsoft graph by email id, can anyone help me I couldn't find it in MS docs.
var users = graphServiceClient.Users.Request().GetAsync().GetAwaiter().GetResult();
this brings only 100 users
I need to get user by email so I can get specific user
Pls try this code.
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "hanxia.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var temp = await graphClient.Users.Request().Filter("mail eq 'tiny#outlook.com'").GetAsync();
When we want to do a filter in Ms graph api, we may firstly check if the target property support filter, for ms user api, mail is supported.
I am trying to upload file on onedrive by using microsoft graph onedrive api.
I am using the method for authentication
Client credentials provider
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
Like:
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "my-tenantid";
// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
HttpPostedFileBase file = Request.Files;[0];
int fileSize = file.ContentLength;
string fileName = file.FileName;
string mimeType = file.ContentType;
Stream fileContent = file.InputStream;
var res = await graphClient.Me.Drive.Root.ItemWithPath(fileName).Content
.Request()
.PutAsync<DriveItem>(fileContent);
After executing this code then it gives an error in response.
Message: /me request is only valid with delegated authentication flow.
Inner error:
AdditionalData:
date: 2021-12-29T05:30:08
request-id: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
client-request-id: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
ClientRequestId: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
Client credential flow will generate the token on behalf the app itself, so in this scenario, users don't need to sign in first to generate the token stand for the user and then call the api. And because of the design,when you used Me in the graph SDK, your code/app don't know who is Me so it can't work. You should know the user_id first and use /users/{id | userPrincipalName} instead of /Me, in the SDK, that is graphClient.Users["your_user_id"] instead of graphClient.Me
In your scenario, there're 2 solutions, one way is using delegated authentication flow like what you said in your title, another way is get the user id before calling the graph api so that you can use Users["id"] but not Me
===================== Update=========================
I haven't finished the code yet but I found the correct solution now.
Firstly, we can upload file to one drive by this api, you may check the screenshot if this is one drive or sharepoint:
https://graph.microsoft.com/v1.0/users/user_id/drive/items/root:/testupload2.txt:/content
If it is, then the next is easy, using the code below to get an access token and send http request to calling the api:
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "your_azuread_clientid";
var clientSecret = "corresponding_client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var tokenRequestContext = new TokenRequestContext(scopes);
var token = clientSecretCredential.GetTokenAsync(tokenRequestContext).Result.Token;
I know it's complex because the api is not the same as this one which has SDK sample, but I think it also deserves to try if they are similar.
I am not an expert on all things Azure, but I'd like to read my own calendar programmatically. I found some code to access Microsoft Graph and read my calendar, but it seems I have to create an App Registration first, is it possible to SKIP the app registration if I only need to read my OWN calendar? here's my starting point:
var scopes = new[] { "User.Read" };
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var userName = "myaccount#company.com";
var password = "pwdhere";
var userNamePasswordCredential = new UsernamePasswordCredential(
userName, password, tenantId, clientId, options);
var graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);
var events = await graphClient.Me.Calendar.Events
.Request()
.Filter("startsWith(subject,'All')")
.GetAsync();
You need an app registration, otherwise you couldn't even log in. If it's an Azure AD you don't control, such as your employer, you'll need to get an admin to create that for you.
I'm trying to create Windows Service that will allow me to send emails on behalf of specific users.
Lates version of Graph Client allows specifying retries using WithMaxRetry.
Unfortunately, there aren't any good examples showing "best practices" when creating ConfidentialClientApplication.
Currently, I use the below code to send email without asking for login and password:
const string clientId = "foo...99a0";
const string clientSecret = "#6A...cx#$a";
const string tenant = "1c...7";
const string azureAdInstance = "https://login.microsoftonline.com/{0}";
var authority = string.Format(CultureInfo.InvariantCulture, azureAdInstance, tenant);
string[] scopes = { "https://graph.microsoft.com/.default" };
var clientCredentials = new ClientCredential(clientSecret);
var confidentialClientApplication =
new ConfidentialClientApplication(
clientId,
authority,
"https://daemon",
clientCredentials,
null,
new TokenCache());
var graphClient =
new GraphServiceClient("https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(
async(requestMessage) =>
{
var result = await confidentialClientApplication
.AcquireTokenForClientAsync(scopes);
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("bearer", result.AccessToken);
}));
var recipients = new List<Recipient>
{
new Recipient
{
EmailAddress = new Microsoft.Graph.EmailAddress
{
Address = "test#example.com"
}
}
};
var email = new Message
{
Body = new ItemBody
{
Content = "Works fine!",
ContentType = BodyType.Html,
},
Subject = "Test",
ToRecipients = recipients
};
await graphClient
.Users["sender#example.onmicrosoft.com"]
.SendMail(email, true)
.Request()
.PostAsync();
but I can't figure out how to create ConfidentialClientApplication based on recent changes from Request Context With Middleware Options.
Because I wasn't able to find up to date example my question is, how should I create GraphServiceClient to be able to send emails from Windows Service?
This is code from above PR:
HttpProvider httpProvider = new HttpProvider();
var graphClient = new GraphServiceClient(appOnlyProvider, httpProvider);
graphClient.PerRequestAuthProvider = () => CreateDelegatedProvider();
var me = await graphClient.Me.Request()
.WithScopes(string[] { "User.Read" }) // adds auth scopes
.WithMaxRetry(5) // specifies maximum number of retries
.WithPerRequestAuthProvider()
.GetAsync();
How should I adopt it per my requirement?
I'm new to Graph so I want to avoid bad code.
One of the pieces of the puzzle that I believe you are missing is the new Authentication Providers library that is here https://www.nuget.org/packages/Microsoft.Graph.Auth/0.1.0-preview and there are some examples of how to use these Authentication providers here https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth
This library provides a set of authorization providers based on the desired OAuth2 flow. In your case you should use the ClientCredentialsProvider instead of the DelegateProvider.
You don't need to use a PerRequestAuthProvider. That is only needed for scenarios where you want to switch between different flows or different appIds in each call.