New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Bcrypt password hashing #1160
Conversation
For Apache CouchDB to accept this code, we will need to import the erlangpack/bcrypt repo and perform due diligence on the LICENSE file. At a glance, it looks OK - just saying that this won't hit I can't speak to the desirability or the technical efficacy of the patch; someone else will need to comment. I know there have been arguments on bcrypt vs. pbkdf2 in the past, but I can't remember where they went. What motivated this work? |
src/couch/src/couch_users_db.erl
Outdated
@@ -75,7 +76,7 @@ save_doc(#doc{body={Body}} = Doc) -> | |||
Body3 = proplists:delete(?PASSWORD, Body2), | |||
Doc#doc{body={Body3}}; | |||
{ClearPassword, "pbkdf2"} -> | |||
Iterations = list_to_integer(config:get("couch_httpd_auth", "iterations", "1000")), | |||
Iterations = list_to_integer(config:get("couch_httpd_auth", "iterations", "10000")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't change the default here without good reason; there are likely reasons it is set to 1000 not 10000. It is also an unrelated change to the proposed addition of bcrypt
, isn't it? This is the pbkdf2
section.
Any change to a config:get
block must be matched with parallel changes to rel/overlay/etc/default.ini
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. I simply noticed that the default value in the authenticate
function in couch_httpd_auth.erl is 10000 so I thought this was a misspelling.
Wasn't aware of rel/overlay/etc/default.ini
but I guess I should just roll back this change, should I?
src/couch/src/couch_passwords.erl
Outdated
++ Iterations). | ||
++ Iterations); | ||
hash_admin_password("bcrypt", ClearPassword) -> | ||
Iterations = list_to_integer(config:get("couch_httpd_auth", "iterations", "12")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't have different defaults for different algorithms. Either be consistent with the existing default value (which I believe is 10) or propose a change with justification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ho, I guess I should rename the parameter into log_rounds
as the real amount if iterations performed is actually 2^log_rounds
.
I'll change it.
src/couch/src/couch_users_db.erl
Outdated
@@ -84,6 +85,13 @@ save_doc(#doc{body={Body}} = Doc) -> | |||
Body3 = ?replace(Body2, ?SALT, Salt), | |||
Body4 = proplists:delete(?PASSWORD, Body3), | |||
Doc#doc{body={Body4}}; | |||
{ClearPassword, "bcrypt"} -> | |||
Iterations = list_to_integer(config:get("couch_httpd_auth", "iterations", "12")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before - inconsistent default vs. pbkdf2
's default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before, will rename it as log_rounds
to prevent misunderstanding.
Thanks @wohali for your review! I have to say this is the first time I contribute to a big opensource project, and the first time I work with Erlang! So If I understand well, I should at least do the following:
Once this is done, how should I proceed to work on a feature branch? I've followed the given instructions but maybe I made something wrong? I don't have a strong opinion about bcrypt vs. pbkdf2. I know both are great with there pros and cons. I happened to use Bcrypt so far and I have several dozens of thousands of user accounts who's passwords are stored in my MySQL database and as I want to migrate to CouchDB (because it's awesome!), the best for me is to have it support Bcrypt, so I can just import my user accounts without requiring any actions from them. |
Hi @pierrekilly , Oops, I wasn't clear in my comments, sorry about that. You should use the same value for iterations for You should not change the default in the same commit. I see the advice that recommends not using less than 10 for the iterations value online, so I understand your going with 12, but since this will affect both algorithms, we need to be sure this will not cause undue concern for users of If you change the default value you must update Someone else more focused on this section of the code will have to help this PR along further, I'm afraid. That may take some time. If it stalls out too long, you should subscribe to |
And because this is your first contribution - THANK YOU for contributing to CouchDB! We're always happy to have new collaborators on our project. :D |
src/couch/src/couch_httpd_auth.erl
Outdated
@@ -309,7 +309,12 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req, AuthModule) -> | |||
Secret = ?l2b(ensure_cookie_auth_secret()), | |||
UserSalt = couch_util:get_value(<<"salt">>, UserProps), | |||
CurrentTime = make_cookie_time(), | |||
Cookie = cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime), | |||
Cookie = case UserSalt =:= undefined of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest case UserSalt of undefined -> ... ; _ ->
.
+1 from me though I made one style comment. Before this merges though;
|
Quick expanding on this. We only include sources that we have a copy of, so we can ensure that we can make releases with all features in perpetuity. That means if/when we accept this PR, we’ll keep a copy of erlang-bcrypt on ASF git infrastructure and this GitHub mirror. This is something team is going to handle, so no additional requirement for you, @pierrekilly. |
@pierrekilly welcome & nice work on your first PR! Some background info which may be useful to help you understand what happens next, Your tidy changes require a NIF (C code) addition to the CouchDB distribution, so
The Apache Software Foundation, as policy, releases sources artefact that contains @dch is happy to do the IP clearance dance assuming we're OK on the NIF side of things. Can anybody look into that? the NIF is an R13B04 era style, does this need any changes? |
Thanks @dch, but this doesn’t require IP clearance, as we just keep a copy, we don’t intend to continue developing the dependency code and we don’t intend to slap our license on it. It just needs to satisfy category A as you point out. With the git mirror in place via @rnewson, this is good to go. |
We now have https://github.com/apache/couchdb-erlang-bcrypt |
I updated the dependency location and rebased master. |
Added LICENSE and NOTICE entries |
@pierrekilly nice work overall, and thanks again for the contribution. This is nearly ready to go, but it’d be great to get test coverage up a little bit. Namely, it’d be great to have a test that proves that:
|
@pierrekilly see https://github.com/apache/couchdb/blob/master/test/javascript/tests/users_db_security.js for getting started |
Just pushed more tests |
Great work here. I'm unable to comment on the code quality, but if @janl and @rnewson are happy, you've pleased the right people. As someone else has probably mentioned, this needs to be squashed before landing. Sorry to bring this up again... @janl and I discussed the whole Jan said he'll think about this and drop by in a day or two to comment. |
Very well! Just one precision about this: in case of PBKDF2, with As the number do not represent exactly the same thing, I preferred to keep them separated, but the decision is up to you guys :-) |
@pierrekilly good point on it being a different types of parameter. It's not just linear difference. Maybe call it |
definitely a separate parameter as they are not comparable. |
Ho, and I forgot to mention that |
I screwed up the branch here trying to resolve rebase conflicts, apologies. I’ll open a new one with a squashed commit. |
@pierrekilly @janl unfortunately bcrypt is terminally broken on Windows, as it is missing the BSD libc extensions (queue.h) and a useful pthreads implementation. Further, it seems to me that it makes no sense for our NIF to link to a function that is, itself, launching pthreads. Surely this will wreak havoc with the Erlang scheduler? /cc @davisp I am unfortunately going to have to remove this functionality to unblock the 2.2 release for now, as we can't hold up the release waiting for a rewrite. I have restored the Since both PRs have landed, I will open a new ticket for this issue to track work going forward. |
The new issue is at #1455 |
Overview
Add support for Bcrypt password hashing.
Testing recommendations
Add the following configuration entry:
couch_httpd_auth
password_scheme
bcrypt
Then you can add a user
and check that this user can authenticate and that his password is hashed using bcrypt:
Related Issues or Pull Requests
There will be a PR from the documentation changes from my fork: https://github.com/pierrekilly/couchdb-documentation/tree/bcrypt-hashing
Checklist
I have forked and updated the documentation but I have an issue with it: in the Hashing passwords section in the Security chapter I would like to add that starting from the next release bcrypt is supported but the next release doesn't exists yet, so the
make html
task fails. I still open this PR as I would like this code to be reviewed already.