public static async Task <string> GetCurrentAemoPassword(TraceWriter log)
        {
            log.Info($"Initializing get current AEMO password in persistence: {DateTime.Now}");

            var KeyVaultUrlFromConfig = Environment.GetEnvironmentVariable("KeyVaultUrl");
            var environment           = Environment.GetEnvironmentVariable("Environment");

            var          keyVaultUrl  = string.Format("{0}/secrets/AemoFtpPassword", KeyVaultUrlFromConfig);
            SecretBundle secretBundle = new SecretBundle();

            var azureServiceTokenProvider = new AzureServiceTokenProvider();

            try
            {
                log.Info($"Creating kv client...");
                var keyVaultClient = new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

                log.Info($"Retrieving secret {keyVaultUrl}");
                secretBundle = await keyVaultClient.GetSecretAsync(keyVaultUrl)
                               .ConfigureAwait(false);
            }
            catch (Exception exp)
            {
                var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Could not get current AEMO password from {keyVaultUrl} with response {exp.Message}</span>";
                log.Error(exceptionMessage);
                await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");
            }

            log.Info($"Finalizing get current AEMO password in persistenced: {DateTime.Now}");

            return(secretBundle.Value);
        }
コード例 #2
0
        /// <summary>Start or stop the function apps</summary>
        /// <param name="log"></param>
        /// <param name="accessToken"></param>
        /// <param name="start"></param>
        /// <param name="resourceGroupToStopStart"></param>
        /// <param name="appService"></param>
        private static async Task <bool> StartFunctionApp(TraceWriter log, string accessToken, bool start, string resourceGroupToStopStart, string appService)
        {
            string action = start == true ? "start" : "stop";

            log.Info($"Initializing {action} function app {resourceGroupToStopStart}|{appService}: {DateTime.Now}");

            var subscriptionId = Environment.GetEnvironmentVariable("SubscriptionId");
            var environment    = Environment.GetEnvironmentVariable("Environment");

            var baseUrl = "https://management.azure.com/subscriptions/" + subscriptionId + "/resourceGroups/" + resourceGroupToStopStart + "/providers/Microsoft.Web/sites/" + appService + "/" + action + "?api-version=2016-08-01";

            Dictionary <string, string> headers = new Dictionary <string, string>()
            {
                { "Authorization", string.Format("Bearer {0}", accessToken) }
            };

            var httpClient = HttpClientHelper.GetOrCreateClient(baseUrl, headers);

            var response = await httpClient.PostAsync(baseUrl, null);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">{action} function app {appService} failed with response {response.Content.ReadAsStringAsync().Result}</span>";
                log.Error(exceptionMessage);
                await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");

                return(false);
            }

            log.Info($"Finalizing {action} function app {resourceGroupToStopStart}|{appService}: {DateTime.Now}");

            return(true);
        }
コード例 #3
0
        /// <summary>Cycle through lists of apps to stop</summary>
        /// <param name="log"></param>
        /// <param name="accessToken"></param>
        /// <param name="rgsWithApps"></param>
        /// <param name="start"></param>
        private static async Task <bool> StartStopApps(TraceWriter log, string accessToken, List <string> rgsWithApps, bool start)
        {
            bool allStopped  = false;
            var  environment = Environment.GetEnvironmentVariable("Environment");

            foreach (var item in rgsWithApps)
            {
                var rgWithApp = item.Split('|').ToList();

                bool appStopped = await StartFunctionApp(log, accessToken, start, rgWithApp[0], rgWithApp[1]);

                if (appStopped == false)
                {
                    var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Not all apps were stopped. ABORTING: {DateTime.Now}</span>";
                    log.Error(exceptionMessage);
                    await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");

                    break;
                }

                allStopped = true;
            }

            return(allStopped);
        }
        public static async Task <string> RotateAndAddNewAemoPassword(TraceWriter log, string lastAemoFtpPassword, string aemoFtpPassword, bool fakeIt)
        {
            log.Info($"Initializing rotate and add new AEMO password in persistence: {DateTime.Now}");
            if (fakeIt)
            {
                var environment = Environment.GetEnvironmentVariable("Environment");

                log.Info($"Faking password change: {DateTime.Now}");
                return($"Note: the application is running in test mode and therefore the [{environment}] AEMO password was not changed");
            }
            else
            {
                var keyVaultUrlFromConfig = Environment.GetEnvironmentVariable("KeyVaultUrl");
                var environment           = Environment.GetEnvironmentVariable("Environment");

                var aemoOldPasswordUrl = string.Format("{0}/secrets/LastAemoFtpPassword", keyVaultUrlFromConfig);
                var aemoNewPasswordUrl = string.Format("{0}/secrets/AemoFtpPassword", keyVaultUrlFromConfig);

                SecretBundle secretBundle = new SecretBundle();

                var azureServiceTokenProvider = new AzureServiceTokenProvider();

                var keyVaultClient = new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

                try
                {
                    log.Info($"Creating kv client...");

                    log.Info($"update secret LastAemoFtpPassword (first 4 characters):{lastAemoFtpPassword.Substring(0, 4)}");
                    secretBundle = await keyVaultClient.SetSecretAsync(keyVaultUrlFromConfig, string.Format("LastAemoFtpPassword"), lastAemoFtpPassword)
                                   .ConfigureAwait(false);
                }

                catch (Exception exp)
                {
                    var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Could not update old password AEMO password from (first 4 characters) {aemoOldPasswordUrl.Substring(0, 4)} with response {exp.Message}</span>";
                    log.Error(exceptionMessage);
                    await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");
                }

                try
                {
                    log.Info($"update newPassword secret newPassword (first 4 characters):{aemoFtpPassword.Substring(0, 4)}");
                    secretBundle = await keyVaultClient.SetSecretAsync(keyVaultUrlFromConfig, "AemoFtpPassword", aemoFtpPassword)
                                   .ConfigureAwait(false);
                }
                catch (Exception exp)
                {
                    log.Error($"Could not update new password AEMO password from {aemoNewPasswordUrl} with response {exp.Message}");
                }

                log.Info($"Finalizing rotate and add new AEMO password in persistence: {DateTime.Now}");

                return(secretBundle.Id);
            }
        }
コード例 #5
0
        /// <summary>Change the AEMO password</summary>
        /// <param name="log"></param>
        /// <param name="newPassword"></param>
        /// <param name="oldAemoPassword"></param>
        private static async Task <bool> ChangeAemoPassword(TraceWriter log, string newPassword, string oldAemoPassword, bool fakeIt)
        {
            log.Info($"Initializing ChangeAemoPassword: {DateTime.Now}");

            if (fakeIt)
            {
                log.Info($"Faking password change: {DateTime.Now}");
                return(true);
            }
            else
            {
                var aemoPasswordRestUrl = Environment.GetEnvironmentVariable("AemoPasswordRestUrl");
                var aemoOriginalWebSite = Environment.GetEnvironmentVariable("AemoOriginalWebSite");
                var aemoUserName        = Environment.GetEnvironmentVariable("AemoUserName");
                var environment         = Environment.GetEnvironmentVariable("Environment");

                var httpClient = HttpClientHelper.GetOrCreateClient(aemoPasswordRestUrl);

                AemoPayload aemoPayload = new AemoPayload
                {
                    AemoUrl     = aemoOriginalWebSite,
                    UserName    = aemoUserName,
                    OldPassword = oldAemoPassword,
                    NewPassword = newPassword
                };

                string payload = JsonConvert.SerializeObject(aemoPayload);

                var content  = new StringContent(payload, Encoding.UTF8, "application/json");
                var response = await httpClient.PostAsync(aemoPasswordRestUrl, content);

                AemoResponseDetail responseDetail = JsonConvert.DeserializeObject <AemoResponseDetail>(await response.Content.ReadAsStringAsync());

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Could not change Aemo password: (StatusCode:{ response.StatusCode}). Response { responseDetail.Result}</span>";
                    log.Error(exceptionMessage);
                    await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");

                    return(false);
                }

                log.Info($"Aemo password changes succesfully: (StatusCode:{response.StatusCode}). Response {responseDetail.Result}");
                log.Info($"Finalizing ChangeAemoPassword: {DateTime.Now}");

                return(true);
            }
        }
コード例 #6
0
        /// <summary>Get an Azure access_token</summary>
        /// <param name="log"></param>
        public static async Task <string> Authenticate(TraceWriter log)
        {
            log.Info($"Initializing Azure authentication: {DateTime.Now}");

            var tenant_id     = Environment.GetEnvironmentVariable("TenantId");
            var grant_type    = Environment.GetEnvironmentVariable("GrantType");
            var client_id     = Environment.GetEnvironmentVariable("ClientId");
            var client_secret = Environment.GetEnvironmentVariable("ClientSecret");
            var resource      = Environment.GetEnvironmentVariable("Resource");
            var environment   = Environment.GetEnvironmentVariable("Environment");

            var token_url = "https://login.microsoftonline.com/" + tenant_id + "/oauth2/token";

            // log.Info($"The token_url is: {token_url}");

            var httpClient = HttpClientHelper.GetOrCreateClient(token_url);

            var payload = $"client_id={client_id}&client_secret={client_secret}&grant_type={grant_type}&resource={resource}";

            // log.Info($"The payload is: {payload}");

            var content  = new StringContent(payload, Encoding.UTF8, "application/x-www-form-urlencoded");
            var response = await httpClient.PostAsync(token_url, content);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var exceptionMessage = string.Format("<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Access Token cannot be obtained, process terminating: {0}</span>", response.Content.ReadAsStringAsync().Result);
                log.Error(exceptionMessage);
                await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");

                return(null);
            }

            log.Info($"Request for token was successful, starting deserialization");

            AuthenticationTokenObject tokenResponse = JsonConvert.DeserializeObject <AuthenticationTokenObject>(await response.Content.ReadAsStringAsync());

            log.Info($"access_token is: {tokenResponse.AccessToken.Substring(0, 10)}XXXXXXX");
            log.Info($"Finalizing Azure authentication: {DateTime.Now}");

            return(tokenResponse.AccessToken);
        }
コード例 #7
0
        public static async Task Run([TimerTrigger("%WorkflowInitiatorTimer%")] TimerInfo myTimer, TraceWriter log)
        {
            log.Info($"Initializing AEMO workflow: {DateTime.Now}");

            bool fakeIt = true;

            var fakeItIsASetting = Environment.GetEnvironmentVariable("FakeIt") == null ? false : true;

            if (fakeItIsASetting)
            {
                fakeIt = bool.Parse(Environment.GetEnvironmentVariable("FakeIt"));
            }

            // Authenticate for Azure REST API
            var accessToken = await AuthenticateAzure.Authenticate(log);

            if (string.IsNullOrEmpty(accessToken))
            {
                throw new NullReferenceException("The access_token was returned as null");
            }

            var resourceGroupAndFunctionAppList = Environment.GetEnvironmentVariable("ResourceGroupAndFunctionAppList");
            var environment   = Environment.GetEnvironmentVariable("Environment");
            var emailHtmlBody = Environment.GetEnvironmentVariable("EmailHtmlBody");
            var slackBody     = Environment.GetEnvironmentVariable("SlackBody");
            var smsBody       = Environment.GetEnvironmentVariable("SmsBody");

            // A list of all apps that require stop, update config and start
            List <string> rgsWithApps = resourceGroupAndFunctionAppList.Split(';').ToList();

            // Did we stop all the apps?
            bool allStopped = await StartStopApps(log, accessToken, rgsWithApps, false);

            if (allStopped)
            {
                log.Info($"Function apps successfully stopped: {DateTime.Now}");

                // TODO : Move this inside if stopped maybe?
                var aemoFtpPassword = await Persistence.GetCurrentAemoPassword(log);

                string newPassword = PasswordGenerator.GeneratePassword(true, true, true, true, false, 8);

                // Call AEMO password changer
                bool passwordChanged = await ChangeAemoPassword(log, newPassword, aemoFtpPassword, fakeIt);

                if (passwordChanged)
                {
                    string rotatedPasswordUrlFromKeyVault = await Persistence.RotateAndAddNewAemoPassword(log, aemoFtpPassword, newPassword, fakeIt);

                    // Start function app
                    bool allStarted = await StartStopApps(log, accessToken, rgsWithApps, true);

                    if (allStarted)
                    {
                        log.Info($"Function app successfully started: {DateTime.Now}");
                    }

                    emailHtmlBody = string.Format(emailHtmlBody, environment, rotatedPasswordUrlFromKeyVault);
                    slackBody     = string.Format(slackBody, environment, rotatedPasswordUrlFromKeyVault);
                    smsBody       = string.Format(smsBody, environment, rotatedPasswordUrlFromKeyVault);

                    // send notifiaction to developers
                    await Messaging.SendNotification(log, fakeIt, emailHtmlBodyOverride : emailHtmlBody, slackBodyOverride : slackBody, smsBodyOverride : smsBody);
                }
                else
                {
                    var exceptionMessage = $"<h1>AEMO Password Changer Workflow Message</h1></br><span style = \"color:red;\">Could not change the AMO password: {DateTime.Now}</span>";
                    log.Error(exceptionMessage);
                    await Messaging.SendNotification(log, false, emailSubjectOverride : $"The [{environment}] AEMO password changer failed to change the AEMO password!", emailHtmlBodyOverride : exceptionMessage, slackBodyOverride : exceptionMessage, smsBodyOverride : exceptionMessage, slackIconOverride : ":bandit:");
                }
            }
            else
            {
                // Start function app
                bool allStarted = await StartStopApps(log, accessToken, rgsWithApps, true);

                if (allStarted)
                {
                    log.Info($"Function app successfully started: {DateTime.Now}");
                }
            }

            log.Info($"Finalizing AEMO workflow: {DateTime.Now}");
        }