public IHttpActionResult CheckPassword(string password)
        {
            string hashSH1          = Hash(password);
            string hashSH1FirstFive = hashSH1.Substring(0, 5);
            string hashSH1Rest      = hashSH1.Substring(5, hashSH1.Length - 5);

            string responseFromServer = "";

            string url = "https://api.pwnedpasswords.com/range/" + hashSH1FirstFive;

            // Create a request for the URL.
            WebRequest request = WebRequest.Create(url);

            // Get the response.
            WebResponse response = request.GetResponse();
            // Display the status.
            string status = ((HttpWebResponse)response).StatusDescription;

            // Get the stream containing content returned by the server.
            // The using block ensures the stream is automatically closed.
            using (Stream dataStream = response.GetResponseStream())
            {
                // Open the stream using a StreamReader for easy access.
                StreamReader reader = new StreamReader(dataStream);
                // Read the content.
                responseFromServer = reader.ReadToEnd();
                // Display the content.
                // Console.WriteLine(responseFromServer);
            }

            // Close the response.
            response.Close();

            var index = responseFromServer.IndexOf(hashSH1Rest);

            if (index > 0)
            {
                index = index + 36;
                var indexCount    = responseFromServer.IndexOf("\r", index);
                var indexLength   = indexCount - index;
                var passwordCount = responseFromServer.Substring(index, indexLength);

                return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Oh no — pwned! " +
                                                                               "This password has been seen " + passwordCount + " times before", HttpStatusCode.Conflict)));
            }
            else
            {
                OutputClaimsModel outputClaims = new OutputClaimsModel();
                outputClaims.passwordPwned = false;
                return(Ok(outputClaims));
            }
        }
示例#2
0
        public async Task <ActionResult <B2CResponseContent> > SignUp()
        {
            string input;

            // If no data came in, then return
            if (Request.Body == null)
            {
                throw new Exception();
            }

            //read data from body
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                input = await reader.ReadToEndAsync();
            }


            // Check the input content value
            if (string.IsNullOrEmpty(input))
            {
                return(StatusCode((int)HttpStatusCode.BadRequest, new B2CResponseContent("Request content is empty", HttpStatusCode.BadRequest)));
            }

            // Convert the input string into an InputClaimsModel object
            InputClaimsModel inputClaims = JsonConvert.DeserializeObject(input, typeof(InputClaimsModel)) as InputClaimsModel;

            if (inputClaims == null)
            {
                return(StatusCode((int)HttpStatusCode.BadRequest, new B2CResponseContent("Can not deserialize input claims", HttpStatusCode.BadRequest)));
            }

            // Run an input validation
            if (inputClaims.FirstName.ToLower() == "test")
            {
                return(StatusCode((int)HttpStatusCode.BadRequest, new B2CResponseContent("Test name is not valid, please provide a valid name", HttpStatusCode.BadRequest)));
            }

            // Create an output claims object and set the loyalty number with a random value
            OutputClaimsModel outputClaims = new OutputClaimsModel();

            outputClaims.LoyaltyNumber = new Random().Next(100, 1000).ToString();

            // Return the output claim(s)
            return(Ok(outputClaims));
        }
        public async System.Threading.Tasks.Task <IHttpActionResult> SignUpAsync()
        {
            // If no data came in, then return
            if (this.Request.Content == null)
            {
                throw new Exception();
            }

            // Read the input claims from the request body
            string input = Request.Content.ReadAsStringAsync().Result;

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Request content is empty", HttpStatusCode.Conflict)));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel  inputClaims  = JsonConvert.DeserializeObject(input, typeof(InputClaimsModel)) as InputClaimsModel;
            OutputClaimsModel outputClaims = new OutputClaimsModel();

            //Run API based logon against Legacy IdP, in this case it calls Azure AD's API based authentication endpoint
            using (HttpClient client = new HttpClient())
            {
                var tokenEndpoint = @"https://login.windows.net/contoso.onmicrosoft.com/oauth2/token";
                var accept        = "application/json";
                client.DefaultRequestHeaders.Add("Accept", accept);
                string postBody = System.String.Format(@"resource=https%3A%2F%2Fgraph.windows.net%2F&client_id=3ce2b90b-9570-4397-a05e-edd06d6d8b65&username={0}&password={1}&scope=openid&grant_type=password", inputClaims.email, HttpContext.Current.Server.UrlEncode(inputClaims.password));
                using (var response = await client.PostAsync(tokenEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded")))
                {
                    //if the creds auth'd - create the user with graph api into b2c
                    if (response.IsSuccessStatusCode)
                    {
                        //Run token validation

                        outputClaims.tokenSuccess      = true;
                        outputClaims.migrationRequired = false;
                        return(Ok(outputClaims));
                    }
                    return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Migrater API - Incorrect password", HttpStatusCode.Conflict)));
                }
            }
        }
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = "identity")] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function 'IdentityFunction' processed a request.");

            try{
                var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                var inputClaims = JsonConvert.DeserializeObject <InputClaimsModel>(requestBody);
                log.LogInformation("data received - {json}", requestBody);

                // validation example - used for signup
                if (inputClaims?.FirstName?.ToLower() == "test")
                {
                    throw new ArgumentException("Invalid First Name was specified");
                }

                // claims enrichment example sending back claims, can come from whatever data source
                var outputClaims = new OutputClaimsModel
                {
                    LoyaltyNumber = Guid.NewGuid().ToString(),
                    AccountId     = inputClaims.AccountId // tech echo back query string
                };

                log.LogInformation("sending output claims");

                return(new OkObjectResult(outputClaims));
            }
            catch (ArgumentException argEx)
            {
                return(new ConflictObjectResult(new B2CResponseContent(
                                                    argEx.Message,
                                                    HttpStatusCode.Conflict)));
            }
            catch (Exception ex)
            {
                return(new BadRequestObjectResult(new B2CResponseContent(
                                                      ex.Message,
                                                      HttpStatusCode.InternalServerError)));
            }
        }
示例#5
0
        private OutputClaimsModel Process(InputClaimsModel model, IdentityAction action)
        {
            _logger.LogInformation($"{nameof(IdentityService)}.{nameof(Process)} - Start");

            var isValid = action != IdentityAction.SignUp || ValidateInputClaims(model);

            if (!isValid)
            {
                throw new ArgumentException("Validation failed for InputClaims.");
            }

            var inputClaimsJson = JsonConvert.SerializeObject(model, Formatting.None);

            var outputClaims = new OutputClaimsModel
            {
                LoyaltyNumber = new Random().Next(100, 1000).ToString(),
                Action        = $"{action.ToString()} at {DateTimeOffset.UtcNow.Ticks}"
            };

            _logger.LogInformation($"{nameof(IdentityService)}.{nameof(Process)} - End");

            return(outputClaims);
        }
示例#6
0
        public async Task <ActionResult> LoalAccountPasswordReset()
        {
            string input = null;

            // If not data came in, then return
            if (this.Request.Body == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is null", HttpStatusCode.Conflict)));
            }

            // Read the input claims from the request body
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                input = await reader.ReadToEndAsync();
            }

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is empty", HttpStatusCode.Conflict)));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel inputClaims = InputClaimsModel.Parse(input);

            if (inputClaims == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not deserialize input claims", HttpStatusCode.Conflict)));
            }

            if (string.IsNullOrEmpty(inputClaims.signInName))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("User 'signInName' is null or empty", HttpStatusCode.Conflict)));
            }

            if (string.IsNullOrEmpty(inputClaims.signInName))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Password is null or empty", HttpStatusCode.Conflict)));
            }

            // Create a retrieve operation that takes a customer entity.
            // Note: Azure Blob Table query is case sensitive, always set the input email to lower case
            var retrieveOperation = TableOperation.Retrieve <UserTableEntity>(Consts.MigrationTablePartition, inputClaims.signInName.ToLower());

            CloudTable table = await GetSignUpTable(this.AppSettings.BlobStorageConnectionString);

            // Execute the retrieve operation.
            TableResult userMigrationEntity = await table.ExecuteAsync(retrieveOperation);

            if (userMigrationEntity != null && userMigrationEntity.Result != null)
            {
                try
                {
                    try
                    {
                        await MigrateUser(inputClaims, table, userMigrationEntity);

                        // Wait until user is created
                        await Task.Delay(3000);
                    }
                    catch (Exception ex)
                    {
                        return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not migrate user", HttpStatusCode.Conflict)));
                    }
                }
                catch (Exception ex)
                {
                    return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel($"User migration error: {ex.Message}", HttpStatusCode.Conflict)));
                }
            }

            AzureADGraphClient azureADGraphClient = new AzureADGraphClient(this.AppSettings.Tenant, this.AppSettings.ClientId, this.AppSettings.ClientSecret);

            GraphAccountModel account = await azureADGraphClient.SearcUserBySignInNames(inputClaims.signInName);

            if (account == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel($"An account could not be found for the provided user ID. (user migration)", HttpStatusCode.Conflict)));
            }

            OutputClaimsModel output = new OutputClaimsModel();

            output.objectId = account.objectId;

            return(Ok(output));
        }
示例#7
0
        public async System.Threading.Tasks.Task <IHttpActionResult> SignUpAsync()
        {
            // If no data came in, then return
            if (this.Request.Content == null)
            {
                throw new Exception();
            }

            // Read the input claims from the request body
            string input = Request.Content.ReadAsStringAsync().Result;

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Request content is empty", HttpStatusCode.Conflict)));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel  inputClaims  = JsonConvert.DeserializeObject(input, typeof(InputClaimsModel)) as InputClaimsModel;
            OutputClaimsModel outputClaims = new OutputClaimsModel();

            //Start migration process if we found the user and its not migrated already

            //Validate captcha blob at google
            using (HttpClient client = new HttpClient())
            {
                var validationEndpoint = @"https://www.google.com/recaptcha/api/siteverify";
                var secret             = "6LdifYcUAAAAAK0dmf7lDXwhJ_4e4dn_NS_SaFbe";
                var accept             = "application/json";
                client.DefaultRequestHeaders.Add("Accept", accept);
                string postBody = String.Format(@"secret={0}&response={1}", secret, HttpContext.Current.Server.UrlEncode(inputClaims.captcha));
                using (var response = await client.PostAsync(validationEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded")))
                {
                    var content = await response.Content.ReadAsStringAsync();

                    content = content.Replace("-", "_");
                    //if the creds auth'd - create the user with graph api into b2c
                    if (response.IsSuccessStatusCode)
                    {
                        dynamic json = JsonConvert.DeserializeObject(content);

                        //Handling scenario where you dont want to reset captcha on failed password
                        //Will accept the same captcha blob twice

                        /*if (json.success == "true" || json.error_codes[0] == "timeout_or_duplicate")
                         * {
                         *  return Content(HttpStatusCode.OK, new B2CResponseContent("", HttpStatusCode.OK));
                         * }*/

                        //Always requires fresh Captcha if the user submits the page with an error (eg wrong password)
                        if (json.success == "true")
                        {
                            return(Content(HttpStatusCode.OK, new B2CResponseContent("", HttpStatusCode.OK)));
                        }
                        else
                        {
                            return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Captcha failed, retry the Captcha.", HttpStatusCode.Conflict)));
                        }
                    }

                    return(Content(HttpStatusCode.Conflict, new B2CResponseContent("Captcha API call failed.", HttpStatusCode.Conflict)));
                }
            }
        }
        public async Task <ActionResult> SignUp()
        {
            string input = null;

            // If not data came in, then return
            if (this.Request.Body == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is null", HttpStatusCode.Conflict)));
            }

            // Read the input claims from the request body
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                input = await reader.ReadToEndAsync();
            }

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is empty", HttpStatusCode.Conflict)));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel inputClaims = InputClaimsModel.Parse(input);

            if (inputClaims == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not deserialize input claims", HttpStatusCode.Conflict)));
            }

            if (string.IsNullOrEmpty(inputClaims.signInName))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("User 'signInName' is null or empty", HttpStatusCode.Conflict)));
            }

            if (string.IsNullOrEmpty(inputClaims.password))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Password is null or empty", HttpStatusCode.Conflict)));
            }

            try
            {
                AzureADGraphClient azureADGraphClient = new AzureADGraphClient(this.AppSettings.Tenant, this.AppSettings.ClientId, this.AppSettings.ClientSecret);

                GraphAccountModel account = await azureADGraphClient.SearcUserBySignInNames(inputClaims.signInName);

                // Return an error if user already exists
                if (account != null)
                {
                    return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel($"A user with the specified ID already exists. Please choose a different one. (REST API)", HttpStatusCode.Conflict)));
                }

                // If user is not exist, return the password back to B2C
                OutputClaimsModel outputClaims = new OutputClaimsModel()
                {
                    password = inputClaims.password
                };
                return(Ok(outputClaims));
            }
            catch (Exception ex)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel($"General error (REST API): {ex.Message}", HttpStatusCode.Conflict)));
            }
        }
        public async Task <ActionResult> IsMemberOf()
        {
            string input = null;

            // If not data came in, then return
            if (this.Request.Body == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is null", HttpStatusCode.Conflict)));
            }

            // Read the input claims from the request body
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                input = await reader.ReadToEndAsync();
            }

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is empty", HttpStatusCode.Conflict)));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel inputClaims = InputClaimsModel.Parse(input);

            if (inputClaims == null)
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not deserialize input claims", HttpStatusCode.Conflict)));
            }

            if (string.IsNullOrEmpty(inputClaims.objectId))
            {
                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("User 'objectId' is null or empty", HttpStatusCode.Conflict)));
            }


            try
            {
                AzureADGraphClient azureADGraphClient = new AzureADGraphClient(this.AppSettings.Tenant, this.AppSettings.ClientId, this.AppSettings.ClientSecret);

                // Demo: Get user's groups
                GraphGroupsModel groups = await azureADGraphClient.GetUserGroup(inputClaims.objectId);

                // Demo: Add the groups to string collections
                List <string> groupsList = new List <string>();
                foreach (var item in groups.value)
                {
                    groupsList.Add(item.displayName);
                }

                // Demo: Set the output claims
                OutputClaimsModel output = new OutputClaimsModel()
                {
                    groups = groupsList
                };

                // Demo: Check if user needs to be a member of a security group
                if (!string.IsNullOrEmpty(inputClaims.onlyMembersOf))
                {
                    List <string> onlyMembersOf = inputClaims.onlyMembersOf.ToLower().Split(',').ToList <string>();
                    bool          isMemberOf    = false;
                    foreach (var item in output.groups)
                    {
                        if (onlyMembersOf.Contains(item.ToLower()))
                        {
                            isMemberOf = true;
                            break;
                        }
                    }

                    // Demo: Throw error if user is not member of one of the security groups
                    if (isMemberOf == false)
                    {
                        return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("You are not authorized to sign-in to this application.", HttpStatusCode.Conflict)));
                    }
                }

                // Demo: Return the groups collection
                return(Ok(output));
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Request_ResourceNotFound"))
                {
                    return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups, user not found", HttpStatusCode.Conflict)));
                }

                return(StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups", HttpStatusCode.Conflict)));
            }
        }