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)); } }
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))); } }
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); }
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)); }
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))); } }