Ejemplo n.º 1
0
        public static ActivityResult SendSmsChallenge(
            [ActivityTrigger] VerificationParameter phone,
            [Microsoft.Azure.WebJobs.Table("approval", "AzureWebJobsStorage")] CloudTable table,
            ILogger log,
            [TwilioSms(AccountSidSetting = "TwilioAccountSid", AuthTokenSetting = "TwilioAuthToken", From = "%TwilioPhoneNumber%")]
            out CreateMessageOptions message)
        {
            try
            {
                int challengeCode = GetChallengeCode();

                log.LogInformation($"Sending verification code {challengeCode} to {phone.Payload}.");

                var entity = new ApprovalEntity(phone.OrchestrationId, "NewMember", challengeCode, EventNameSms);
                log.LogInformation(SimpleJson.SimpleJson.SerializeObject(entity));

                table.AddToTableStorageASync(entity).GetAwaiter().GetResult();
                message = new CreateMessageOptions(new PhoneNumber(phone.Payload));

                message.Body = $"Your verification code is {challengeCode:0000}";

                return(new ActivityResult {
                    HasError = false, Value = challengeCode
                });
            }
            catch (Exception ex)
            {
                message = null;
                return(new ActivityResult {
                    HasError = true, Value = ex.Message
                });
            }
        }
Ejemplo n.º 2
0
        public static async Task <ActivityResult> SendEMailVerification(
            [ActivityTrigger] VerificationParameter eMail,
            [Microsoft.Azure.WebJobs.Table("approval", "AzureWebJobsStorage")] CloudTable table,
            ILogger log, Microsoft.Azure.WebJobs.ExecutionContext context)
        {
            var config = new ConfigurationBuilder()
                         .SetBasePath(context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", true, true)
                         .AddEnvironmentVariables()
                         .Build();

            string uriFlow = config["flowRESTTarget"];

            log.LogInformation(config.ToString());

            int challengeCode = GetChallangeCode();

            try
            {
                var valueObject = new SendMail
                {
                    emailadress  = eMail.Payload,
                    emailSubject = "Confirmation of membership - " + challengeCode,
                    emailBody    = $"http://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}/api/approve/{challengeCode}"
                };

                var entity = new ApprovalEntity(eMail.OrchestrationId, "NewMember", challengeCode, EventNameEMail);
                await table.AddToTableStorageASync(entity);

                var client  = new RestClient(uriFlow);
                var request = new RestRequest(Method.POST);
                request.AddHeader("Cache-Control", "no-cache");
                request.AddHeader("Content-Type", "application/json");
                request.AddParameter("undefined", SimpleJson.SimpleJson.SerializeObject(valueObject), ParameterType.RequestBody);
                IRestResponse response = client.Execute(request);
                if (!response.IsSuccessful)
                {
                    log.LogError(new EventId(1, "EMail not sent"), $"EMail to receiver {valueObject.emailadress} could not be sent. Error: {response.Content}");
                }

                return(new ActivityResult {
                    HasError = false, Value = challengeCode
                });
            }
            catch (Exception ex)
            {
                return(new ActivityResult {
                    HasError = true, Value = ex.Message
                });
            }
        }
Ejemplo n.º 3
0
        public static async Task <object> Run(
            [OrchestrationTrigger] DurableOrchestrationContext context,
            ILogger log)
        {
            string input           = context.GetInput <string>();
            string orchestrationId = context.InstanceId;

            if (!context.IsReplaying)
            {
                log.LogInformation($"This is the input value: {input}");
            }

            var splitString = input.Split(',');

            if (splitString.Count() != 2)
            {
                throw new ArgumentException("To few arguments! Expected is phoneNumber and eMail");
            }
            var phoneNumber  = splitString[0];
            var emailAddress = splitString[1];

            if (string.IsNullOrEmpty(phoneNumber))
            {
                throw new ArgumentNullException(
                          nameof(phoneNumber),
                          "A phone number input is required.");
            }

            var phoneParameter = new VerificationParameter
            {
                OrchestrationId = orchestrationId,
                Payload         = phoneNumber
            };

            var emailParameter = new VerificationParameter
            {
                OrchestrationId = orchestrationId,
                Payload         = emailAddress
            };

            /*
             * The next following lines are for demonstrating error handling for FanOut-FanIn pattern
             *
             * it could be a "WhenAny" (would succeed), but taking "WhenAll" will lead to exception and stop if not handled correctly
             *
             */
            var fanOuts = new List <Task <ActivityResult> >();

            fanOuts.Add(context.CallActivityAsync <ActivityResult>("A1_SendSmsChallenge", phoneParameter));
            fanOuts.Add(context.CallActivityAsync <ActivityResult>("A2_SendEmailChallenge", emailParameter));

            var resultList = new List <ActivityResult>();
            var tasks      = fanOuts.Select(async task =>
            {
                try
                {
                    resultList.Add(await task);
                }
                catch (AggregateException ex)
                {
                    log.LogError($"############   Exception: {task.Exception?.Message}");
                }
            }).ToList();
            await Task.WhenAll(tasks);

            var codes = resultList.Where(x => !x.HasError).Select(x => (Int64)x.Value).ToList();

            context.SetCustomStatus(new { Codes = codes });

            using (var timeoutCts = new CancellationTokenSource())
            {
                // The user has 90 seconds to respond with the code they received in the SMS message or an eMail.
                DateTime expiration  = context.CurrentUtcDateTime.AddSeconds(_expirationValue);
                Task     timeoutTask = context.CreateTimer(expiration, timeoutCts.Token);

                bool authorized = false;
                for (int retryCount = 0; retryCount <= 3; retryCount++)
                {
                    context.SetCustomStatus(new { message = $"Retrynumber:{retryCount}" });
                    Task <int> smsResponseTask  = context.WaitForExternalEvent <int>(Activity_SendSMSChallenge.EventNameSms);
                    Task <int> mailResponseTask = context.WaitForExternalEvent <int>(Activity_SendEMailChallenge.EventNameEMail);

                    Task winner = await Task.WhenAny(smsResponseTask, mailResponseTask, timeoutTask);

                    if (winner != timeoutTask)
                    {
                        // We got back a response! Compare it to the challenge code.
                        if (codes.Contains(((Task <int>)winner).Result))
                        {
                            authorized = true;
                            break;
                        }
                    }
                    else
                    {
                        // Timeout expired
                        break;
                    }
                }

                if (!timeoutTask.IsCompleted)
                {
                    // All pending timers must be complete or canceled before the function exits.
                    timeoutCts.Cancel();
                }

                return(new { reason = input, isAuthorized = authorized });
            }
        }