Delete Unique permissions for One-Drive Item through Microsoft Graph - microsoft-graph-api

Is there a way perform Delete Unique Permissions from Microsoft Graph API. As we can do this from the UI.

You can delete only not inerited permissions.
var permissions = await _client
.Drives[{ driveId }]
.Items[{ itemId }]
.Permissions
.Request()
.GetAsync();
foreach (var p in permissions)
{
if (p.InheritedFrom == null)
{
await _client
.Drives[{ driveId }]
.Items[{ itemId }]
.Permissions[p.Id]
.Request()
.DeleteAsync();
}
}

Related

How to create a online MeetingParticipantInfo using Graph API

I would like to create an online Meeting event with participant where I suppose to pass the MeetingParticipants, how to get the IdentitySet from Graph User?
List<MeetingParticipantInfo> participantInfos = new List<MeetingParticipantInfo>()
{
new MeetingParticipantInfo()
{
Identity = new IdentitySet(){
User = graphUser ??????,
}
}
};
MeetingParticipants participants = new MeetingParticipants()
{
Attendees = participantInfos,
};
Any help is greatly appreciated.
Thanks
Charles
You can simply get the user details(Id, UPN etc.,) whom you want to include in the online Meeting by specifying the user's UPN(ABC#domain.com) as shown in the below code.
public static async Task<OnlineMeeting> CreateOnlineMeeting()
{
var User = await graphClient.Users["ABC#domain.com"] // UPN or ID would work
.Request()
.GetAsync();
var startDateTime = DateTimeOffset.Parse("2020-02-06T01:49:21.3524945+00:00");
var endDateTime = DateTimeOffset.Parse("2020-02-06T02:19:21.3524945+00:00");
var subject = "Create a meeting with customId provided";
var externalId = "7eb8263f-d0e0-4149-bb1c-1f0476083c56";
var participants = new MeetingParticipants
{
Attendees = new List<MeetingParticipantInfo>()
{
new MeetingParticipantInfo
{
Identity = new IdentitySet
{
User = new Identity
{
Id = User.Id
}
},
Upn = User.UserPrincipalName
}
}
};
return await graphClient.Me.OnlineMeetings
.CreateOrGet(externalId, null, endDateTime, participants, startDateTime, subject)
.Request()
.PostAsync();
}

Receiving multiple webhook notifications for outlook calendar event

I am using node.js and the Microsoft Graph npm package (#microsoft/microsoft-graph-client)for calling webhook in office 365 for calendar events. I am receiving multiple webhook notifications for every Office 365 calendar event update, delete and create.
My source code is
router.post("/webhook", (req, res) => {
if (req.query.validationToken) {
res.status(200);
res.send(req.query.validationToken)
} else {
res.status(202);
console.log(req.body.value[0].changeType);
console.log(req.body.value[0].resource);
}
});
//CREAE A WEBHOOK
router.get("/createWebhook", async (req, res) => {
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
const subscription = {
changeType: "deleted,updated,created",
notificationUrl: "https://abccb3e5.ngrok.io/calendar/webhook",
resource: "me/events",
expirationDateTime: "2020-01-26T18:23:45.9356913Z",
clientState: "My calendar sync"
};
try {
client.api('/subscriptions')
.post(subscription, (errr,result) => {
if (result)
console.log(result);
//process subscription
});
} catch (err) {
console.log(err)
}
res.redirect('/calendar');
});
When I create an event, Graph notifies multiple times in post webhook endpoint and then continues for deletes and updates also.
This is by design, the Microsoft Graph Webhooks service can send you duplicate notifications for the same events.
Your code needs to handle this scenario, some notifications carry a unique id to help you keep tracks of the deliveries

Setting custom properties on an 365 group with GraphClient

I want to set CustomProperty5 on a 265 group. I have following code:
var extensions = await graphClient.Groups["xxx"].Extensions.Request().GetAsync();
var dictionary = new Dictionary<string, object>();
dictionary.Add("CustomAttribute5", "Works!");
await graphClient
.Groups["xxx"]
.Request()
.UpdateAsync(new Microsoft.Graph.Group()
{
AdditionalData = dictionary
});
However I get following error:
Microsoft.Graph.ServiceException: 'Code: Request_BadRequest Message:
One or more property values specified are invalid.
Any pointers how to set custom properties on a 365 group?
For existing group open extension could be updated like this via msgraph-sdk-dotnet:
//retrieve an existing group custom property
var ext = await graphClient.Groups[groupId].Extensions[extName].Request().GetAsync();
//update
ext.AdditionalData = new Dictionary<string, object>()
{
{
"status", "Closed"
}
};
await graphClient.Groups[groupId].Extensions[extName]
.Request()
.UpdateAsync(ext);
When it comes to complex type extension, it could be updated via group update endpoint. Lets assume the following type extension is registered:
{
"id":"contoso_grpstatus",
"description": "",
"targetTypes": [
"Group"
],
"properties": [
{
"name": "Status",
"type": "String"
}
]
}
Then an existing group instance with the contoso_grpstatus complex type extension defined could be updated like this:
var group = new Group
{
AdditionalData = new Dictionary<string, object>()
{
{
"contoso_grpstatus", new Dictionary<string, object>()
{
{"Status", "Closed"}
}
}
}
};
await graphClient.Groups[groupId]
.Request()
.UpdateAsync(group);

Adding invited (guest) user to teams seems to not work properly

Hi (ref issue)
After setting up the tenant to allow invitation of user from another domain, we are able to invite external users (in set domain) to teams. This works fine when doing it manually, in the GUI.
However, when trying to add an invited user threw the windows graph API, something is not working properly.
Our procedure to invite a user to a team is as follows:
Note we are using application privileges
Invite the user to the tenant (with or without welcome mail)
https://learn.microsoft.com/en-us/graph/api/invitation-post?view=graph-rest-1.0
Add the invited user to the team
https://learn.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0
Both these calls complete successfully and does not return any error messages. In all the admin GUI’s (AAD, Teams, Exchange) the user is invited and is added to the group.
But the user in question does not receive a welcome mail that he/she has been added to the team. And if the user (given we send a welcome mail in step 1) tries to access http://teams.microsoft.com the user gets notified that he/she does not have permissions and/or does not see the team.
Any tips?
API Permissions
EDIT:
After some investigation, by monitoring the network traffic. It's seems that the missing call, to get properly invited to the team is:
POST https://api.teams.skype.com/emea/beta/teams/($teamurl)/bulkUpdateRoledMembers?allowBotsInChannel=true
where you send in a list of userid (8:orgid:{userid}) and the groupid. (teamurl seems to be the channel id)
{"users":[{"mri":"8:orgid:00000000-5946-0000-87d2-b16b6fdf7a72","role":2}],"groupId":"00000000-2e8b-4d18-0000-394c6a4846d0"}
I have tried to call this from application & delegation, but get 'Unauthorized'. Also I could not find any API permission that granted access to 'api.teams.skype.com'.
I finally figured out how to get an access token to invoke bulkUpdateRoledMembers. It only works if I request an access token for it directly, so no Application Permissions and no On-Behalf-Of Flow.
private static async Task<string> GetAccessTokenForTeams(string tenantId)
{
var client = new PublicClientApplication(
clientId: "d3590ed6-52b3-4102-aeff-aad2292ab01c",
authority: $"https://login.microsoftonline.com/{tenantId}/",
userTokenCache: null);
try
{
var result = await client.AcquireTokenInteractive(new[] { "https://api.spaces.skype.com/user_impersonation" }, null).ExecuteAsync();
return result.AccessToken;
}
catch (Exception e)
{
Debug.WriteLine(e);
throw;
}
}
It turns out you also need a Skypetoken, which you can get very easily with the just acquired access token.
private static async Task<string> GetSkypeToken(string accessToken)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add(HttpRequestHeader.Authorization.ToString(), "Bearer " + accessToken);
using (var response = await client.PostAsync("https://api.teams.skype.com/beta/auth/skypetoken", null))
{
var contentString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var skypeTokenResponse = JsonConvert.DeserializeObject<SkypeTokenResponse>(contentString);
return skypeTokenResponse.Tokens.SkypeToken;
}
else
{
throw new Exception(response.StatusCode.ToString() + ": " + contentString);
}
}
}
}
private class SkypeTokenResponse
{
public Token Tokens { get; set; }
public class Token
{
public string SkypeToken { get; set; }
public string ExpiresIn { get; set; }
}
}
Then you can finally invoke bulkUpdateRoledMembers by passing both tokens along.
private static async Task<object> bulkUpdateRoledMembers(string accessToken, string skypeToken, string teamUrl, string groupId, string userId)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add(HttpRequestHeader.Authorization.ToString(), "Bearer " + accessToken);
client.DefaultRequestHeaders.Add("X-Skypetoken", skypeToken);
var bodyString = JsonConvert.SerializeObject(new
{
users = new List<object>
{
new
{
mri = "8:orgid:" + userId,
role = 2
}
},
groupId = groupId
});
var body = new StringContent(bodyString, Encoding.UTF8, "application/json");
using (var response = await client.PutAsync($"https://teams.microsoft.com/api/mt/emea/beta/teams/{teamUrl}/bulkUpdateRoledMembers?allowBotsInChannel=true", body))
{
var contentString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var jsonresult = JObject.Parse(contentString);
return jsonresult;
}
else
{
throw new Exception(response.StatusCode.ToString() + ": " + contentString);
}
}
}
}

Azure ActiveDirectory Graph API GraphClient not returning AD Groups

I want to retrieve a User's Group information from Azure AD.
Using the following Graph API packages to achieve this
Microsoft.Azure.ActiveDirectory.GraphClient
Microsoft.IdentityModel.Clients.ActiveDirectory 2.13.112191810
I am able to successfully retrieve Users information from the Azure Graph API.
But when I run this method to retrieve a User's groups, Fiddler shows a successful HTTP 200 response with JSON fragment containing group information however the method itself does not return with the IEnumerable.
IEnumerable<string> groups = user.GetMemberGroupsAsync(false).Result.ToList();
The code doesn't seem to return from this async request.
The resulting experience is blank page while the authentication pipeline gets stuck.
Full code
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated == true &&
_authorizationService.IdentityRegistered(incomingPrincipal.Identity.Name))
{
return base.Authenticate(resourceName, incomingPrincipal);
}
_authorizationService.AddClaimsToIdentity(((ClaimsIdentity) incomingPrincipal.Identity));
Claim tenantClaim = incomingPrincipal.FindFirst(TenantIdClaim);
if (tenantClaim == null)
{
throw new NotSupportedException("Tenant claim not available, role authentication is not supported");
}
string tenantId = tenantClaim.Value;
string authority = String.Format(CultureInfo.InvariantCulture, _aadInstance, _tenant);
Uri servicePointUri = new Uri("https://graph.windows.net");
ClientCredential clientCredential = new ClientCredential(_clientId, _password);
AuthenticationContext authContext = new AuthenticationContext(authority, true);
AuthenticationResult result = authContext.AcquireToken(servicePointUri.ToString(), clientCredential);
Token = result.AccessToken;
ActiveDirectoryClient activeDirectoryClient =
new ActiveDirectoryClient(new Uri(servicePointUri, tenantId),
async () => await AcquireTokenAsync());
IUser user = activeDirectoryClient
.Users
.Where(x => x.UserPrincipalName.Equals(incomingPrincipal.Identity.Name))
.ExecuteAsync()
.Result
.CurrentPage
.ToList()
.FirstOrDefault();
if (user == null)
{
throw new NotSupportedException("Unknown User.");
}
IEnumerable<string> groups = user.GetMemberGroupsAsync(false).Result.ToList();
return incomingPrincipal;
}
I have the same problem. My code is working after changing it according to documentation
https://github.com/AzureADSamples/ConsoleApp-GraphAPI-DotNet
IUserFetcher retrievedUserFetcher = (User) user;
IPagedCollection<IDirectoryObject> pagedCollection = retrievedUserFetcher.MemberOf.ExecuteAsync().Result;
do {
List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
foreach (IDirectoryObject directoryObject in directoryObjects) {
if (directoryObject is Group) {
Group group = directoryObject as Group;
((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(
new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String, "GRAPH"));
}
}
pagedCollection = pagedCollection.GetNextPageAsync().Result;
} while (pagedCollection != null && pagedCollection.MorePagesAvailable);
IEnumerable, string groups = user.GetMemberGroupsAsync(false).Result.ToList() doesn't work since the result is not of type IEnumerable, string.
IEnumerable<string> groups = await user.GetMemberGroupsAsync(false);
Above code would return the correct type.

Resources