implementing user authentication with bcrypt in ChicagoBoss.
see http://shanelogsdon.com/erlang/implementing-user-authentication-with-bcrypt-in-chicagoboss
implementing user authentication with bcrypt in ChicagoBoss.
see http://shanelogsdon.com/erlang/implementing-user-authentication-with-bcrypt-in-chicagoboss
| {deps, [ | |
| {boss, ".*", {git, "git://github.com/evanmiller/ChicagoBoss.git", "HEAD"}}, | |
| {bcrypt, ".*", {git, "https://github.com/opscode/erlang-bcrypt.git", "HEAD"}} | |
| ]}. | |
| {plugin_dir, ["priv/rebar"]}. | |
| {plugins, [boss_plugin]}. | |
| {eunit_compile_opts, [{src_dirs, ["src/test"]}]}. | |
| {lib_dirs, ["./deps/elixir/lib"]}. |
| %% file: priv/init/module_10_bcrypt.erl | |
| -module(module_10_bcrypt). | |
| -export([init/0, stop/0]). | |
| %% We need to manually start the bcrypt application. | |
| %% @TODO: figure out how to get this to run via boss.config. | |
| init() -> | |
| %% Uncomment the following line if your CB app doesn't start crypto on its own | |
| % crypto:start(), | |
| bcrypt:start(). | |
| stop() -> | |
| bcrypt:stop(). | |
| %% Comment the above and uncomment the following lines if your CB app doesn't start crypto on its own | |
| % bcrypt:stop(), | |
| % crypto:stop(). |
| %% file: src/model/test_user.erl | |
| -module(test_user, [Id, Email, Username, Password]). | |
| -compile(export_all). | |
| -define(SETEC_ASTRONOMY, "Too many secrets"). | |
| session_identifier() -> | |
| mochihex:to_hex(erlang:md5(?SETEC_ASTRONOMY ++ Id)). | |
| check_password(PasswordAttempt) -> | |
| StoredPassword = erlang:binary_to_list(Password), | |
| user_lib:compare_password(PasswordAttempt, StoredPassword). | |
| set_login_cookies() -> | |
| [ mochiweb_cookies:cookie("user_id", erlang:md5(Id), [{path, "/"}]), | |
| mochiweb_cookies:cookie("session_id", session_identifier(), [{path, "/"}]) ]. |
| %% file: src/lib/user_lib.erl | |
| -module(user_lib). | |
| -compile(export_all). | |
| %% On success, returns {ok, Hash}. | |
| hash_password(Password)-> | |
| {ok, Salt} = bcrypt:gen_salt(), | |
| bcrypt:hashpw(Password, Salt). | |
| %% Tests for presence and validity of session. | |
| %% Forces login on failure. | |
| require_login(Req) -> | |
| case Req:cookie("user_id") of | |
| undefined -> {redirect, "/user/login"}; | |
| Id -> | |
| case boss_db:find(Id) of | |
| undefined -> {redirect, "/user/login"}; | |
| TestUser -> | |
| case TestUser:session_identifier() =:= Req:cookie("session_id") of | |
| false -> {redirect, "/user/login"}; | |
| true -> {ok, TestUser} | |
| end | |
| end | |
| end. | |
| compare_password(PasswordAttempt, Password) -> | |
| {ok, Password} =:= bcrypt:hashpw(PasswordAttempt, Password). |
| %% file: src/controller/test_user_controller.erl | |
| -module(test_user_controller, [Req]). | |
| -compile(export_all). | |
| login('GET', []) -> | |
| {ok, [{redirect, Req:header(referer)}]}; | |
| login('POST', []) -> | |
| Username = Req:post_param("username"), | |
| case boss_db:find(annie_user, [{username, Username}], [{limit, 1}]) of | |
| [TestUser] -> | |
| case TestUser:check_password(Req:post_param("password")) of | |
| true -> | |
| {redirect, proplists:get_value("redirect", | |
| Req:post_params(), "/"), TestUser:set_login_cookies()}; | |
| false -> | |
| {ok, [{error, "Password mismatch"}]} | |
| end; | |
| [] -> | |
| {ok, [{error, "User not found"}]} | |
| end. | |
| register('GET', []) -> | |
| {ok, []}; | |
| register('POST', []) -> | |
| Email = Req:post_param("email"), | |
| Username = Req:post_param("username"), | |
| {ok, Password} = user_lib:hash_password(Req:post_param("password")), | |
| TestUser = test_user:new(id, Email, Username, Password), | |
| Result = TestUser:save(), | |
| {ok, [Result]}. |
| %% file: src/controller/test_index_controller.erl | |
| -module(test_index_controller, [Req]). | |
| -compile(export_all). | |
| %% Forces login if valid session is not present. | |
| %% Called before all actions. | |
| before_(_) -> | |
| user_lib:require_login(Req). | |
| %% | |
| %% Index | |
| %% | |
| %% requires TestUser | |
| %% | |
| %% GET index/index | |
| %% | |
| index('GET', [], TestUser) -> | |
| {ok, [{test_user, TestUser}]}. |