Skip to content

Instantly share code, notes, and snippets.

@doobry
Created July 26, 2011 13:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save doobry/1106727 to your computer and use it in GitHub Desktop.
Save doobry/1106727 to your computer and use it in GitHub Desktop.
MySQL user auth with stored procedures
/*
Possible SHA1 values 2^160 = 1.46150164 × 10^48
RAND() returns a float from 0 to 1 ~= 10^16
CONCAT(RAND(), RAND(), RAND())
*/
SELECT LENGTH(UNHEX(SHA(RAND())));
DROP TABLE users;
CREATE TABLE users (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(32) NOT NULL UNIQUE,
salt BINARY(20) NOT NULL,
hash BINARY(20) NOT NULL
) ENGINE = INNODB;
DELIMITER //
DROP PROCEDURE user_auth //
CREATE PROCEDURE user_auth(IN name CHAR(32), IN pass CHAR(64))
BEGIN
SELECT users.id, users.name, users.salt INTO @id, @name, @salt FROM users WHERE users.name = name;
IF (SELECT COUNT(users.id) FROM users WHERE users.name = name AND users.hash = UNHEX(SHA1(CONCAT(HEX(@salt), pass)))) != 1 THEN
SET @message_text = CONCAT('Login incorrect for user \'', @name, '\'');
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @message_text;
ELSE
SELECT @id AS id, @name AS name;
END IF;
END//
DROP PROCEDURE user_create //
CREATE PROCEDURE user_create(IN name CHAR(32), IN pass CHAR(64))
BEGIN
IF (SELECT COUNT(users.id) FROM users WHERE users.name = name) > 0 THEN
SET @message_text = CONCAT('User \'', name, '\' already exists');
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @message_text;
ELSE
SET @salt = UNHEX(SHA1(CONCAT(RAND(), RAND(), RAND())));
INSERT INTO users(name, salt, hash) VALUES (name, @salt, UNHEX(SHA1(CONCAT(HEX(@salt), pass))));
CALL user_auth(name, pass);
END IF;
END//
DELIMITER ;
DROP USER 'doobrymedia'@'localhost';
CREATE USER 'doobrymedia'@'localhost' IDENTIFIED BY 'secret';
GRANT EXECUTE ON PROCEDURE doobrymedia.user_auth TO 'doobrymedia'@'localhost';
GRANT EXECUTE ON PROCEDURE doobrymedia.user_create TO 'doobrymedia'@'localhost';
CALL user_create('chris', SHA1('secret'));
CALL user_create('chris', SHA1('secret'));
CALL user_create('chris', SHA1('secret'));
CALL user_create('chris', SHA1('secret'));
CALL user_create('chris', SHA1('secret'));
CALL user_create('seonaid', SHA1('secret'));
CALL user_auth('chris', SHA1('secret'));
CALL user_auth('chris', SHA1('secret2'));
Copy link

ghost commented Mar 1, 2020

What are the benefits of create two separate procs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment