public async Task <HashSet <string> > DirectoryRoles() { try { var directoryRoles = await GraphServiceHelper.GetDirectoryRolesAsync(_graphClient, _httpContext); var userIds = await GraphServiceHelper.GetUsersAsync(_graphClient, _httpContext); var administrators = new HashSet <string>(); var directoryRolesNames = new HashSet <string>(); await directoryRoles.ForEachAsync(async _ => { var roleMembers = await GraphServiceHelper.GetDirectoryRoleMembers(_graphClient, _httpContext, _.Id); var members = Extensions.DirectoryRoleMembersResultsToList(roleMembers); BloodHoundHelper.DirectoryRoleMembership(_, members); if (Startup.IsCosmosDbGraphEnabled) { CosmosDbGraphHelper.DirectoryRoleMembership(_, members); GetDeviceAdministratorsIds(_.DisplayName, members, administrators); CosmosDbGraphHelper.DirectoryRolePermissions(_, userIds, administrators); } directoryRolesNames.Add(_.DisplayName); }); return(directoryRolesNames); } catch (Exception ex) { _logger.Error(ex, $"{nameof(DirectoryRoles)} {ex.Message} {ex.InnerException}"); return(null); } }
public async Task <int> Applications() { try { var applications = await GraphServiceHelper.GetApplications(_graphClient); applications.ForEach(async _ => { try { var owners = await GraphServiceHelper.GetApplicationsOwner(_graphClient, _.Id); CosmosDbGraphHelper.AppOwnership(_, owners); } catch (Exception e) { Console.WriteLine(e); } } ); return(applications.Count); } catch (Exception e) { Console.WriteLine(e); throw; } return(0); }
public async Task <HashSet <string> > Groups() { try { var groupsCollectionPage = await GraphServiceHelper.GetGroupsAsync(_graphClient, _httpContext); var groups = new HashSet <string>(); await groupsCollectionPage.ForEachAsync(async _ => { var groupOwner = await GraphServiceHelper.GetGroupOwnersAsync(_graphClient, _httpContext, _.Id); var groupOwnership = BloodHoundHelper.BuildGroupOwnership(groupOwner); var groupMembersList = await GraphServiceHelper.GetGroupMembers(_graphClient, _httpContext, _.Id); var groupMembers = BloodHoundHelper.BuildGroupMembersList(groupMembersList); BloodHoundHelper.GroupMembership(_, groupMembers); if (Startup.IsCosmosDbGraphEnabled) { CosmosDbGraphHelper.GroupMembership(_, groupMembers); CosmosDbGraphHelper.GroupMembership(_, groupOwnership); } groups.Add(_.DisplayName); }); return(groups); } catch (Exception ex) { _logger.Error(ex, $"{nameof(Groups)} {ex.Message} {ex.InnerException}"); return(null); } }
public async Task <int> Users() { try { return((await GraphServiceHelper.GetUsersAsync(_graphClient, _httpContext)).Count); } catch (Exception ex) { _logger.Error(ex, $"{nameof(Users)} {ex.Message} {ex.InnerException}"); return(-1); } }
/// <summary> /// Updates the content of the synchronized OneNote page to reflect the given list of ToDo /// objects. /// </summary> /// <param name="todos">The list of todos to synchronize with OneNote.</param> /// <returns></returns> public async Task UpdateToDoList(List <ToDo> todos) { // First get the page that we are syncing with from OneNote. var client = GraphServiceHelper.GetAuthenticatedClient(); var pages = await OneNoteService.GetMyPages(client); var todoPage = pages.Where(page => page.Title == todoPageTitle).SingleOrDefault(); if (todoPage == null) { throw new Exception("Cannot update todo list. Failed to get OneNote page to update."); } // Load the HTML content of the page with OneNote IDs. Stream contentStream = await OneNoteService.GetPageContent(client, todoPage, includeIds : true); var pageContent = new HtmlDocument(); using (StreamReader reader = new StreamReader(contentStream)) { string stringContent = reader.ReadToEnd(); pageContent.LoadHtml(stringContent); } // The container of our todos will be the first <div> tag on the page. var targetDiv = pageContent.DocumentNode.Descendants("div").FirstOrDefault(); if (targetDiv == null) { throw new Exception("Cannot update todo list. Text content on a OneNote page must be contained within a div tag."); } // The div's ID will be used to identify the target on the page that we want to update. var targetDivId = targetDiv.ChildAttributes("id").FirstOrDefault(); if (targetDivId == null) { throw new Exception("Cannot update todo list. Target div tag does not have an id."); } // Regenerate HTML content for current todos. targetDiv.RemoveAllChildren(); foreach (ToDo todo in todos) { string dataTag = todo.Done ? "to-do:completed" : "to-do"; targetDiv.AppendChild(HtmlNode.CreateNode($"<p data-tag=\"{dataTag}\">{todo.Task}</p>")); } // Update the OneNote page. await OneNoteService.UpdatePage(client, todoPage, targetDivId.Value, targetDiv.InnerHtml); }
public async Task <List <InteractiveLogon> > InteractiveLogins() { try { var signIns = await GraphServiceHelper.GetSignIns(_graphClient, _httpContext); var interactiveLogOns = new List <InteractiveLogon>(); signIns .Where(_ => _.ClientAppUsed?.Equals("Mobile Apps and Desktop clients", StringComparison.OrdinalIgnoreCase) == true) .Where(_ => _.ResourceDisplayName?.Equals("Windows Azure Active Directory", StringComparison.OrdinalIgnoreCase) == true) .Where(_ => _.CreatedDateTime.HasValue && _.CreatedDateTime.Value.UtcDateTime.IsNotOlderThan(10.Days())) .ForEach(_ => { interactiveLogOns.Add( new InteractiveLogon( _.DeviceDetail, _.Location, _.UserId, _.CreatedDateTime.GetValueOrDefault().UtcDateTime, _.UserDisplayName)); }); interactiveLogOns.DistinctBy(_ => new { _.UserId, _.DeviceId }); interactiveLogOns. Where(_ => _.UserId != null && _.UserDisplayName != null && _.DeviceDisplayName != null). ForEach(_ => { BloodHoundHelper.InteractiveLogOns(_); if (Startup.IsCosmosDbGraphEnabled) { CosmosDbGraphHelper.InteractiveLogOns(_, _deviceObjectIdToDeviceId); } }); return(interactiveLogOns); } catch (Exception ex) { _logger.Error(ex, $"{nameof(InteractiveLogins)} {ex.Message} {ex.InnerException}"); return(null); } }
/// <summary> /// Reads the synchronized page in OneNote and translates the content into a list of todo objects. /// </summary> /// <returns>The list of todos synchronized with OneNote.</returns> public async Task <List <ToDo> > GetToDoList() { // First get the synchronized page. If it doesn't exist, create it. var client = GraphServiceHelper.GetAuthenticatedClient(); var pages = await OneNoteService.GetMyPages(client); var todoPage = pages.Where(page => page.Title == todoPageTitle).SingleOrDefault(); if (todoPage == null) { todoPage = await CreateToDoPage(client); } // Read the HTML content of the synchronized page and translate that into ToDo objects. List <ToDo> result = new List <ToDo>(); Stream contentStream = await OneNoteService.GetPageContent(client, todoPage); using (StreamReader reader = new StreamReader(contentStream)) { string pageContent = reader.ReadToEnd(); var document = new HtmlDocument(); document.LoadHtml(pageContent); // A OneNote todo list is a sequence of <p> tags with the data-tag attribute set // to "to-do" or "to-do:completed". foreach (var node in document.DocumentNode.Descendants("p").Where( p => p.GetAttributeValue("data-tag", "not-to-do") != "not-to-do")) { string dataTag = node.Attributes["data-tag"].Value; if (dataTag != "to-do" && dataTag != "to-do:completed") { continue; // node is not a OneNote todo } result.Add(new ToDo { Task = node.InnerText, Done = dataTag == "to-do:completed" }); } } return(result); }
public async Task <HashSet <string> > Domains() { try { var domainResults = await GraphServiceHelper.GetDomains(_graphClient, _httpContext); var domains = new HashSet <string>(); domainResults.ForEach(_ => { domains.Add(_.Id); BloodHoundHelper.Domains(_); }); return(domains); } catch (Exception ex) { _logger.Error(ex, $"{nameof(Domains)} {ex.Message} {ex.InnerException}"); return(null); } }
public async Task <HashSet <DirectoryObject> > DeviceOwners() { try { var directoryRoles = await GraphServiceHelper.GetDirectoryRolesAsync(_graphClient, _httpContext); var devices = await GraphServiceHelper.GetDevicesAsync(_graphClient, _httpContext); HashSet <DirectoryObject> ownersList = new HashSet <DirectoryObject>(); await devices. Where(_ => _.DisplayName != null). ForEachAsync(async _ => { _deviceObjectIdToDeviceId.Add(_.DeviceId, _.Id); var ownerList = (await GraphServiceHelper.GetDeviceOwners(_graphClient, _httpContext, _.Id)) .Where(__ => __ != null) .ToList(); BloodHoundHelper.DeviceOwners(_, ownerList); if (Startup.IsCosmosDbGraphEnabled) { CosmosDbGraphHelper.DeviceOwners(_, ownerList, directoryRoles); } ownersList.UnionWith(ownerList); }); return(ownersList); } catch (Exception ex) { _logger.Error(ex, $"{nameof(DeviceOwners)} {ex.Message} {ex.InnerException}"); return(null); } }
public GraphService() { _authProvider = new AuthenticationProvider(appId, scopes); _graphServiceHelper = new GraphServiceHelper(_authProvider); }
public async Task <int> ServicePrincipals() { try { var appsPermissions = await GraphServiceHelper.GetAppsPermission(_graphClient, _httpContext); var principalsPermissions = await GraphServiceHelper.GetDirectoryAudits(_graphClient, _httpContext); var servicePrincipals = await GraphServiceHelper.GetServicePrincipals(_graphClient, _httpContext); var principalIdToPermissions = new Dictionary <string, HashSet <string> >(); principalsPermissions.ForEach(_ => { principalIdToPermissions.TryAdd( _.TargetResources.First().Id, ToHashSetExtension.ToHashSet(_.TargetResources.First().ModifiedProperties.First(__ => __.DisplayName == "ConsentAction.Permissions").NewValue.Split("Scope:").Last(). Split("]").First().Split(" ").Where(__ => __ != "")) ); }); var appIdToPermissionsSetDictionary = new Dictionary <string, HashSet <string> >(); appsPermissions.ForEach(_ => { var permissionsSet = ToHashSetExtension.ToHashSet(Newtonsoft.Json.Linq.Extensions.Value <string>(_["scope"]) .Split(' ')); var appId = Newtonsoft.Json.Linq.Extensions.Value <string>(_["clientId"]); appIdToPermissionsSetDictionary.TryAdd(appId, permissionsSet); }); var appIdToNameDictionary = new Dictionary <string, Tuple <string, string, string, string> >(); servicePrincipals.ForEach(_ => appIdToNameDictionary.Add( Newtonsoft.Json.Linq.Extensions.Value <string>(_["id"]), new Tuple <string, string, string, string>( Newtonsoft.Json.Linq.Extensions.Value <string>(_["appId"]), Newtonsoft.Json.Linq.Extensions.Value <string>(_["displayName"]), Newtonsoft.Json.Linq.Extensions.Value <string>(_["homepage"]), Newtonsoft.Json.Linq.Extensions.Value <string>(_["appOwnerOrganizationId"]) ))); appIdToNameDictionary.ForEach(_ => { appIdToPermissionsSetDictionary.TryGetValue(_.Key, out var appPermissions); principalIdToPermissions.TryGetValue(_.Key, out var principalPermissions); if (Startup.IsCosmosDbGraphEnabled && (principalPermissions != null || appPermissions != null)) { if (principalPermissions != null) { CosmosDbGraphHelper.Applications(_.Value.Item2, _.Value.Item1, principalPermissions, UserIds, _.Key, _.Value.Item3, _.Value.Item4); } else { CosmosDbGraphHelper.Applications(_.Value.Item2, _.Key, appPermissions, UserIds, _.Value.Item1, _.Value.Item3, _.Value.Item4); } } }); return(appIdToNameDictionary.Count); } catch (Exception ex) { _logger.Error(ex, $"{nameof(ServicePrincipals)} {ex.Message} {ex.InnerException}"); } return(0); }
/// <summary> /// Initiate restoration of data from OneDrive. /// <para>*Application restarts if finished successfully.</para> /// </summary> private async void RestoreFromOneDrive() { progressRing.IsActive = true; try { // Request a token to sign in the user var accessToken = await authProvider.GetAccessToken(); // Initialize Graph Client GraphServiceHelper.InitializeClient(authProvider); // Set current user (temp) App.CurrentUser = await GraphServiceHelper.GetMeAsync(); // Find the backupFolder in OneDrive, if it exists var backupFolder = await GraphServiceHelper.GetOneDriveFolderAsync("Kanban Tasker"); if (backupFolder != null) { // Restore local data file using the backup file, if it exists await GraphServiceHelper.RestoreFileFromOneDriveAsync(backupFolder.Id, "ktdatabase.db"); await DisplayMessageAsync("Data restored successfully."); var displayName = await GraphServiceHelper.GetMyDisplayNameAsync(); await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { txtResults.Text = "Welcome " + App.CurrentUser.GivenName; btnSignOutTip.IsEnabled = true; }); Thread.Sleep(2000); // Restart app to make changes await Windows.ApplicationModel.Core.CoreApplication.RequestRestartAsync(""); } else { await DisplayMessageAsync("No backup folder found to restore from."); } } catch (ServiceException ex) { if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) { // MS Graph Known Error // Users need to sign into OneDrive at least once // https://docs.microsoft.com/en-us/graph/known-issues#files-onedrive // Empty all cached accounts / data to allow user to rety await authProvider.SignOut(); await DisplayMessageAsync("Error 401. Access Denied. Please make sure you've logged\ninto OneDrive and your email at least once then try again."); } else if (ex.StatusCode == HttpStatusCode.NotFound) { await DisplayMessageAsync("Error 404. Resource requested is not available."); } else if (ex.StatusCode == HttpStatusCode.Conflict) { await DisplayMessageAsync("Error 409. Error backing up, issue retrieving backup folder. Please try again."); } else if (ex.StatusCode == HttpStatusCode.BadGateway) { await DisplayMessageAsync("Error 502. Bad Gateway.\nPlease check your internet connection and try again in a few."); } else if (ex.StatusCode == HttpStatusCode.ServiceUnavailable) { await DisplayMessageAsync("Error 503. Service unavailable due to high load or maintenance.\nPlease try again in a few."); } else if (ex.IsMatch(GraphErrorCode.GeneralException.ToString())) { await DisplayMessageAsync("General Exception. Please check your internet connection and try again in a few."); } } catch (MsalException msalex) { if (msalex.ErrorCode == MsalError.AuthenticationCanceledError) { await DisplayMessageAsync(msalex.Message); } else if (msalex.ErrorCode == MsalError.InvalidGrantError) { // invalid_grant comes from no consent to needed scopes await DisplayMessageAsync("Invalid access scopes, please contact the developer."); } } catch (Exception ex) { await DisplayMessageAsync("Unexpected Error: " + ex.Message); } finally { progressRing.IsActive = false; } }
/// <summary> /// Initiate backup of data to OneDrive. /// </summary> private async void BackupToOneDrive() { progressRing.IsActive = true; try { // Request a token to sign in the user var accessToken = await authProvider.GetAccessToken(); // Initialize Graph Client GraphServiceHelper.InitializeClient(authProvider); // Set current user (temp) App.CurrentUser = await GraphServiceHelper.GetMeAsync(); // Find backupFolder in user's OneDrive, if it exists var backupFolder = await GraphServiceHelper.GetOneDriveFolderAsync("Kanban Tasker"); // Create backup folder in OneDrive if not exists if (backupFolder == null) { backupFolder = await GraphServiceHelper.CreateNewOneDriveFolderAsync("Kanban Tasker") as DriveItem; } // Backup datafile (or overwrite) var uploadedFile = await GraphServiceHelper.UploadFileToOneDriveAsync(backupFolder.Id, DataFilename); await DisplayMessageAsync("Data backed up successfully."); var displayName = await GraphServiceHelper.GetMyDisplayNameAsync(); await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { txtResults.Text = "Welcome " + displayName; btnSignOutTip.IsEnabled = true; }); } catch (ServiceException ex) { if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) { // MS Graph Known Error // Users need to sign into OneDrive at least once // https://docs.microsoft.com/en-us/graph/known-issues#files-onedrive // Empty all cached accounts / data to allow user to rety await authProvider.SignOut(); await DisplayMessageAsync("Error 401. Access Denied. Please make sure you've logged\ninto OneDrive and your email at least once then try again."); } else if (ex.StatusCode == HttpStatusCode.NotFound) { await DisplayMessageAsync("Error 404. Resource requested is not available."); } else if (ex.StatusCode == HttpStatusCode.Conflict) { await DisplayMessageAsync("Error 409. Error backing up, issue retrieving backup folder. Please try again."); } else if (ex.StatusCode == HttpStatusCode.BadGateway) { await DisplayMessageAsync("Error 502. Bad Gateway.\nPlease check your internet connection and try again in a few."); } else if (ex.StatusCode == HttpStatusCode.ServiceUnavailable) { await DisplayMessageAsync("Error 503. Service unavailable due to high load or maintenance.\nPlease try again in a few."); } else if (ex.IsMatch(GraphErrorCode.GeneralException.ToString())) { await DisplayMessageAsync("General Exception. Please check your internet connection and try again in a few."); } } catch (MsalException msalex) { if (msalex.ErrorCode == MsalError.AuthenticationCanceledError) { await DisplayMessageAsync(msalex.Message); } else if (msalex.ErrorCode == MsalError.InvalidGrantError) { // invalid_grant ErrorCode comes from no consent // for the correct scopes (todo: add interactive retry) await DisplayMessageAsync("Invalid access scopes, please contact the developer."); } } catch (Exception ex) { await DisplayMessageAsync(ex.Message); } finally { progressRing.IsActive = false; } }