A user can claim any address and even if they don't verify it, that still blocks someone else from trying to claim it. This can be fixed in auth.py like:
- if M.EmailAddress.query.get(_id=new_addr['addr']): + if M.EmailAddress.query.get(_id=new_addr['addr'], confirmed=True):
However this leads to another problem, if multiple users have the same email address claimed (but not verified). One user sees a "verify" link, but the other sees "Unknown addr obj foo@bar.com", on the preferences page.
There probably are more issues when it gets to verification, too.
allura:al/7527
I think this is a good approach, but wow it has a pretty broad impact. I found several issues:
You left a few pydevd lines.
In
verify_addr
when other addresses are removed, we should log which were removed. In case there are issues and we need to check the logs to find out what happened. If [#7524] is merged yet, you can use those audit logs. Else just regular python logging is ok.by_email_address
andidentify_sender
andpassword_recovery_hash
methods use the user for the first record it finds. There could be multiple results though. Should limit it to confirmed address and I think that'll work then.These were true before this change, but might as well fix them now:
claim_only_addresses()
has a query on theclaimed_by_user_id
field which will run slowly since it's not the first field in any index. Butclaim_only_addresses
isn't used anywhere, so you can just delete it :) Andverify_addr
has a query bynonce
so we should add an index onnonce
. Might as well make it a unique index too, so we never risk duplicate nonces.The
upsert
method behavior changed so it always just gets a new one and never returns an existing one. Perhaps that is the way it should work now, but probably good to review the logic of eachupsert
call, I am not so sure. If that's how it should be, it should be renamed to reflect what it does. We also have one reference in SF's internal repo toEmailAddress.upsert
that I think needs to be changed (it assumes it'll get the existing record not a new one). That code also has aemail_record._id
which needs to be fixed.The migration fails for me with
ming.schema.Invalid: _id:admin2@users.sf.net is not a valid ObjectId
probably because its loading old data with the new model and so it doesn't validate. And I don't think a singleupdate()
call to change all directly in mongo would work either since we need to assign new ObjectIds. Looking around for ideas, I also came across the restriction that _id field can't be changed. So this may require some research. One approach we've done in the past for really big changes is to copy the old model definition and call itEmailAddressOld
and then inEmailAddress
change the__mongometa__ name = 'email_address'
so that the data is stored in a new collection. Then the migration can copy from one to the other. Also, once you get something working, I'm curious how long it takes to handle a few million user records? I am thinking it might be necessary to also have on-the-fly migrations so that everything works for people using the site before the migration completes. If we do that, we'd still want the script to ensure all records get switched over to the new format. For on-the-fly migrations see http://merciless.sourceforge.net/tour.html#specifying-a-migration although that might not work with a 2-model approach.Lastly, and we may want to spin this off into a separate ticket, but giving a "Email address already claimed" message allows for "email enumeration" which we're trying to avoid (e.g. [#7543]). We should instead send a message to the given address and do something from there. I haven't thought through exactly what the process should be: email message says its already associated with username "foo", or allow new account to validate the address and remove it from old user, etc.
Related
Tickets:
#7524Tickets:
#75431) I have fixed the bugs & pushed changes related to forge to the same branch in that repo
2) before_save approach for EmailAddress doesn't work for us, since it is a) called only when you actually save it to the database b) although it is getting called during flush, the actual saved data is not right in the resulting saved object.(looks like that changes I do to data does not reflect on the model) c) In some cases we need to generate an object without saving to DB & it won't be canonical, thus I've just renamed upsert -> create
3)I have updated the migration script with raw mongo JS. The approach is the following:
Approach is looking good. In the migration .js file you should have
$ne
instead of$not
. Can you also split this into 3 files? Something like this so that each file can be run on its own cleanly:030-email-address-_id-to-email--before-upgrade.js
030-email-address-_id-to-email--after-upgrade.js
030-email-address-_id-to-email--cleanup.js
And then in the SF internal code,
M.EmailAddress.create
is creating too many records - a new copy each time you log in. Should just look up an existing record with the canonical form of the email address I think. Also need to ensure the email is marked as verified and primary.forge-classic:al/7527 & allura fork:al/7527