Facebook login in asp.net core not working and return 500 - facebook

I have been using facebook login for one of my asp.net core projects. However, it stopped working for Facebook login suddenly. I am getting HTTP 500 error.
The issue is, even in the debug more, asp.net core is not mentioning any error. It is just same 500 error code. Nothing else.
When I tried to set breakpoint in the first line of public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null) function, I realized that it is not even hitting that and failing even before that.
I am not sure how to debug this further. Am I missing anything here? Or is there any change from FB in the login side?
The return URL being hit is by Facebook is:
https://localhost:44300/signin-facebook?code=AQBxGGw7ZCoa9xtXc3CCsVGRD9TJLL428bZ_eJpUu4CtVu3K4UrfOZuYYdwFBXzGZ6GOGXpOi2Nme_jfbewB84otVZhKZfs4i7Dhi9Y3E_rloU9ouLeIvuOsm29jr7IDCtTj_HM7rKuKjj3zmc4yz5i_fniZ9ZhMfXtSus5KyKa4EFkZTsmKrz2ngMlGQalUAob_52GJNhvSIXDlmiNSrZLJV3m7Zbkf9eXETQkqhu2L1kgXPvWkMzVP8EN00GwRCYB3xT1kQMOimDANRKhziZjoVS5QZFUJTP0Faj47tE1xNfmAzb30iuwcaRORCOTMipUrnRvOO4nGRo8JuUNdPJaO&state=CfDJ8EHIO3qHMHFClr5BAt4EC1Wj7LyAs5Pg1XOqKo4uFiJM2Jr1rNyooxLIu2fbXr6Z3X5_kqbF_7WwFfvF3L3H4xgyooo-3Y9BV8Zh1S5wXlLJDAyCT5_LwkPJ1j8Zrwx4umQJp6NOl76GwRXpi1_BHlWGRxnh_naTL35iqeGovOa8oEDC0jOQ4trRe7YG3fV_ptjWk4yOnvJnsI81O-6wfyhdc3jm-LTP7ZO7-duf_lPZXZ8mL42XyLXDTIyOJ__S2yLYdvwItdDVntsM8Hwq94goXdU-RaH7ZkDA8iAzeCl3Ke0tWAdYBKy9vooJIXmE9Q#_=_
Based on this article, it should have state_token too in the URL. But that seems to be missing here. How can I figure out here what is the actual error?
I am using asp.net core RC2 release.
My callback function is:
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null)
{
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
if (email == null)
{
return View("Error");
}
/* Determine user from external login info */
var name = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Name);
string firstName;
string lastName = "";
if (!string.IsNullOrWhiteSpace(name))
{
firstName = name.Split(' ').Length > 1? name.Split(new[] { ' ' }, 2)[0] : name;
lastName = name.Split(' ').Length > 1 ? name.Split(new[] { ' ' }, 2)[1] : "";
}
else
firstName = email.Split('#')[0];
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
/* No user with same email ID. So, create a new user.*/
var newUser = new ApplicationUser
{
UserName = email,
Email = email,
FirstName = firstName,
LastName = lastName,
PasswordLastModifiedTime = DateTime.UtcNow,
UserSignUpDate = DateTime.UtcNow
};
var userCreationResult = await _userManager.CreateAsync(newUser);
if (userCreationResult.Succeeded)
{
userCreationResult = await _userManager.AddLoginAsync(newUser, info);
if (userCreationResult.Succeeded)
{
// Add user claims TODO:// Test if the claims are added successfully.
await _userManager.AddClaimAsync(newUser, new Claim("FirstName", newUser.FirstName));
await _userManager.AddClaimAsync(newUser, new Claim("LastName", newUser.LastName));
// Set user email to confirmed. This is more of work around
var code = await _userManager.GenerateEmailConfirmationTokenAsync(newUser);
userCreationResult = await _userManager.ConfirmEmailAsync(newUser, code);
if (userCreationResult.Succeeded)
{
//Create Subscription for user
var planService = new PlanServices();
var plan = planService.Find((int)SubscriptionType.Basic);
await _subscriptionService.CreateSubscription(newUser, plan, null);
await _signInManager.SignInAsync(newUser, isPersistent: false);
_logger.LogInformation(6, "User created an account using {Name} provider.",
info.LoginProvider);
await _emailSender.SendWelcomeEmailAsync(newUser.Email, newUser.FirstName);
return RedirectToLocal(returnUrl);
}
}
}
}
else
{
/* A user with email ID exists. Associate the account with that.*/
var loginAddResult = await _userManager.AddLoginAsync(user, info);
if (loginAddResult.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email, FirstName = firstName, LastName = lastName});
}
}
And ConfigureServices method is:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddScoped<ApplicationDbContext>();
services.AddIdentity<ApplicationUser, IdentityRole>(o =>
{
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonLetterOrDigit = false;
o.Password.RequiredLength = 8;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddCaching();
services.AddSession();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.AddTransient<ISubscriptionService, SubscriptionService>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.Configure<RecaptchaOptions>(Configuration);
__serviceProvider = services.BuildServiceProvider();
}
The thing is, it worked well for a long time and has stopped working now. Also, it is not even hitting ExternalLoginCallback, so I am not sure where to head for debugging it further.

Related

Flutter add multiple value into map

So I'm trying to create a flutter app. In my app user A can invite user B,C and so on to join the group, but the user invited can reject the ticket. The user ID that reject the ticket will be stored in the firestore to detect which id reject it and there's a reason why.
The database data looks like this:
- Rejected_detail_map
----Rejected_role_admin
-------- USER_ID_A : "REASON_TO_REJECT"
-------- USER_ID_C : "REASON_TO_REJECT"
----Rejected_role_member
-------- User_ID_B :"REASON_TO_REJECT_2"
I wanted to fetch the data from each rejected_detail_map in one of my page, and use that ID to get the information such as nickname, prof_pic, etc.
Here's how I do it:
if (data['reject_detail_map'] != null) {
if (data['reject_detail_map'].isNotEmpty) {
List rejectDetailKeyList = data['reject_detail_map'].keys.toList();
if (rejectDetailKeyList.contains('rejected_by_pic')) {
List picIdRejectList = data['reject_detail_map']['rejected_by_pic'].keys.toList();
Map picRejectData = {};
await Future.forEach(picIdRejectList, (picId) async {
try {
if (Provider.of<OtherUserDataProvider>(context, listen: false)
.getUserData(picId.toString()) ==
null) {
picRejectData[picId] = await UserDatabase.getUserShortData(userId: picId.toString(), context: context);
Provider.of<OtherUserDataProvider>(context, listen: false).setUserData(userInfo: picRejectData[picId], userId: picId.toString());
picRejectData[picId]['role'] = 'pic';
picRejectData[picId]['reject_text'] = data['reject_detail_map']['rejected_by_pic'][picId];
ticketData['user_reject_data'] = Map.of(picRejectData);
} else {
picRejectData[picId] = Map.of(Provider.of<OtherUserDataProvider>(context, listen: false).getUserData(picId.toString())!);
picRejectData[picId]['role'] = 'pic';
picRejectData[picId]['reject_text'] = data['reject_detail_map']['rejected_by_pic'][picId];
ticketData['user_reject_data'] = Map.of(picRejectData);
}
} catch (e) {
DevMode.log("Error: $e");
}
});
}
if (rejectDetailKeyList.contains('rejected_by_client')) {
List clientIdRejectList = data['reject_detail_map']['rejected_by_client'].keys.toList();
Map clientRejectData = {};
await Future.forEach(clientIdRejectList, (clientId) async {
try {
if (Provider.of<OtherUserDataProvider>(context, listen: false)
.getUserData(clientId.toString()) ==
null) {
clientRejectData[clientId] = await UserDatabase.getUserShortData(userId: clientId.toString(), context: context);
Provider.of<OtherUserDataProvider>(context, listen: false).setUserData(userInfo: clientRejectData[clientId], userId: clientId.toString());
clientRejectData[clientId]['role'] = 'client';
clientRejectData[clientId]['reject_text'] = data['reject_detail_map']['rejected_by_client'][clientId];
ticketData['user_reject_data'] = Map.of(clientRejectData);
} else {
clientRejectData[clientId] = Map.of(
Provider.of<OtherUserDataProvider>(context, listen: false)
.getUserData(clientId.toString())!);
clientRejectData[clientId]['role'] = 'client';
clientRejectData[clientId]['reject_text'] = data['reject_detail_map']['rejected_by_client'][clientId];
ticketData['user_reject_data'] = Map.of(clientRejectData);
}
} catch (e) {
DevMode.log("Error: $e");
}
});
}
}
}
The problem is the ticketData['user_reject_data'] is always limited to 1 person, like the data from before next id is overwritten. So if there are 2 person rejecting the invitation:
User A reject as admin
User B reject as member
the data that i expect to be shown when printing the 'user_reject_data' are:
user_reject_data{
"user_A" : {his info}
"user_B" : {his info}
}
but i will always get only the user B data, like the user A is being over written. I guess there's something wrong with the way I add the data to the map. How to fix this ?

PayPal authentication problem on azure "live store"

I am getting the following error when trying to use paypal API
HttpStatusCode: Unauthorized; AUTHENTICATION_FAILURE; Authentication failed due to invalid authentication credentials or a missing Authorization header.
But problem is only when i publish my code to Azure Api. Live store works if I run it on visual studio.
public async Task<bool> InvoicingCreate(Models.ShopTransaction t)
{
sentJson = null;
if (_accessToken == null) await GetAccessTokenAsync();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "v2/invoicing/invoices");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken.access_token);
bool addNotes;
if (t.Product.TotalPrice == 0.0) addNotes = false;
else if (t.PaymentMethod == null) addNotes = true;
else if (t.PaymentMethod == "paypal" || t.PaymentMethod == "credit_card") addNotes = false;
else addNotes = true;
string billingEmail;
if (t.Product.IndividualCouponId.HasValue)
{
billingEmail = _configuration["Shop:CouponInvoiceEmail"];
}
else
{
billingEmail = t.BillingAddress.Email;
}
var inv = new Root
{
detail = new Detail
{
.......details the items. ...
},
.......Fill the items. ...
sentJson = JsonConvert.SerializeObject(inv, Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
request.Content = new StringContent(JsonConvert.SerializeObject(inv), Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.SendAsync(request);
string content = await response.Content.ReadAsStringAsync();
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
Error error = JsonConvert.DeserializeObject<Error>(content);
throw new Exception(CompactError("Invoicing-create", response.StatusCode, error));
}
CreateResponse invoiceCreated = JsonConvert.DeserializeObject<CreateResponse>(content);
t.InvoiceId = invoiceCreated.href.Split('/').Last();
return true;
}
Auth methode
appsettings.json paypalmodel
Invoicing methode
I found the problem.
It's an domain issue. It has send to many request on paypal server. So classic denial of service.

Asp.Net Core Identity Create User

I have trouble creating a user. The process runs correctly, reads data to user, redirects to Home / Index, but there is no new user in the database.
I have the same code in DbSeeder and the users are created correctly there.
[HttpPost]
public async Task<IActionResult> Create(WorkerVM model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByNameAsync(model.Username);
if (user == null)
{
user = new User()
{
FirstName = model.FirstName,
LastName = model.LastName,
Email = model.Username,
UserName = model.Username
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, "Worker");
}
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError("", "Registration Failed");
return View();
}
The most possible reason that the user is not created in db is the new password doesn't fit the password criteria.
Check the password criterias and fix the password. Also fixed your code by moving "}" behind the first return operator:
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, "Worker");
return RedirectToAction("Index", "Home");
}
you can manage your password criteria adding this code to startup
services.Configure<IdentityOptions>(x => {
x.Password.RequireDigit = false;
x.Password.RequiredLength = 2;
x.Password.RequireUppercase = false;
x.Password.RequireLowercase = false;
x.Password.RequireNonAlphanumeric = false;
x.Password.RequiredUniqueChars = 0;
x.Lockout.AllowedForNewUsers = true;
x.Lockout.MaxFailedAccessAttempts = 5;
x.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(30);
});

Box.com API Usage - Get Folder Count as a service app

We are creating an app that is meant to be used with a Service Account in your system; another user (user-2) has authorized this app by adding our app key to their Custom Application list. How do I get this User-2's UserID, so we can impersonate him and access his files list and files, etc. We need their UserID, so we can pass the "AS-User: " Header. And can this header be set using some property from within the .NET SDK - a sample code will be appreciated.
This does it for all enterprise users but you can easily put an if statement to get the user you're looking for.
static async Task MainAsync()
{
// rename the private_key.pem.example to private_key.pem and put your JWT private key in the file
var privateKey = File.ReadAllText(PRIVATE_KEY_FILE);
var boxConfig = new BoxConfig(CLIENT_ID, CLIENT_SECRET, ENTERPRISE_ID, privateKey, JWT_PRIVATE_KEY_PASSWORD, JWT_PUBLIC_KEY_ID);
var boxJWT = new BoxJWTAuth(boxConfig);
var adminToken = boxJWT.AdminToken();
Console.WriteLine("Admin Token: " + adminToken);
Console.WriteLine();
var adminClient = boxJWT.AdminClient(adminToken); // adminClient == serviceAccount
var userDetails = await adminClient.UsersManager.GetCurrentUserInformationAsync();
Console.WriteLine("\tAdmin User Details:");
Console.WriteLine("\tId: {0}", userDetails.Id);
Console.WriteLine("\tName: {0}", userDetails.Name);
Console.WriteLine("\tStatus: {0}", userDetails.Status);
Console.WriteLine();
var users = await adminClient.UsersManager.GetEnterpriseUsersAsync();
users.Entries.ForEach(i =>
{
Console.WriteLine("\t{0}", i.Name);
Console.WriteLine("\t{0}", i.Status);
if (i.Status == "active")
{
var userToken = boxJWT.UserToken(i.Id);
var userClient = boxJWT.UserClient(userToken, i.Id);
Task u = getUserItems(userClient, i.Id);
u.Wait();
}
});
}
static async Task getUserItems(BoxClient userClient, string id)
{
var userDetails = await userClient.UsersManager.GetCurrentUserInformationAsync();
Console.WriteLine("\nManaged User Details:");
Console.WriteLine("\tId: {0}", userDetails.Id);
Console.WriteLine("\tName: {0}", userDetails.Name);
Console.WriteLine("\tStatus: {0}", userDetails.Status);
Console.WriteLine();
Console.WriteLine("managed users older items");
var items = await userClient.FoldersManager.GetFolderItemsAsync("0", 500);
items.Entries.ForEach(i =>
{
Console.WriteLine("\t{0}", i.Name);
});
Console.WriteLine();
}

ConfirmEmailAsync() method is not working

I am having issue in confirming new user email. the Confirm email link works for first 20 minutes , but after 50 minutes the link expires. I have set the token expiration time to 24 hours. Please help me in resolving this issue. I am stuck on it for last 2 days:(.My code is as follows:
I am setting the token lifetime in Create() method in ApplicationUserManager as following:
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = _settings.ConfirmationAndResetTokenExpirationTimeSpan
};
}
And then In AccountsController, the Create method for new user is geiven below. The SendEmailAsync method consist of email subject, email body, generated password and the callback uri.
[Authorize(Roles = Roles.Bam.Name.Admin)]
[HttpPost]
[Route(Routes.Accounts.Template.Create, Name = Routes.Accounts.Name.Create)]
public async Task<IHttpActionResult> Create(CreateUserBindingModel createUserBindingModel)
{
IHttpActionResult result;
var memberNameExists = UserManager.Users.Any(x => x.MemberName.ToLower() == createUserBindingModel.MemberName.ToLower());
if (!memberNameExists)
{
var applicationUser = new ApplicationUser
{
UserName = createUserBindingModel.Email,
Email = createUserBindingModel.Email,
FirstName = createUserBindingModel.FirstName,
LastName = createUserBindingModel.LastName,
Company = createUserBindingModel.Company,
Location = createUserBindingModel.Location,
PhoneNumber = createUserBindingModel.PhoneNumber,
MemberName = createUserBindingModel.MemberName,
LastLoginDate = SqlDateTime.MinValue.Value,
CreateDate = DateTime.Now,
CreatedBy = User.Identity.GetUserId(),
UpdateDate = DateTime.Now,
UpdatedBy = User.Identity.GetUserId(),
TwoFactorEnabled = createUserBindingModel.TwoFactorEnabled,
SecurityResetRequired = true,
PasswordExpirationDate = DateTime.Now.AddDays(Convert.ToDouble(ConfigurationManager.AppSettings["PasswordExpirationDays"]))
};
if (!string.IsNullOrEmpty(createUserBindingModel.AvatarBase64))
{
var avatarBytes = Convert.FromBase64String(createUserBindingModel.AvatarBase64);
var resizedAvatarBytes = ImageResizer.ResizeImage(avatarBytes, _avatarWidth, _avatarHeight);
applicationUser.UserAvatar = new ApplicationUserAvatar
{
Avatar = resizedAvatarBytes
};
}
var generatedPassword = PasswordGenerator.GenerateStrongPassword(10, 10);
var identityResult = await UserManager.CreateAsync(applicationUser, generatedPassword);
if (identityResult.Succeeded)
{
await UserManager.AddToRolesAsync(applicationUser.Id, createUserBindingModel.Roles.ToArray());
var token = await UserManager.GenerateEmailConfirmationTokenAsync(applicationUser.Id);
var callbackUri = string.Format("{0}?userId={1}&token={2}", createUserBindingModel.EmailConfirmationCallbackUri, applicationUser.Id, HttpUtility.UrlEncode(token));
await UserManager.SendEmailAsync(applicationUser.Id, Email.Confirmation.Subject, string.Format(Email.Confirmation.Body, string.Format("{0} {1}", applicationUser.FirstName, applicationUser.LastName), callbackUri, generatedPassword, _settings.AccessTokenExpirationTimeSpan.TotalHours));
var userUrl = new Uri(Url.Link(Routes.Accounts.Name.Get, new { id = applicationUser.Id }));
var roles = await UserManager.GetRolesAsync(applicationUser.Id);
var contract = _accountsMapper.ToContract(applicationUser, roles);
result = Created(userUrl, contract);
}
else
{
result = GetErrorResult(identityResult);
}
}
else
{
ModelState.AddModelError(string.Empty, "Member Name already exists!");
result = BadRequest(ModelState);
}
return result;
}
Once the email is generated the UI has following JS angular code which gets executed and the provide the userid and token to service.
Angular JS code:
angular.module('confirmEmailModule').factory('confirmEmailFactory', function ($http) {
var factory = {};
factory.confirmEmail = function(userId, token) {
var encodedToken = encodeURIComponent(token);
var uri = '/identity/api/accounts/confirmemail?userId=' + userId + '&token=' + token;
return $http.post(uri);
}
return factory;
});
and the Service is :
[AllowAnonymous]
[HttpPost]
[Route(Routes.Accounts.Template.ConfirmEmail, Name = Routes.Accounts.Name.ConfirmEmail)]
public async Task<IHttpActionResult> ConfirmEmail([FromUri] string userId, [FromUri] string token)
{
//var decodedToken = HttpUtility.UrlDecode(token);
var identityResult = await UserManager.ConfirmEmailAsync(userId, token);
var result = identityResult.Succeeded ? StatusCode(HttpStatusCode.NoContent) : GetErrorResult(identityResult);
return result;
}
Please advice.
I found the solution to this issue. I am posting it if somebody faced the same issue. In my case the services and web API were on different servers. Different machine keys caused this issue. So I generated the machine key for my Web application and posted the same machine key in web.config file of Identity service. After that it worked. For more information on generating machine key, following link is helpful.
http://gunaatita.com/Blog/How-to-Generate-Machine-Key-using-IIS/1058
This is what worked for me. Hope it helps out;
public async Task<IActionResult> ConfirmEmail(string userId, string token)
{
if (userId == null || token == null)
{
return RedirectToAction("employees", "home");
}
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"The User ID {userId} is invalid";
return View("NotFound");
}
var result = await userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(token));
if (result != null)
{
user.EmailConfirmed = true;
await userManager.UpdateAsync(user);
return View();
}
}