anchor.diff:      UserName = ?l2b(couch_util:get_value("name", Form, "")),
       Password = ?l2b(couch_util:get_value("password", Form, "")),
       ?LOG_DEBUG("Attempt Login: ~s",[UserName]),
  -    User = case couch_auth_cache:get_user_creds(UserName) of
  +    UserProps = case couch_auth_cache:get_user_creds(UserName) of
           nil -> [];
           Result -> Result
       end,
  -    UserSalt = couch_util:get_value(<<"salt">>, User, <<>>),
  -    case authenticate(Password, User) of
  +    case authenticate(Password, UserProps) of
           true ->
  +            UserProps2 = maybe_upgrade_password_hash(UserName, Password, UserProps),
               % setup the session cookie
               Secret = ?l2b(ensure_cookie_auth_secret()),
  +            UserSalt = couch_util:get_value(<<"salt">>, UserProps2),
               CurrentTime = make_cookie_time(),
               Cookie = cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime),
               % TODO document the "next" feature in Futon
  
positive.code: maybe_value(Key, Else, Fun) ->
      [{Key, Fun(Else)}].
  
  authenticate(Pass, UserProps) ->
      UserSalt = couch_util:get_value(<<"salt">>, UserProps, <<>>),
      {PasswordHash, ExpectedHash} =
  
negative.code:             send_json(Req#httpd{req_body=ReqBody}, Code, Headers,
                  {[
                      {ok, true},
                      {name, couch_util:get_value(<<"name">>, UserProps2, null)},
                      {roles, couch_util:get_value(<<"roles">>, UserProps2, [])}
                  ]});
          _Else ->
              % clear the session
  