-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Adding HTTP Basic Auth support? #145
Comments
Just adding a few pointers to the corresponding Rails port implementation: User auth call: Library functions: https://github.com/openstreetmap/openstreetmap-website/blob/master/lib/password_hash.rb#L18-L30 Create and upgrade doesn't seem necessary for cgimap. Test cases: |
I ported the library function #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <crypto++/base64.h>
#include <crypto++/config.h>
#include <crypto++/filters.h>
#include <crypto++/hex.h>
#include <crypto++/md5.h>
#include <crypto++/pwdbased.h>
#include <crypto++/secblock.h>
#include <crypto++/sha.h>
#include <sys/types.h>
#include <cassert>
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
using namespace CryptoPP;
class PasswordHash {
public:
static bool check(const std::string& pass_crypt, const std::string& pass_salt,
const std::string& candidate) {
std::string hashed_candidate;
if (pass_salt.empty()) {
const auto digest = md5_hash(candidate);
return (boost::iequals(digest, pass_crypt));
}
std::vector<std::string> params; // fields: algorithm, iterations, salt
boost::split(params, pass_salt, boost::is_any_of("!"));
if (params.size() != 3) {
const auto digest = md5_hash(pass_salt + candidate);
return (boost::iequals(digest, pass_crypt));
}
const auto algorithm = params[0];
const auto iterations = stoi(params[1]);
const auto salt = params[2];
const auto pass_crypt_decoded = base64decode(pass_crypt);
if (algorithm == "sha512")
hashed_candidate = PBKDF2_HMAC_SHA_string<SHA512>(
candidate, salt, iterations, pass_crypt_decoded.size());
else
throw std::runtime_error("Unknown hash algorithm");
return (hashed_candidate == pass_crypt); // both strings are base64 encoded
}
private:
template <class T>
static std::string PBKDF2_HMAC_SHA_string(const std::string& pass,
const std::string& salt,
const uint iterations,
const uint outputBytes) {
SecByteBlock result(outputBytes);
std::string base64Result;
PKCS5_PBKDF2_HMAC<T> pbkdf;
pbkdf.DeriveKey(result, result.size(), 0x00, (byte*)pass.data(),
pass.size(), (byte*)salt.data(), salt.size(), iterations);
ArraySource resultEncoder(
result, result.size(), true,
new Base64Encoder(new StringSink(base64Result), false));
return base64Result;
}
static std::string md5_hash(const std::string& s) {
Weak::MD5 hash;
std::string digest;
StringSource ss(
s, true,
new HashFilter(hash, new HexEncoder(new StringSink(digest), false)));
return digest;
}
static std::string base64decode(const std::string& s) {
std::string result;
StringSource ss(s, true, new Base64Decoder(new StringSink(result)));
return result;
}
};
int main(int argc, char* argv[]) {
std::cout << "Testing PasswordHash...";
// test_md5_without_salt
assert(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "",
"password") == true);
assert(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "", "wrong") ==
false);
// test_md5_with_salt
assert(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt",
"password") == true);
assert(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt",
"wrong") == false);
assert(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "wrong",
"password") == false);
// test_pbkdf2_1000_32_sha512
assert(PasswordHash::check(
"ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=",
"sha512!1000!HR4z+hAvKV2ra1gpbRybtoNzm/CNKe4cf7bPKwdUNrk=",
"password") == true);
assert(PasswordHash::check(
"ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=",
"sha512!1000!HR4z+hAvKV2ra1gpbRybtoNzm/CNKe4cf7bPKwdUNrk=",
"wrong") == false);
assert(PasswordHash::check(
"ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=",
"sha512!1000!HR4z+hAvKV2ra1gwrongtoNzm/CNKe4cf7bPKwdUNrk=",
"password") == false);
// test_pbkdf2_10000_32_sha512
assert(PasswordHash::check(
"3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=",
"sha512!10000!OUQLgtM7eD8huvanFT5/WtWaCwdOdrir8QOtFwxhO0A=",
"password") == true);
assert(PasswordHash::check(
"3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=",
"sha512!10000!OUQLgtM7eD8huvanFT5/WtWaCwdOdrir8QOtFwxhO0A=",
"wrong") == false);
assert(PasswordHash::check(
"3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=",
"sha512!10000!OUQLgtMwronguvanFT5/WtWaCwdOdrir8QOtFwxhO0A=",
"password") == false);
std::cout << "finished." << std::endl;
return 0;
}
|
Do we really want to be adding basic auth here? Ideally we'd be phasing it out, not extending it... |
Right, this is a bit guided by the following comment by @pnorman in #140 (comment):
As we don't want to funnel all those calls through the Rails port or cgimap-ruby, I see this as an intermediate step to be still somewhat downward compatible when GDPR restrictions or the changeset upload need an authenticated user. Fully agree though on a more mid term goal to phase out Basic auth. |
If we want to phase it out, we should do that in the rails port. But we don't have any plans for that yet, do we?
The basic auth without HTTPS point is now moot |
Basic auth support has been added in #152 now. |
Initially discussed here: #140 (comment)
As this topic could also be relevant in the context of GDPR, I'm creating a separate issue for it. After all, people might want to use e.g. the
/map
call along with Basic Auth to get full meta data.The text was updated successfully, but these errors were encountered: