How do I change an ASP.NET Identity user's email WITHOUT requiring an email confirmation? - asp.net-core

We have many non-tech-savvy users who find it very challenging to use the regular method of changing their email (click a link on the log-in page, enter their email, check their inbox, click the link in the email to confirm). We would like to allow the site admins to be able to change the emails directly, without requiring the users to do anything.
I realise that this has certain dangers, but we have checks in place to ensure that we are going to use the correct new email.
It seems that if I have the existing user from the database and the modified one from a <form> on the admin page, I can just do this...
existingUser.Email = modifiedUser.Email;
existingUser.NormalizedEmail = modifiedUser.Email.ToUpper();
existingUser.UserName = modifiedUser.Email;
existingUser.NormalizedUserName = modifiedUser.Email.ToUpper();
_appDbContext.Users.Update(existingUser);
await _appDbContext.SaveChangesAsync();
This does seem to work (with one caveat, see below), but given that I've never seen recommend this, and every example I've seen creates a token and uses UserManager.SetEmailAsync, I'm wondering if I've missed something.
The one caveat that makes me even more suspicious is that once or twice when I've tried the above, it's created a new user with the same details as the existing one, but the new email. I can't reproduce this, so can't say for definite what causes it.
Anyone able to comment on the best way to handle this? Thanks.

You can set and confirm the email without sending any email like this. Use the UserManager provided by ASP.NET Core Identity:
// set the email on the user, but don't send any email
await _userManager.SetEmailAsync(currentUser, newEmailAddress);
//generate an email confirmation token
var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(existingUser);
//confirm the new email right away
result = await _userManager.ConfirmEmailAsync(existingUser, emailConfirmationToken);

Related

When using GoogleWebAuthorizationBroker.AuthorizeAsync the user can click on the wrong email address

We're using this library Google.Apis.Auth.OAuth2 to request the user to enter oauth credentials.
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth
This line
var precreds = GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecret,
scopesList,
emailAddress,
CancellationToken.None,
new FileDataStore(AuthStorageDir)
);
var creds = await precreds;
This will popup a browser and request the user to click on the correct oauth account.
The issue is the emailAddress. In the documentation some places show its being set to "user" and other places say "the user to authorize". We're using the latter interpretation and are providing an email address. But the user could click on a different email address.
Does anyone know what is the correct interpretation?
If we are correct and an email address can be provided, is there a way to detect the email address they clicked on? and then popup a warning message.
I was also wondering what this user information is in GoogleWebAuthorizationBroker.AuthorizeAsync and was searching for an explanation as it is documented very poorly. I think I found the answer in the comments of the following topic: Check if user is already logged in
It is only an information about local users and has nothing to do with the user authenticated against the api. It only enables you to switch users in your application if you need this e.g. For every user an inidividual response file ist stored on your machine: C:\Users\WindowsUser\AppData\Roaming\Google.Apis.Auth\Google.Apis.Auth.OAuth2.Responses.TokenResponse-AuthorizeAsyncUser.
I will check this today in the evening.

How can a webhook identify USER_IDs?

I'm developing a webhook, and I want it to be able to #mention specific users. The simple message format specifies using the format of <users/123456789012345> to #mention a specific users. Since this is not a bot, it is not processing an incoming message and cannot pull the from the sender field, as suggested in the note on the developer site linked above.
How can I get the USER_ID of a user on my domain?
I am in the same boat as you. Trying to use a Webhook to mention a user.
If you inspect the HTML on https://chat.google.com, using web/dev tools, you can actually see user ID under tag data-member-id="user/bot/123456789012345"
Using the above I tried to form a webhook that mentioned the user (in my case another bot).
Unfortunately it didn't work. Passing in the string <users/123456789012345> please test came through to chat as a string literal.
It's strange because the html links and markup DO get interpreted. As mentioned here. Edit: so does <users/all>.
I'm leaving this here since your question asks for how to elicit the ID. While it may not be pretty, or much automatable, it helped me get the user ID at least.
Edit 2: It works, just not to mention my other bot for some reason. But using this method I was able to mention a human user :)
I use this for find the USER_ID but if you have another way let me know
Right click on the user and select inspect
Search for data-member-id this is your USER_ID
A webhook will not be able to pull the USER_ID of a user. As a workaround for this, you can create a service account and a bot that has access to the room and use the REST API spaces.members.list() and spaces.members.get() method.
Note: The bot will need to be added to the room.
Okay, so in order to get the UserID without having to do all of the things that you're trying to do here you need to use the Admin SDK API in google app script. Basically what you'll want to do is use your google app script as an intermediary for what you're trying to do. So you'll post something to google app script via their web exec functions on a deployed app and then have that app communicate to the google chat API via something like this:
var googlewebhookurl = 'https://chat.googleapis.com/v1/spaces/ASDFLKAJHEPQIHEWFQOEWNQWEFOINQ';
var options = {
'method': 'post',
'contentType': 'application/json',
'payload' : JSON.stringify({ text: "<users/000000000001> I see you!" })
}
UrlFetchApp.fetch(googlewebhookurl, options);
To start, you'll need to add the Admin SDK API to the services in your google app script services area. So click the plus next to "Services" and then select the Admin SDK API and click add to add it to the services, it winds up showing up in the list as "AdminDirectory" once it has been added to the services.
This is an image showing what it looks like once you've added it to the services.
Here is a link to the documentation for the Admin SDK API getting user information: https://developers.google.com/apps-script/advanced/admin-sdk-directory#get_user
You should be able to copy and paste that example function to get the information you're looking for regarding the user. I'm pasting the example code below in case something happens to this link:
/**
* Get a user by their email address and logs all of their data as a JSON string.
*/
function getUser() {
var userEmail = 'liz#example.com';
var user = AdminDirectory.Users.get(userEmail);
Logger.log('User data:\n %s', JSON.stringify(user, null, 2));
}
In order to get the user id, take the user variable that comes back and access user.id and voila! You have the ID you're looking for. From there just plaster it into a text message in google chat and you should be in business. I haven't gotten it to work with cards at all yet. I'm not seeing any documentation saying that it's supported in cards at all. For more information regarding chat messages and cards take a look at these:
https://developers.google.com/chat/api/guides/message-formats/basic
https://developers.google.com/chat/api/guides/message-formats/cards

Protractor E2E testing: email verification after creating an account

So I am writing some E2E tests for creating an account on a website. After creating a website account, the website will send me an email to verify my account so I can login. My question is, how far is E2E testing suppose to go? would I be going in the wrong direction if I use protractor to go to google, find the email, and click the link to verify myself. Then go back to the website and login? My other possible option would be to somehow get my userID and then send a request for verification?
I'm just not sure which direction would be best. Any ideas?
It is pretty much arguable how far your tests should go. But if there is a critical to testing information being sent on email, you should consider extracting that information during the test run.
In other words, this is so called "end-to-end testing", but both of the ends could be beyond the borders we are used to think and consider.
Here is the solution using mail-listener2 nodejs library that worked for me during the Two Factor Authentication functionality test (registration code is sent to an email after passing username/password verification step).
Personally I do test that a verification email gets sent with the correct contents — I do not, however, login at Google, to find the email. Instead I've exposed a server side function that returns the latest email it sent to a certain email address. Here's how I use it:
b.get(origin + '/-/e2e/last-email-sent?to=' + address, (response) => {
var responseObj = JSON.parse(response.body);
// Now I have the email text in responseObj.bodyHtmlText.
// Let's extract the URL to the next page:
// (it's the first thing we find that starts with our server origin, i.e.
// http://whatever/....)
var regexString = originRegexEscaped + '\\/[^"]+';
var matches = responseObj.bodyHtmlText.match(new RegExp(regexString));
if (!matches) {
b.assert.fail(responseObj.bodyHtmlText, regexString,
'No next-page-link regex match in email');
}
else {
// Tell our e2e browser to go to the page linked in the email
// as if the user had clicked the link in the email.
b.url(matches[0]);
}
});
I'm going to add lots of other funny e2e test server side functions too, like /-/e2e/fast-forward-time?how-much=3600-seconds :-)
What I do test, with a real Gmail user (a real Gmail account I created for e2e tests and nothing else), is just signups. I.e. that OpenAuth login works. If that works, I'm going to assume any Gmail user is thereafter able to read emails.

ServiceStack Authorization: Permitting Repeated Emails

we're using SS4 and would like to set it so that unique emails are not enforced (we have some customers who require the ability to repeat emails for different users).
Demis had mentioned that it's configurable, but a quick glance at the code doesn't reveal what to do to relax the requirement that every account has a unique email.
It looks like maybe we need to mess around with the RegistrationValidator?
is there a sample in the SS code anywhere that shows changing the validation rules for account registering to permit duplicate email addresses to be used?
You can configure it when you register the AuthFeature plugin with:
Plugins.Add(new AuthFeature(...) {
ValidateUniqueEmails = false
});
Simple solution in SS 3.x which I assume will work in SS 4.x
AssertNoExistingUser() checks for email uniqueness EVEN if you are trying to use a username as the username on the credentials and not the email.
The simple workaround is to create the user with a null email address (and a valid username).
Once the user is saved you can apply the email back into the user and call AuthRepo.PatchUserAuth(userAuth)
It will save and you wont have any problems.

Forgot Password: what is the best method of implementing a forgot password function?

I'm wondering what the best method is for creating a forgot password function on a website. I have seen quite a few out there, here are a few or combination of:
passphrase question / answer (1 or more)
send email with new password
on screen give new password
confirmation through email: must click link to get new password
page requiring user to enter a new password
What combination or additional steps would you add to a forgot password function? I'm wondering about how they request the new password and how they end up getting it.
I'm operating on the principal that the password cannot be retrieved; a new password must be given/generated.
Edit I like what Cory said about not displaying if the username exists, but I'm wondering what to display instead. I'm thinking half the problem is that the user forgot which email address they used, which displaying some sort of "does not exist" message is useful. Any solutions?
I personally would send an email with a link to a short term page that lets them set a new password. Make the page name some kind of UID.
If that does not appeal to you, then sending them a new password and forcing them to change it on first access would do as well.
Option 1 is far easier.
A few important security concerns:
A passphrase question / answer actually lowers security since it typically becomes the weakest link in the process. It's often easier to guess someone's answer than it is a password - particularly if questions aren't carefully chosen.
Assuming emails operate as the username in your system (which is generally recommended for a variety of reasons), the response to a password reset request shouldn't indicate whether a valid account was found. It should simply state that a password request email has been sent to the address provided. Why? A response indicating that an email does/doesn't exist allows a hacker to harvest a list of user accounts by submitting multiple password requests (typically via an HTTP proxy like burp suite) and noting whether the email is found. To protect from login harvesting you must assure no login/auth related functions provide any indication of when a valid user's email has been entered on a login/pass reset form.
For more background, checkout the Web Application Hackers Handbook. It's an excellent read on creating secure authentication models.
EDIT: Regarding the question in your edit - I'd suggest:
"A password request email has been
sent to the address you provided. If
an email doesn't arrive shortly,
please check your spam folder. If no
email arrives, then no account exists
with the email you provided."
There's a trade-off being made here between ease of use and security. You have to balance this based on context - is security important enough to you and your users to justify this inconvenience?
Send email with new password.
FORCE a password change when they arrive and key in the new password.
This ensures that the person who wanted the password will be the only only getting in to the account.
If the email is sniffed, someone could get in to the account (of course), but the real party will discover this immediately (as their password you just sent them doesn't work).
Also send confirmations of password changes to the users.
If someone get the new password, and then an email saying "thanx for changing the password", they're going to be rather puzzled and will talk to an admin if they didn't do it.
Using the email verification/password reset link will give you better security.
If you look around this is how most websites do it and people are pretty used to this verification, so I'd recommend using this type of authentication.
I would think (gbrandt's) Option 2 would be a great method if it is combined with some personal information you already have for the user. i.e date of birth.
When the user requests a new password (reset) via entering his email address, he also has to enter a correct date of birth (or something else) before the password is reset and a new one is emailed to the user.
Only those who know him well can possibly annoy him by resetting his password! It cant be a stranger or a bot
Upon 5 or 7 bad email-address & date of birth combinations the user is emailed that his password has been requested to be reset and has failed due to an incorrect credential. Then password resetting for that account is suspended for 24hrs or any desired period.
(if too many users contact the webadmin regarding this email he'll know someone is trying to maliciously attain information from your website/app)
What do you guys think?
Option 1. is not a good idea, as generally his becomes easily guessable by others. Sarah Palin's personal email (Yahoo I think) was hacked in this way by a third party.
The other options are better and previous posts have outlined the detail.
The idea I was thinking about was to sign the data in the link that is sent to the user. Then, when the user clicks the link and the server receives the call, the server also gets the encrypted part and can validate that the data was untouched.
I have implemented a JAVA project for this use case. It is on GitHub, open source. It answers your question perfectly... implemented in Java.
As for the link in the email - it generates the link, plus validates it upon usage.
There are explanation for everything (and if something is missing - let me know...)
Have a look: https://github.com/OhadR/Authentication-Flows
See a Demo here.
This is the client web-app that uses the auth-flows, with the README with all explanations. it directs you the implementation: https://github.com/OhadR/authentication-flows/tree/master/authentication-flows