Ejemplo n.º 1
0
        /// <summary>
        /// Retrieves and populates permissions descriptions from a Service Principal.
        /// </summary>
        /// <param name="config">The application configuration settings.</param>
        /// <param name="result">The JSON response of the permissions and their descriptions retrieved from the Service Prinicpal.</param>
        /// <param name="version">The version of the API from which to fetch the scopes descriptions from the Service Principal.</param>
        private static void PopulateScopesDescriptions(PermissionsAppConfig config,
                                                       AuthenticationResult result,
                                                       string version)
        {
            string webApiUrl = $"{config.ApiUrl}{version}/serviceprincipals?$filter=appId eq '{config.ServicePrincipalId}'";
            var    spJson    = ProtectedApiCallHelper
                               .CallWebApiAsync(webApiUrl, result.AccessToken)
                               .GetAwaiter().GetResult();

            if (string.IsNullOrEmpty(spJson))
            {
                throw new ArgumentNullException(nameof(spJson), $"The call to fetch the Service Principal returned empty data. URL: {webApiUrl} ");
            }

            var spJsonResponse = PermissionsFormatHelper.FormatServicePrincipalResponse(spJson, config);

            // Retrieve the top level scope dictionary
            var spValue = JsonConvert.DeserializeObject <JObject>(spJsonResponse).Value <JArray>(config.TopLevelDictionaryName);

            if (spValue == null)
            {
                throw new ArgumentNullException(nameof(config.TopLevelDictionaryName), $"Attempt to retrieve the top-level dictionary returned empty data." +
                                                $"Name: {config.TopLevelDictionaryName}");
            }

            /* Fetch permissions defined in the second level dictionary(ies),
             * e.g. appRoles, oauth2PermissionScopes --> 2nd level dictionary keys
             */
            foreach (string scopeName in config.ScopesNames)
            {
                // Retrieve all scopes descriptions for a given 2nd level dictionary retrieved from the Service Principal
                var scopeDescriptions = spValue.First.Value <JArray>(scopeName)?.ToObject <List <Dictionary <string, object> > >();

                if (scopeDescriptions == null)
                {
                    continue;
                }

                // Add a key to the reference dictionary (if not present)
                if (!_scopesDescriptions.ContainsKey(scopeName))
                {
                    _scopesDescriptions.Add(scopeName, new List <Dictionary <string, object> >());
                }

                /* Add each of the scope description from SP to the current key in the
                 * reference dictionary
                 */
                foreach (var scopeDesc in scopeDescriptions)
                {
                    /* Add only unique scopes (there might be duplicated scopes in both v1.0 and beta)
                     * Uniqueness identified by id of the scope description
                     */
                    bool newScope = _uniqueScopes.Add(scopeDesc["id"].ToString());
                    if (newScope)
                    {
                        _scopesDescriptions[scopeName].Add(scopeDesc);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public static void Run([TimerTrigger("0 0 9 * * 1-5")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"DescriptionsScraper function started. Time: {DateTime.UtcNow}");

            try
            {
                PermissionsAppConfig permsAppConfig = PermissionsAppConfig.ReadFromJsonFile("local.settings.json");

                log.LogInformation($"Authenticating into the Web API... Time: {DateTime.UtcNow}");
                var authResult = AuthService.GetAuthentication(permsAppConfig);

                if (authResult == null)
                {
                    log.LogInformation($"Failed to get authentication into the Web API. Time: {DateTime.UtcNow}");
                    return;
                }
                log.LogInformation($"Successfully authenticated into the Web API. Time: {DateTime.UtcNow}");

                _scopesDescriptions = new Dictionary <string, List <Dictionary <string, object> > >();
                if (permsAppConfig.ApiVersions?.Length > 0)
                {
                    _uniqueScopes = new HashSet <string>();

                    foreach (string apiVersion in permsAppConfig.ApiVersions)
                    {
                        log.LogInformation($"Fetching Service Principal permissions descriptions for {apiVersion}. Time: {DateTime.UtcNow}");
                        PopulateScopesDescriptions(permsAppConfig, authResult, apiVersion);
                        log.LogInformation($"Finished fetching Service Principal permissions descriptions for {apiVersion}. Time: {DateTime.UtcNow}");
                    }
                }

                if (!_scopesDescriptions.Any())
                {
                    log.LogInformation($"{nameof(_scopesDescriptions)} dictionary returned empty data. " +
                                       $"Exiting function DescriptionsScraper Time: {DateTime.UtcNow}");
                    return;
                }

                var servicePrincipalScopes = JsonConvert.SerializeObject(_scopesDescriptions, Formatting.Indented)
                                             .Replace("\r", string.Empty); // Hack to avoid whitespace diff with GitHub source document (formatted with only \n)

                // Fetch permissions descriptions from GitHub repo
                var gitHubAppConfig = new GitHubRepoAppConfig
                {
                    GitHubAppId          = permsAppConfig.GitHubAppId,
                    GitHubOrganization   = permsAppConfig.GitHubOrganization,
                    GitHubAppName        = permsAppConfig.GitHubAppName,
                    GitHubRepoName       = permsAppConfig.GitHubRepoName,
                    ReferenceBranch      = permsAppConfig.ReferenceBranch,
                    FileContentPath      = permsAppConfig.FileContentPath,
                    WorkingBranch        = permsAppConfig.WorkingBranch,
                    Reviewers            = permsAppConfig.Reviewers,
                    PullRequestTitle     = permsAppConfig.PullRequestTitle,
                    PullRequestBody      = permsAppConfig.PullRequestBody,
                    PullRequestLabels    = permsAppConfig.PullRequestLabels,
                    PullRequestAssignees = permsAppConfig.PullRequestAssignees,
                    CommitMessage        = permsAppConfig.CommitMessage,
                    TreeItemMode         = Enums.TreeItemMode.Blob
                };

                log.LogInformation($"Fetching permissions descriptions from GitHub repository '{gitHubAppConfig.GitHubRepoName}', branch '{permsAppConfig.ReferenceBranch}'. " +
                                   $"Time: {DateTime.UtcNow}");

                // Fetch permissions descriptions from repo.
                var repoScopes = BlobContentReader.ReadRepositoryBlobContentAsync(gitHubAppConfig, permsAppConfig.GitHubAppKey).GetAwaiter().GetResult();

                log.LogInformation($"Finished fetching permissions descriptions from GitHub repository '{gitHubAppConfig.GitHubRepoName}', branch '{permsAppConfig.ReferenceBranch}'. " +
                                   $"Time: {DateTime.UtcNow}");

                log.LogInformation($"Comparing scopes from the Service Principal and the GitHub repository '{gitHubAppConfig.GitHubRepoName}', branch '{permsAppConfig.ReferenceBranch}' " +
                                   $"for new updates... Time: {DateTime.UtcNow}");

                // Compare GitHub permissions descriptions to Service Principal permissions descriptions
                if (servicePrincipalScopes.Equals(repoScopes, StringComparison.OrdinalIgnoreCase))
                {
                    log.LogInformation($"No permissions descriptions update required. Exiting function 'DescriptionsScraper'. Time: {DateTime.UtcNow}");
                    return;
                }

                // Save the new Service Principal scopes
                gitHubAppConfig.FileContent = servicePrincipalScopes;

                log.LogInformation($"Writing updated Service Principal permissions descriptions into GitHub repository '{gitHubAppConfig.GitHubRepoName}', " +
                                   $"branch '{gitHubAppConfig.WorkingBranch}'. Time: {DateTime.UtcNow}");

                // Write permissions descriptions to repo.
                BlobContentWriter.WriteToRepositoryAsync(gitHubAppConfig, permsAppConfig.GitHubAppKey).GetAwaiter().GetResult();

                log.LogInformation($"Finished updating Service Principal permissions descriptions into GitHub repository '{gitHubAppConfig.GitHubRepoName}', " +
                                   $"branch '{gitHubAppConfig.WorkingBranch}'. Time: {DateTime.UtcNow}");

                // Create PR
                log.LogInformation($"Creating PR for updated Service Principal permissions descriptions in GitHub repository '{gitHubAppConfig.GitHubRepoName}'" +
                                   $" from branch '{gitHubAppConfig.WorkingBranch}' into branch '{gitHubAppConfig.ReferenceBranch}'. Time: {DateTime.UtcNow}");

                PullRequestCreator.CreatePullRequestAsync(gitHubAppConfig, permsAppConfig.GitHubAppKey).GetAwaiter().GetResult();

                log.LogInformation($"Finished creating PR for updated Service Principal permissions descriptions in GitHub repository '{gitHubAppConfig.GitHubRepoName}'" +
                                   $" from branch '{gitHubAppConfig.WorkingBranch}' into branch '{gitHubAppConfig.ReferenceBranch}'. Time: {DateTime.UtcNow}");

                log.LogInformation($"Exiting function DescriptionsScraper. Time: {DateTime.UtcNow}");
            }
            catch (ApiException ex)
            {
                if (ex.ApiError.Errors != null)
                {
                    foreach (var item in ex.ApiError.Errors)
                    {
                        log.LogInformation($"Exception occurred: {item.Message} Time: {DateTime.UtcNow}");
                    }
                    return;
                }

                log.LogInformation($"Exception occurred: {ex.ApiError.Message} Time: {DateTime.UtcNow}");
            }
            catch (Exception ex)
            {
                log.LogInformation($"Exception occurred: {ex.InnerException?.Message ?? ex.Message} Time: {DateTime.UtcNow}");
                log.LogInformation($"Exception stack trace: {ex.StackTrace}");
            }
        }