app: Implement username / password based API access #139
This commit is contained in:
parent
1dd7316d44
commit
d31e0108b4
5 changed files with 133 additions and 10 deletions
|
|
@ -16,6 +16,7 @@
|
|||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/app/api.hpp>
|
||||
#include <graphene/app/api_access.hpp>
|
||||
#include <graphene/app/application.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
|
|
@ -349,17 +350,47 @@ namespace graphene { namespace app {
|
|||
|
||||
bool login_api::login(const string& user, const string& password)
|
||||
{
|
||||
auto db_api = std::make_shared<database_api>(std::ref(*_app.chain_database()));
|
||||
auto net_broadcast_api = std::make_shared<network_broadcast_api>(std::ref(_app));
|
||||
auto hist_api = std::make_shared<history_api>(_app);
|
||||
auto net_node_api = std::make_shared<network_node_api>(std::ref(_app));
|
||||
_database_api = db_api;
|
||||
_network_broadcast_api = net_broadcast_api;
|
||||
_history_api = hist_api;
|
||||
_network_node_api = net_node_api;
|
||||
optional< api_access_info > acc = _app.get_api_access_info( user );
|
||||
if( !acc.valid() )
|
||||
return false;
|
||||
if( acc->password_hash_b64 != "*" )
|
||||
{
|
||||
std::string password_salt = fc::base64_decode( acc->password_salt_b64 );
|
||||
std::string acc_password_hash = fc::base64_decode( acc->password_hash_b64 );
|
||||
|
||||
fc::sha256 hash_obj = fc::sha256::hash( password + password_salt );
|
||||
if( hash_obj.data_size() != acc_password_hash.length() )
|
||||
return false;
|
||||
if( memcmp( hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size() ) != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
for( const std::string& api_name : acc->allowed_apis )
|
||||
enable_api( api_name );
|
||||
return true;
|
||||
}
|
||||
|
||||
void login_api::enable_api( const std::string& api_name )
|
||||
{
|
||||
if( api_name == "database_api" )
|
||||
{
|
||||
_database_api = std::make_shared< database_api >( std::ref( *_app.chain_database() ) );
|
||||
}
|
||||
else if( api_name == "network_broadcast_api" )
|
||||
{
|
||||
_network_broadcast_api = std::make_shared< network_broadcast_api >( std::ref( _app ) );
|
||||
}
|
||||
else if( api_name == "history_api" )
|
||||
{
|
||||
_history_api = std::make_shared< history_api >( _app );
|
||||
}
|
||||
else if( api_name == "network_node_api" )
|
||||
{
|
||||
_network_node_api = std::make_shared< network_node_api >( std::ref(_app) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
network_broadcast_api::network_broadcast_api(application& a):_app(a)
|
||||
{
|
||||
_applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); });
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@
|
|||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/app/api.hpp>
|
||||
#include <graphene/app/api_access.hpp>
|
||||
#include <graphene/app/application.hpp>
|
||||
#include <graphene/app/plugin.hpp>
|
||||
#include <graphene/app/api.hpp>
|
||||
|
||||
#include <graphene/net/core_messages.hpp>
|
||||
|
||||
|
|
@ -200,11 +201,41 @@ namespace detail {
|
|||
_chain_db->reindex(_data_dir / "blockchain", initial_state);
|
||||
}
|
||||
|
||||
if( _options->count("apiaccess") )
|
||||
_apiaccess = fc::json::from_file( _options->at("apiaccess").as<boost::filesystem::path>() )
|
||||
.as<api_access>();
|
||||
else
|
||||
{
|
||||
// TODO: Remove this generous default access policy
|
||||
// when the UI logs in properly
|
||||
_apiaccess = api_access();
|
||||
api_access_info wild_access;
|
||||
wild_access.password_hash_b64 = "*";
|
||||
wild_access.password_salt_b64 = "*";
|
||||
wild_access.allowed_apis.push_back( "database_api" );
|
||||
wild_access.allowed_apis.push_back( "network_broadcast_api" );
|
||||
wild_access.allowed_apis.push_back( "history_api" );
|
||||
_apiaccess.permission_map["*"] = wild_access;
|
||||
}
|
||||
|
||||
reset_p2p_node(_data_dir);
|
||||
reset_websocket_server();
|
||||
reset_websocket_tls_server();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
optional< api_access_info > get_api_access_info( const string& username )const
|
||||
{
|
||||
optional< api_access_info > result;
|
||||
auto it = _apiaccess.permission_map.find( username );
|
||||
if( it == _apiaccess.permission_map.end() )
|
||||
{
|
||||
it = _apiaccess.permission_map.find( "*" );
|
||||
if( it == _apiaccess.permission_map.end() )
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* If delegate has the item, the network has no need to fetch it.
|
||||
*/
|
||||
|
|
@ -410,6 +441,7 @@ namespace detail {
|
|||
|
||||
fc::path _data_dir;
|
||||
const bpo::variables_map* _options = nullptr;
|
||||
api_access _apiaccess;
|
||||
|
||||
std::shared_ptr<graphene::chain::database> _chain_db;
|
||||
std::shared_ptr<graphene::net::node> _p2p_network;
|
||||
|
|
@ -449,6 +481,7 @@ void application::set_program_options(boost::program_options::options_descriptio
|
|||
("server-pem,p", bpo::value<string>()->implicit_value("server.pem"), "The TLS certificate file for this server")
|
||||
("server-pem-password,P", bpo::value<string>()->implicit_value(""), "Password for this certificate")
|
||||
("genesis-json", bpo::value<boost::filesystem::path>(), "File to read Genesis State from")
|
||||
("apiaccess", bpo::value<boost::filesystem::path>(), "JSON file specifying API permissions")
|
||||
;
|
||||
command_line_options.add(configuration_file_options);
|
||||
command_line_options.add_options()
|
||||
|
|
@ -519,6 +552,11 @@ void application::set_block_production(bool producing_blocks)
|
|||
my->_is_block_producer = producing_blocks;
|
||||
}
|
||||
|
||||
optional< api_access_info > application::get_api_access_info( const string& username )const
|
||||
{
|
||||
return my->get_api_access_info( username );
|
||||
}
|
||||
|
||||
void graphene::app::application::add_plugin(const string& name, std::shared_ptr<graphene::app::abstract_plugin> p)
|
||||
{
|
||||
my->_plugins[name] = p;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/net/node.hpp>
|
||||
|
||||
|
||||
#include <graphene/market_history/market_history_plugin.hpp>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
|
|
@ -439,6 +438,9 @@ namespace graphene { namespace app {
|
|||
fc::api<network_node_api> network_node()const;
|
||||
|
||||
private:
|
||||
/// @brief Called to enable an API, not reflected.
|
||||
void enable_api( const string& api_name );
|
||||
|
||||
application& _app;
|
||||
optional< fc::api<database_api> > _database_api;
|
||||
optional< fc::api<network_broadcast_api> > _network_broadcast_api;
|
||||
|
|
|
|||
50
libraries/app/include/graphene/app/api_access.hpp
Normal file
50
libraries/app/include/graphene/app/api_access.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
|
||||
struct api_access_info
|
||||
{
|
||||
std::string password_hash_b64;
|
||||
std::string password_salt_b64;
|
||||
std::vector< std::string > allowed_apis;
|
||||
};
|
||||
|
||||
struct api_access
|
||||
{
|
||||
std::map< std::string, api_access_info > permission_map;
|
||||
};
|
||||
|
||||
} } // graphene::app
|
||||
|
||||
FC_REFLECT( graphene::app::api_access_info,
|
||||
(password_hash_b64)
|
||||
(password_salt_b64)
|
||||
(allowed_apis)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::app::api_access,
|
||||
(permission_map)
|
||||
)
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/app/api_access.hpp>
|
||||
#include <graphene/net/node.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ namespace graphene { namespace app {
|
|||
std::shared_ptr<chain::database> chain_database()const;
|
||||
|
||||
void set_block_production(bool producing_blocks);
|
||||
fc::optional< api_access_info > get_api_access_info( const string& username )const;
|
||||
|
||||
private:
|
||||
void add_plugin( const string& name, std::shared_ptr<abstract_plugin> p );
|
||||
|
|
|
|||
Loading…
Reference in a new issue