@@ -2617,6 +2617,7 @@ class RGWUserPermHandler {
26172617 rgw::IAM::Environment env;
26182618 std::unique_ptr<rgw::auth::Identity> identity;
26192619 RGWAccessControlPolicy user_acl;
2620+ std::vector<rgw::IAM::Policy> user_policies;
26202621 };
26212622
26222623 std::shared_ptr<_info> info;
@@ -2644,7 +2645,7 @@ class RGWUserPermHandler {
26442645 }
26452646
26462647 auto result = rgw::auth::transform_old_authinfo (
2647- sync_env->dpp , null_yield, sync_env->driver , user.get ());
2648+ sync_env->dpp , null_yield, sync_env->driver , user.get (), &info-> user_policies );
26482649 if (!result) {
26492650 return result.error ();
26502651 }
@@ -2679,16 +2680,15 @@ class RGWUserPermHandler {
26792680 std::shared_ptr<_info> info;
26802681 RGWAccessControlPolicy bucket_acl;
26812682 std::optional<perm_state> ps;
2683+ boost::optional<rgw::IAM::Policy> bucket_policy;
26822684 public:
26832685 Bucket () {}
26842686
26852687 int init (RGWUserPermHandler *handler,
26862688 const RGWBucketInfo& bucket_info,
26872689 const map<string, bufferlist>& bucket_attrs);
26882690
2689- bool verify_bucket_permission (int perm);
2690- bool verify_object_permission (const map<string, bufferlist>& obj_attrs,
2691- int perm);
2691+ bool verify_bucket_permission (const rgw_obj_key& obj_key, const uint64_t op);
26922692 };
26932693
26942694 static int policy_from_attrs (CephContext *cct,
@@ -2728,6 +2728,14 @@ int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
27282728 return r;
27292729 }
27302730
2731+ // load bucket policy
2732+ try {
2733+ bucket_policy = get_iam_policy_from_attr (sync_env->cct , bucket_attrs, bucket_info.bucket .tenant );
2734+ } catch (const std::exception& e) {
2735+ ldpp_dout (sync_env->dpp , 0 ) << " ERROR: reading IAM Policy: " << e.what () << dendl;
2736+ return -EACCES;
2737+ }
2738+
27312739 ps.emplace (sync_env->cct ,
27322740 info->env ,
27332741 info->identity .get (),
@@ -2740,36 +2748,40 @@ int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
27402748 return 0 ;
27412749}
27422750
2743- bool RGWUserPermHandler::Bucket::verify_bucket_permission (int perm)
2744- {
2745- return verify_bucket_permission_no_policy (sync_env->dpp ,
2746- &(*ps),
2747- info->user_acl ,
2748- bucket_acl,
2749- perm);
2750- }
2751-
2752- bool RGWUserPermHandler::Bucket::verify_object_permission (const map<string, bufferlist>& obj_attrs,
2753- int perm)
2751+ bool RGWUserPermHandler::Bucket::verify_bucket_permission (const rgw_obj_key& obj_key, const uint64_t op)
27542752{
2755- RGWAccessControlPolicy obj_acl;
2756-
2757- int r = policy_from_attrs (sync_env->cct , obj_attrs, &obj_acl);
2758- if (r < 0 ) {
2759- return r;
2760- }
2761-
2762- return verify_bucket_permission_no_policy (sync_env->dpp ,
2763- &(*ps),
2764- bucket_acl,
2765- obj_acl,
2766- perm);
2753+ const rgw_obj obj (ps->bucket_info .bucket , obj_key);
2754+ const auto arn = rgw::ARN (obj);
2755+
2756+ if (ps->identity ->get_account ()) {
2757+ const bool account_root = (ps->identity ->get_identity_type () == TYPE_ROOT);
2758+ if (!ps->identity ->is_owner_of (bucket_acl.get_owner ().id )) {
2759+ ldpp_dout (sync_env->dpp , 4 ) << " cross-account request for bucket owner "
2760+ << bucket_acl.get_owner ().id << " != " << ps->identity ->get_aclowner ().id << dendl;
2761+ // cross-account requests evaluate the identity-based policies separately
2762+ // from the resource-based policies and require Allow from both
2763+ return ::verify_bucket_permission (sync_env->dpp , &(*ps), arn, account_root, {}, {}, {},
2764+ info->user_policies , {}, op)
2765+ && ::verify_bucket_permission (sync_env->dpp , &(*ps), arn, false , info->user_acl ,
2766+ bucket_acl, bucket_policy, {}, {}, op);
2767+ } else {
2768+ // don't consult acls for same-account access. require an Allow from
2769+ // either identity- or resource-based policy
2770+ return ::verify_bucket_permission (sync_env->dpp , &(*ps), arn, account_root, {}, {},
2771+ bucket_policy, info->user_policies ,
2772+ {}, op);
2773+ }
2774+ }
2775+ constexpr bool account_root = false ;
2776+ return ::verify_bucket_permission (sync_env->dpp , &(*ps), arn, account_root,
2777+ info->user_acl , bucket_acl,
2778+ bucket_policy, info->user_policies ,
2779+ {}, op);
27672780}
27682781
27692782class RGWFetchObjFilter_Sync : public RGWFetchObjFilter_Default {
27702783 rgw_bucket_sync_pipe sync_pipe;
27712784
2772- std::shared_ptr<RGWUserPermHandler::Bucket> bucket_perms;
27732785 std::optional<rgw_sync_pipe_dest_params> verify_dest_params;
27742786
27752787 std::optional<ceph::real_time> mtime;
@@ -2782,10 +2794,8 @@ class RGWFetchObjFilter_Sync : public RGWFetchObjFilter_Default {
27822794
27832795public:
27842796 RGWFetchObjFilter_Sync (rgw_bucket_sync_pipe& _sync_pipe,
2785- std::shared_ptr<RGWUserPermHandler::Bucket>& _bucket_perms,
27862797 std::optional<rgw_sync_pipe_dest_params>&& _verify_dest_params,
27872798 std::shared_ptr<bool >& _need_retry) : sync_pipe(_sync_pipe),
2788- bucket_perms (_bucket_perms),
27892799 verify_dest_params (std::move(_verify_dest_params)),
27902800 need_retry(_need_retry) {
27912801 *need_retry = false ;
@@ -2852,12 +2862,6 @@ int RGWFetchObjFilter_Sync::filter(CephContext *cct,
28522862 *poverride_owner = acl_translation_owner;
28532863 }
28542864 }
2855- if (params.mode == rgw_sync_pipe_params::MODE_USER) {
2856- if (!bucket_perms->verify_object_permission (obj_attrs, RGW_PERM_READ)) {
2857- ldout (cct, 0 ) << " ERROR: " << __func__ << " : permission check failed: user not allowed to fetch object" << dendl;
2858- return -EPERM;
2859- }
2860- }
28612865
28622866 if (!dest_placement_rule &&
28632867 params.dest .storage_class ) {
@@ -2900,7 +2904,6 @@ class RGWObjFetchCR : public RGWCoroutine {
29002904 rgw_sync_pipe_params::Mode param_mode;
29012905
29022906 std::optional<RGWUserPermHandler> user_perms;
2903- std::shared_ptr<RGWUserPermHandler::Bucket> source_bucket_perms;
29042907 RGWUserPermHandler::Bucket dest_bucket_perms;
29052908
29062909 std::optional<rgw_sync_pipe_dest_params> dest_params;
@@ -3016,33 +3019,22 @@ class RGWObjFetchCR : public RGWCoroutine {
30163019 return set_cr_error (retcode);
30173020 }
30183021
3019- if (!dest_bucket_perms.verify_bucket_permission (RGW_PERM_WRITE )) {
3022+ if (!dest_bucket_perms.verify_bucket_permission (dest_key. value_or (key), rgw::IAM::s3PutObject )) {
30203023 ldout (cct, 0 ) << " ERROR: " << __func__ << " : permission check failed: user not allowed to write into bucket (bucket=" << sync_pipe.info .dest_bucket .get_key () << " )" << dendl;
30213024 return -EPERM;
30223025 }
3023-
3024- /* init source bucket permission structure */
3025- source_bucket_perms = make_shared<RGWUserPermHandler::Bucket>();
3026- r = user_perms->init_bucket (sync_pipe.source_bucket_info ,
3027- sync_pipe.source_bucket_attrs ,
3028- source_bucket_perms.get ());
3029- if (r < 0 ) {
3030- ldout (cct, 20 ) << " ERROR: " << __func__ << " : failed to init bucket perms manager for uid=" << *param_user << " bucket=" << sync_pipe.source_bucket_info .bucket .get_key () << dendl;
3031- return set_cr_error (retcode);
3032- }
30333026 }
30343027
30353028 yield {
30363029 if (!need_retry) {
30373030 need_retry = make_shared<bool >();
30383031 }
30393032 auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe,
3040- source_bucket_perms,
30413033 std::move (dest_params),
30423034 need_retry);
30433035
30443036 call (new RGWFetchRemoteObjCR (sync_env->async_rados , sync_env->driver , sc->source_zone ,
3045- nullopt ,
3037+ param_user ,
30463038 sync_pipe.source_bucket_info .bucket ,
30473039 std::nullopt , sync_pipe.dest_bucket_info ,
30483040 key, dest_key, versioned_epoch,
@@ -4528,7 +4520,7 @@ class RGWBucketSyncSingleEntryCR : public RGWCoroutine {
45284520 }
45294521 tn->set_resource_name (SSTR (bucket_str_noinstance (bs.bucket ) << " /" << key));
45304522 }
4531- if (retcode == -ERR_PRECONDITION_FAILED) {
4523+ if (retcode == -ERR_PRECONDITION_FAILED || retcode == -EPERM ) {
45324524 pretty_print (sc->env , " Skipping object s3://{}/{} in sync from zone {}\n " ,
45334525 bs.bucket .name , key, zone_name);
45344526 set_status (" Skipping object sync: precondition failed (object contains newer change or policy doesn't allow sync)" );
0 commit comments