Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain::authorization_manager Class Reference

#include <authorization_manager.hpp>

Public Types

using permission_id_type = permission_object::id_type
 

Public Member Functions

 authorization_manager (controller &c, chainbase::database &d)
 
void add_indices ()
 
void initialize_database ()
 
void add_to_snapshot (const snapshot_writer_ptr &snapshot) const
 
void read_from_snapshot (const snapshot_reader_ptr &snapshot)
 
const permission_objectcreate_permission (account_name account, permission_name name, permission_id_type parent, const authority &auth, time_point initial_creation_time=time_point())
 
const permission_objectcreate_permission (account_name account, permission_name name, permission_id_type parent, authority &&auth, time_point initial_creation_time=time_point())
 
void modify_permission (const permission_object &permission, const authority &auth)
 
void remove_permission (const permission_object &permission)
 
void update_permission_usage (const permission_object &permission)
 
fc::time_point get_permission_last_used (const permission_object &permission) const
 
const permission_objectfind_permission (const permission_level &level) const
 
const permission_objectget_permission (const permission_level &level) const
 
std::optional< permission_namelookup_minimum_permission (account_name authorizer_account, scope_name code_account, action_name type) const
 Find the lowest authority level required for authorizer_account to authorize a message of the specified type.
 
void check_authorization (const vector< action > &actions, const flat_set< public_key_type > &provided_keys, const flat_set< permission_level > &provided_permissions=flat_set< permission_level >(), fc::microseconds provided_delay=fc::microseconds(0), const std::function< void()> &checktime=std::function< void()>(), bool allow_unused_keys=false, bool check_but_dont_fail=false, const flat_set< permission_level > &satisfied_authorizations=flat_set< permission_level >()) const
 Check authorizations of a vector of actions with provided keys, permission levels, and delay.
 
void check_authorization (account_name account, permission_name permission, const flat_set< public_key_type > &provided_keys, const flat_set< permission_level > &provided_permissions=flat_set< permission_level >(), fc::microseconds provided_delay=fc::microseconds(0), const std::function< void()> &checktime=std::function< void()>(), bool allow_unused_keys=false) const
 Check authorizations of a permission with provided keys, permission levels, and delay.
 
flat_set< public_key_typeget_required_keys (const transaction &trx, const flat_set< public_key_type > &candidate_keys, fc::microseconds provided_delay=fc::microseconds(0)) const
 

Static Public Attributes

static std::function< void()> _noop_checktime {&noop_checktime}
 

Detailed Description

Definition at line 19 of file authorization_manager.hpp.

Member Typedef Documentation

◆ permission_id_type

Constructor & Destructor Documentation

◆ authorization_manager()

sysio::chain::authorization_manager::authorization_manager ( controller & c,
chainbase::database & d )
explicit

Definition at line 24 of file authorization_manager.cpp.

25 :_control(c),_db(d){}

Member Function Documentation

◆ add_indices()

void sysio::chain::authorization_manager::add_indices ( )

Definition at line 27 of file authorization_manager.cpp.

27 {
28 authorization_index_set::add_indices(_db);
29 }
Here is the caller graph for this function:

◆ add_to_snapshot()

void sysio::chain::authorization_manager::add_to_snapshot ( const snapshot_writer_ptr & snapshot) const

Definition at line 96 of file authorization_manager.cpp.

96 {
97 authorization_index_set::walk_indices([this, &snapshot]( auto utils ){
98 using section_t = typename decltype(utils)::index_t::value_type;
99
100 // skip the permission_usage_index as its inlined with permission_index
101 if (std::is_same<section_t, permission_usage_object>::value) {
102 return;
103 }
104
105 snapshot->write_section<section_t>([this]( auto& section ){
106 decltype(utils)::walk(_db, [this, &section]( const auto &row ) {
107 section.add_row(row, _db);
108 });
109 });
110 });
111 }
Here is the caller graph for this function:

◆ check_authorization() [1/2]

void sysio::chain::authorization_manager::check_authorization ( account_name account,
permission_name permission,
const flat_set< public_key_type > & provided_keys,
const flat_set< permission_level > & provided_permissions = flat_set<permission_level>(),
fc::microseconds provided_delay = fc::microseconds(0),
const std::function< void()> & checktime = std::function<void()>(),
bool allow_unused_keys = false ) const
Parameters
account- the account owner of the permission
permission- the permission name to check for authorization
provided_keys- a set of public keys
provided_permissions- the set of permissions which can be considered satisfied (empty permission name acts as wildcard)
provided_delay- the delay considered to be satisfied for the authorization check
checktime- the function that can be called to track CPU usage and time during the process of checking authorization
allow_unused_keys- true if method does not require all keys to be used

Definition at line 575 of file authorization_manager.cpp.

583 {
584 const auto& checktime = ( static_cast<bool>(_checktime) ? _checktime : _noop_checktime );
585
586 auto delay_max_limit = fc::seconds( _control.get_global_properties().configuration.max_transaction_delay );
587
588 auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
589 _control.get_global_properties().configuration.max_authority_depth,
590 provided_keys,
591 provided_permissions,
592 ( provided_delay >= delay_max_limit ) ? fc::microseconds::maximum() : provided_delay,
593 checktime
594 );
595
596 SYS_ASSERT( checker.satisfied({account, permission}), unsatisfied_authorization,
597 "permission '${auth}' was not satisfied under a provided delay of ${provided_delay} ms, "
598 "provided permissions ${provided_permissions}, provided keys ${provided_keys}, "
599 "and a delay max limit of ${delay_max_limit_ms} ms",
600 ("auth", permission_level{account, permission})
601 ("provided_delay", provided_delay.count()/1000)
602 ("provided_permissions", provided_permissions)
603 ("provided_keys", provided_keys)
604 ("delay_max_limit_ms", delay_max_limit.count()/1000)
605 );
606
607 if( !allow_unused_keys ) {
608 SYS_ASSERT( checker.all_keys_used(), tx_irrelevant_sig,
609 "irrelevant keys provided: ${keys}",
610 ("keys", checker.unused_keys()) );
611 }
612 }
const mie::Vuint & p
Definition bn.cpp:27
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
constexpr int64_t count() const
Definition time.hpp:26
static constexpr microseconds maximum()
Definition time.hpp:14
static std::function< void()> _noop_checktime
const permission_object & get_permission(const permission_level &level) const
const global_property_object & get_global_properties() const
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
auto make_auth_checker(PermissionToAuthorityFunc &&pta, uint16_t recursion_depth_limit, const flat_set< public_key_type > &provided_keys, const flat_set< permission_level > &provided_permissions=flat_set< permission_level >(), fc::microseconds provided_delay=fc::microseconds(0), const std::function< void()> &_checktime=std::function< void()>())
authority_checker
uint32_t max_transaction_delay
the maximum number of seconds that can be imposed as a delay requirement by authorization checks
Here is the call graph for this function:

◆ check_authorization() [2/2]

void sysio::chain::authorization_manager::check_authorization ( const vector< action > & actions,
const flat_set< public_key_type > & provided_keys,
const flat_set< permission_level > & provided_permissions = flat_set<permission_level>(),
fc::microseconds provided_delay = fc::microseconds(0),
const std::function< void()> & checktime = std::function<void()>(),
bool allow_unused_keys = false,
bool check_but_dont_fail = false,
const flat_set< permission_level > & satisfied_authorizations = flat_set<permission_level>() ) const
Parameters
actions- the actions to check authorization across
provided_keys- the set of public keys which have authorized the transaction
provided_permissions- the set of permissions which have authorized the transaction (empty permission name acts as wildcard)
provided_delay- the delay satisfied by the transaction
checktime- the function that can be called to track CPU usage and time during the process of checking authorization
allow_unused_keys- true if method should not assert on unused keys

Definition at line 471 of file authorization_manager.cpp.

480 {
481 const auto& checktime = ( static_cast<bool>(_checktime) ? _checktime : _noop_checktime );
482
483 auto delay_max_limit = fc::seconds( _control.get_global_properties().configuration.max_transaction_delay );
484
485 auto effective_provided_delay = (provided_delay >= delay_max_limit) ? fc::microseconds::maximum() : provided_delay;
486
487 auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
488 _control.get_global_properties().configuration.max_authority_depth,
489 provided_keys,
490 provided_permissions,
491 effective_provided_delay,
492 checktime
493 );
494
495 map<permission_level, fc::microseconds> permissions_to_satisfy;
496
497 for( const auto& act : actions ) {
498 bool special_case = false;
499 fc::microseconds delay = effective_provided_delay;
500
501 if( act.account == config::system_account_name ) {
502 special_case = true;
503
504 if( act.name == updateauth::get_name() ) {
505 check_updateauth_authorization( act.data_as<updateauth>(), act.authorization );
506 } else if( act.name == deleteauth::get_name() ) {
507 check_deleteauth_authorization( act.data_as<deleteauth>(), act.authorization );
508 } else if( act.name == linkauth::get_name() ) {
509 check_linkauth_authorization( act.data_as<linkauth>(), act.authorization );
510 } else if( act.name == unlinkauth::get_name() ) {
511 check_unlinkauth_authorization( act.data_as<unlinkauth>(), act.authorization );
512 } else if( act.name == canceldelay::get_name() ) {
513 delay = std::max( delay, check_canceldelay_authorization(act.data_as<canceldelay>(), act.authorization) );
514 } else {
515 special_case = false;
516 }
517 }
518
519 for( const auto& declared_auth : act.authorization ) {
520
521 checktime();
522
523 if( !special_case ) {
524 auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.account, act.name);
525 if( min_permission_name ) { // since special cases were already handled, it should only be false if the permission is sysio.any
526 const auto& min_permission = get_permission({declared_auth.actor, *min_permission_name});
527 SYS_ASSERT( get_permission(declared_auth).satisfies( min_permission,
528 _db.get_index<permission_index>().indices() ),
529 irrelevant_auth_exception,
530 "action declares irrelevant authority '${auth}'; minimum authority is ${min}",
531 ("auth", declared_auth)("min", permission_level{min_permission.owner, min_permission.name}) );
532 }
533 }
534
535 if( satisfied_authorizations.find( declared_auth ) == satisfied_authorizations.end() ) {
536 auto res = permissions_to_satisfy.emplace( declared_auth, delay );
537 if( !res.second && res.first->second > delay) { // if the declared_auth was already in the map and with a higher delay
538 res.first->second = delay;
539 }
540 }
541 }
542 }
543
544 // Now verify that all the declared authorizations are satisfied:
545
546 // Although this can be made parallel (especially for input transactions) with the optimistic assumption that the
547 // CPU limit is not reached, because of the CPU limit the protocol must officially specify a sequential algorithm
548 // for checking the set of declared authorizations.
549 // The permission_levels are traversed in ascending order, which is:
550 // ascending order of the actor name with ties broken by ascending order of the permission name.
551 for( const auto& p : permissions_to_satisfy ) {
552 checktime(); // TODO: this should eventually move into authority_checker instead
553 SYS_ASSERT( checker.satisfied( p.first, p.second ) || check_but_dont_fail, unsatisfied_authorization,
554 "transaction declares authority '${auth}', "
555 "but does not have signatures for it under a provided delay of ${provided_delay} ms, "
556 "provided permissions ${provided_permissions}, provided keys ${provided_keys}, "
557 "and a delay max limit of ${delay_max_limit_ms} ms",
558 ("auth", p.first)
559 ("provided_delay", provided_delay.count()/1000)
560 ("provided_permissions", provided_permissions)
561 ("provided_keys", provided_keys)
562 ("delay_max_limit_ms", delay_max_limit.count()/1000)
563 );
564
565 }
566
567 if( !allow_unused_keys || check_but_dont_fail) {
568 SYS_ASSERT( checker.all_keys_used(), tx_irrelevant_sig,
569 "transaction bears irrelevant signatures from these keys: ${keys}",
570 ("keys", checker.unused_keys()) );
571 }
572 }
const generic_index< MultiIndexType > & get_index() const
std::optional< permission_name > lookup_minimum_permission(account_name authorizer_account, scope_name code_account, action_name type) const
Find the lowest authority level required for authorizer_account to authorize a message of the specifi...
void delay(websocketpp::connection_hdl, long duration)
chainbase::shared_multi_index_container< permission_object, indexed_by< ordered_unique< tag< by_id >, member< permission_object, permission_object::id_type, &permission_object::id > >, ordered_unique< tag< by_parent >, composite_key< permission_object, member< permission_object, permission_object::id_type, &permission_object::parent >, member< permission_object, permission_object::id_type, &permission_object::id > > >, ordered_unique< tag< by_owner >, composite_key< permission_object, member< permission_object, account_name, &permission_object::owner >, member< permission_object, permission_name, &permission_object::name > > >, ordered_unique< tag< by_name >, composite_key< permission_object, member< permission_object, permission_name, &permission_object::name >, member< permission_object, permission_object::id_type, &permission_object::id > > > > > permission_index
static action_name get_name()
static action_name get_name()
static action_name get_name()
static action_name get_name()
static action_name get_name()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_permission() [1/2]

const permission_object & sysio::chain::authorization_manager::create_permission ( account_name account,
permission_name name,
permission_id_type parent,
authority && auth,
time_point initial_creation_time = time_point() )

Definition at line 168 of file authorization_manager.cpp.

174 {
175 for(const key_weight& k: auth.keys)
176 SYS_ASSERT(k.key.which() < _db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
177 "Unactivated key type used when creating permission");
178
179 auto creation_time = initial_creation_time;
180 if( creation_time == time_point() ) {
181 creation_time = _control.pending_block_time();
182 }
183
184 const auto& perm_usage = _db.create<permission_usage_object>([&](auto& p) {
185 p.last_used = creation_time;
186 });
187
188 const auto& perm = _db.create<permission_object>([&](auto& p) {
189 p.usage_id = perm_usage.id;
190 p.parent = parent;
191 p.owner = account;
192 p.name = name;
193 p.last_updated = creation_time;
194 p.auth = std::move(auth);
195
196 if (auto dm_logger = _control.get_deep_mind_logger()) {
197 dm_logger->on_create_permission(p);
198 }
199 });
200 return perm;
201 }
std::string name
const ObjectType & create(Constructor &&con)
const ObjectType & get(CompatibleKey &&key) const
deep_mind_handler * get_deep_mind_logger() const
time_point pending_block_time() const
Here is the call graph for this function:

◆ create_permission() [2/2]

const permission_object & sysio::chain::authorization_manager::create_permission ( account_name account,
permission_name name,
permission_id_type parent,
const authority & auth,
time_point initial_creation_time = time_point() )

Definition at line 133 of file authorization_manager.cpp.

139 {
140 for(const key_weight& k: auth.keys)
141 SYS_ASSERT(k.key.which() < _db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
142 "Unactivated key type used when creating permission");
143
144 auto creation_time = initial_creation_time;
145 if( creation_time == time_point() ) {
146 creation_time = _control.pending_block_time();
147 }
148
149 const auto& perm_usage = _db.create<permission_usage_object>([&](auto& p) {
150 p.last_used = creation_time;
151 });
152
153 const auto& perm = _db.create<permission_object>([&](auto& p) {
154 p.usage_id = perm_usage.id;
155 p.parent = parent;
156 p.owner = account;
157 p.name = name;
158 p.last_updated = creation_time;
159 p.auth = auth;
160
161 if (auto dm_logger = _control.get_deep_mind_logger()) {
162 dm_logger->on_create_permission(p);
163 }
164 });
165 return perm;
166 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_permission()

const permission_object * sysio::chain::authorization_manager::find_permission ( const permission_level & level) const

Definition at line 251 of file authorization_manager.cpp.

252 { try {
253 SYS_ASSERT( !level.actor.empty() && !level.permission.empty(), invalid_permission, "Invalid permission" );
254 return _db.find<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
255 } SYS_RETHROW_EXCEPTIONS( chain::permission_query_exception, "Failed to retrieve permission: ${level}", ("level", level) ) }
#define SYS_RETHROW_EXCEPTIONS(exception_type, FORMAT,...)
const ObjectType * find(CompatibleKey &&key) const
uint32_t level
Type of a channel package.
Definition levels.hpp:37
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_permission()

const permission_object & sysio::chain::authorization_manager::get_permission ( const permission_level & level) const

Definition at line 257 of file authorization_manager.cpp.

258 { try {
259 SYS_ASSERT( !level.actor.empty() && !level.permission.empty(), invalid_permission, "Invalid permission" );
260 return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
261 } SYS_RETHROW_EXCEPTIONS( chain::permission_query_exception, "Failed to retrieve permission: ${level}", ("level", level) ) }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_permission_last_used()

fc::time_point sysio::chain::authorization_manager::get_permission_last_used ( const permission_object & permission) const

Definition at line 247 of file authorization_manager.cpp.

247 {
248 return _db.get<permission_usage_object, by_id>( permission.usage_id ).last_used;
249 }
Here is the call graph for this function:

◆ get_required_keys()

flat_set< public_key_type > sysio::chain::authorization_manager::get_required_keys ( const transaction & trx,
const flat_set< public_key_type > & candidate_keys,
fc::microseconds provided_delay = fc::microseconds(0) ) const

Definition at line 614 of file authorization_manager.cpp.

618 {
619 auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
620 _control.get_global_properties().configuration.max_authority_depth,
621 candidate_keys,
622 {},
623 provided_delay,
625 );
626
627 for (const auto& act : trx.actions ) {
628 for (const auto& declared_auth : act.authorization) {
629 SYS_ASSERT( checker.satisfied(declared_auth), unsatisfied_authorization,
630 "transaction declares authority '${auth}', but does not have signatures for it.",
631 ("auth", declared_auth) );
632 }
633 }
634
635 return checker.used_keys();
636 }
Here is the call graph for this function:

◆ initialize_database()

void sysio::chain::authorization_manager::initialize_database ( )

reserve perm 0 (used else where)

Definition at line 31 of file authorization_manager.cpp.

31 {
32 _db.create<permission_object>([](auto&){});
33 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ lookup_minimum_permission()

std::optional< permission_name > sysio::chain::authorization_manager::lookup_minimum_permission ( account_name authorizer_account,
scope_name code_account,
action_name type ) const
Parameters
authorizer_accountThe account authorizing the message
code_accountThe account which publishes the contract that handles the message
typeThe type of message

Definition at line 286 of file authorization_manager.cpp.

290 {
291 // Special case native actions cannot be linked to a minimum permission, so there is no need to check.
292 if( scope == config::system_account_name ) {
293 SYS_ASSERT( act_name != updateauth::get_name() &&
294 act_name != deleteauth::get_name() &&
295 act_name != linkauth::get_name() &&
296 act_name != unlinkauth::get_name() &&
297 act_name != canceldelay::get_name(),
298 unlinkable_min_permission_action,
299 "cannot call lookup_minimum_permission on native actions that are not allowed to be linked to minimum permissions" );
300 }
301
302 try {
303 std::optional<permission_name> linked_permission = lookup_linked_permission(authorizer_account, scope, act_name);
304 if( !linked_permission )
305 return config::active_name;
306
307 if( *linked_permission == config::sysio_any_name )
308 return std::optional<permission_name>();
309
310 return linked_permission;
311 } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
312 }
#define FC_CAPTURE_AND_RETHROW(...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ modify_permission()

void sysio::chain::authorization_manager::modify_permission ( const permission_object & permission,
const authority & auth )

Definition at line 203 of file authorization_manager.cpp.

203 {
204 for(const key_weight& k: auth.keys)
205 SYS_ASSERT(k.key.which() < _db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
206 "Unactivated key type used when modifying permission");
207
208 _db.modify( permission, [&](permission_object& po) {
209 auto dm_logger = _control.get_deep_mind_logger();
210
211 std::optional<permission_object> old_permission;
212 if (dm_logger) {
213 old_permission = po;
214 }
215
216 po.auth = auth;
217 po.last_updated = _control.pending_block_time();
218
219 if (auto dm_logger = _control.get_deep_mind_logger()) {
220 dm_logger->on_modify_permission(*old_permission, po);
221 }
222 });
223 }
void modify(const ObjectType &obj, Modifier &&m)
Here is the call graph for this function:

◆ read_from_snapshot()

void sysio::chain::authorization_manager::read_from_snapshot ( const snapshot_reader_ptr & snapshot)

Definition at line 113 of file authorization_manager.cpp.

113 {
114 authorization_index_set::walk_indices([this, &snapshot]( auto utils ){
115 using section_t = typename decltype(utils)::index_t::value_type;
116
117 // skip the permission_usage_index as its inlined with permission_index
118 if (std::is_same<section_t, permission_usage_object>::value) {
119 return;
120 }
121
122 snapshot->read_section<section_t>([this]( auto& section ) {
123 bool more = !section.empty();
124 while(more) {
125 decltype(utils)::create(_db, [this, &section, &more]( auto &row ) {
126 more = section.read_row(row, _db);
127 });
128 }
129 });
130 });
131 }
Here is the caller graph for this function:

◆ remove_permission()

void sysio::chain::authorization_manager::remove_permission ( const permission_object & permission)

Definition at line 225 of file authorization_manager.cpp.

225 {
226 const auto& index = _db.template get_index<permission_index, by_parent>();
227 auto range = index.equal_range(permission.id);
228 SYS_ASSERT( range.first == range.second, action_validate_exception,
229 "Cannot remove a permission which has children. Remove the children first.");
230
231 _db.get_mutable_index<permission_usage_index>().remove_object( permission.usage_id._id );
232
233 if (auto dm_logger = _control.get_deep_mind_logger()) {
234 dm_logger->on_remove_permission(permission);
235 }
236
237 _db.remove( permission );
238 }
void remove(const ObjectType &obj)
generic_index< MultiIndexType > & get_mutable_index()
constexpr std::size_t get_index()
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension Error decompressing transaction Transaction should have at least one required authority Expired Transaction Invalid Reference Block Duplicate deferred transaction The transaction can not be found Transaction is too big Invalid transaction extension Transaction includes disallowed Transaction exceeded transient resource limit action_validate_exception
chainbase::shared_multi_index_container< permission_usage_object, indexed_by< ordered_unique< tag< by_id >, member< permission_usage_object, permission_usage_object::id_type, &permission_usage_object::id > > > > permission_usage_index
Here is the call graph for this function:

◆ update_permission_usage()

void sysio::chain::authorization_manager::update_permission_usage ( const permission_object & permission)

Definition at line 240 of file authorization_manager.cpp.

240 {
241 const auto& puo = _db.get<permission_usage_object, by_id>( permission.usage_id );
242 _db.modify( puo, [&](permission_usage_object& p) {
243 p.last_used = _control.pending_block_time();
244 });
245 }
Here is the call graph for this function:

Member Data Documentation

◆ _noop_checktime

std::function< void()> sysio::chain::authorization_manager::_noop_checktime {&noop_checktime}
static

Definition at line 116 of file authorization_manager.hpp.


The documentation for this class was generated from the following files: