Drizzled Public API Documentation

auth_test.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Rackspace
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <string>
00023 
00024 #include <drizzled/plugin/authentication.h>
00025 #include <drizzled/identifier.h>
00026 #include <drizzled/util/convert.h>
00027 #include <drizzled/algorithm/sha1.h>
00028 
00029 using namespace std;
00030 using namespace drizzled;
00031 
00032 namespace auth_test
00033 {
00034 
00035 /* This is the result of MYSQL_PASSWORD("scramble_password"). */
00036 static const char *scrambled_password= "2C5A870CEFF02BA3B0A927D7956B3FEB4D59CF21";
00037 
00038 class AuthTest: public plugin::Authentication
00039 {
00040 public:
00041   AuthTest(string name_arg):
00042     plugin::Authentication(name_arg)
00043   { }
00044 
00045   virtual bool authenticate(const identifier::User &sctx, const string &password)
00046   {
00047     /* The "root" user always succeeds for drizzletest to get in. */
00048     if (sctx.username() == "root" && password.empty())
00049       return true;
00050 
00051     /* Any password succeeds. */
00052     if (sctx.username() == "password_ok" && !password.empty())
00053       return true;
00054 
00055     /* No password succeeds. */
00056     if (sctx.username() == "no_password_ok" && password.empty())
00057       return true;
00058 
00059     /* Check if MySQL password scramble succeeds. */
00060     if (sctx.username() == "scramble_ok" &&
00061         sctx.getPasswordType() == identifier::User::MYSQL_HASH &&
00062         sctx.getPasswordContext().size() == SHA1_DIGEST_LENGTH &&
00063         password.size() == SHA1_DIGEST_LENGTH)
00064     {
00065       SHA1_CTX ctx;
00066       uint8_t scrambled_password_hash[SHA1_DIGEST_LENGTH];
00067       uint8_t temp_hash[SHA1_DIGEST_LENGTH];
00068       uint8_t scrambled_password_check[SHA1_DIGEST_LENGTH];
00069 
00070       /* Get the double-hashed password from the stored hex string. */
00071       drizzled_hex_to_string(reinterpret_cast<char*>(scrambled_password_hash),
00072                              scrambled_password, SHA1_DIGEST_LENGTH * 2);
00073 
00074       /* Hash the scramble that was sent to client with the stored password. */
00075       SHA1Init(&ctx);
00076       SHA1Update(&ctx, reinterpret_cast<const uint8_t*>(sctx.getPasswordContext().c_str()), SHA1_DIGEST_LENGTH);
00077       SHA1Update(&ctx, scrambled_password_hash, SHA1_DIGEST_LENGTH);
00078       SHA1Final(temp_hash, &ctx);
00079 
00080       /* Next, XOR the result with what the client sent to get the original
00081          single-hashed password. */
00082       for (int x= 0; x < SHA1_DIGEST_LENGTH; x++)
00083         temp_hash[x]= temp_hash[x] ^ password[x];
00084 
00085       /* Hash this result once more to get the double-hashed password again. */
00086       SHA1Init(&ctx);
00087       SHA1Update(&ctx, temp_hash, SHA1_DIGEST_LENGTH);
00088       SHA1Final(scrambled_password_check, &ctx);
00089 
00090       /* These should match for a successful auth. */
00091       return memcmp(scrambled_password_hash, scrambled_password_check, SHA1_DIGEST_LENGTH) == 0;
00092     }
00093 
00094     return false;
00095   }
00096 };
00097 
00098 AuthTest *auth_test= NULL;
00099 
00100 static int init(module::Context &context)
00101 {
00102   auth_test= new AuthTest("auth_test");
00103   context.add(auth_test);
00104   return 0;
00105 }
00106 
00107 } /* namespace auth_test */
00108 
00109 DRIZZLE_PLUGIN(auth_test::init, NULL, NULL);