一个表上的Postgres RLS不一致

时间:2017-10-25 15:47:43

标签: postgresql row-level-security

我在多租户模型中使用RLS。我启用的前几个表没有问题。然后我将RLS添加到新表中,然后我突然无法在该表中插入记录。

这是一个有效的表格:

CREATE TABLE wtr.adjustment (
  id uuid UNIQUE NOT NULL DEFAULT uuid_generate_v1(),
  created_at timestamp NOT NULL DEFAULT current_timestamp,
  updated_at timestamp NOT NULL DEFAULT current_timestamp,
  vendor_id uuid NOT NULL,
  reporting_period_id uuid NOT NULL,
  inventory_lot_id uuid NOT NULL,
  adjustment_date date NOT NULL,
  quantity_delta NUMERIC(50,2) NOT NULL,
  adjustment_type wtr.adjustment_type NOT NULL,
  comments text,
  CONSTRAINT pk_adjustment PRIMARY KEY (id)
);
--||--
GRANT select, insert, update, delete ON TABLE wtr.adjustment TO wtr_user;
--||--
ALTER TABLE wtr.adjustment ADD CONSTRAINT fk_adjustment_vendor FOREIGN KEY ( vendor_id ) REFERENCES wtr.vendor( id );
--||--
ALTER TABLE wtr.adjustment ADD CONSTRAINT fk_adjustment_reporting_period FOREIGN KEY ( reporting_period_id ) REFERENCES wtr.reporting_period( id );
--||--
ALTER TABLE wtr.adjustment ADD CONSTRAINT fk_adjustment_inventory_lot FOREIGN KEY ( inventory_lot_id ) REFERENCES wtr.inventory_lot( id );
--||--
ALTER TABLE wtr.adjustment ENABLE ROW LEVEL SECURITY;
--||--
CREATE POLICY select_adjustment ON wtr.adjustment FOR SELECT
  USING (vendor_id = wtr.current_vendor_id());
--||--
CREATE FUNCTION wtr.fn_timestamp_update_adjustment() RETURNS trigger AS $$
BEGIN
  NEW.updated_at = current_timestamp;
  RETURN NEW;
END; $$ LANGUAGE plpgsql;
--||--
CREATE TRIGGER tg_timestamp_update_adjustment
    BEFORE UPDATE ON wtr.adjustment
    FOR EACH ROW
    EXECUTE PROCEDURE wtr.fn_timestamp_update_adjustment();
--||--

以及有效的相关功能:

CREATE OR REPLACE FUNCTION wtr.build_adjustment(
  _reporting_period_id uuid,
  _inventory_lot_gov_id text,
  _strain_name text,
  _room_name text,
  _inventory_type_name text,
  _adjustment_date text,
  _quantity_delta NUMERIC(50,2),
  _adjustment_type wtr.adjustment_type,
  _comments text  
)
RETURNS wtr.adjustment as $$
DECLARE
  _vendor_id uuid;
  _inventory_lot wtr.inventory_lot;
  _adjustment wtr.adjustment;
  _inventory_type_id uuid;
BEGIN
  _vendor_id := wtr.current_vendor_id();

  _inventory_lot := wtr.find_or_build_existing_inventory_lot(
    _strain_name,
    _room_name,
    _inventory_lot_gov_id,
    _inventory_type_name
  );

  INSERT INTO wtr.adjustment(
    vendor_id,
    reporting_period_id,
    inventory_lot_id,
    adjustment_date,
    quantity_delta,
    adjustment_type,
    comments
  )
  SELECT
    _vendor_id,
    _reporting_period_id,
    _inventory_lot.id,
    _adjustment_date::DATE,
    _quantity_delta,
    _adjustment_type,
    _comments
  RETURNING *
  INTO _adjustment;

  RETURN _adjustment;
END;
$$ language plpgsql strict security definer;
--||--
GRANT execute ON FUNCTION wtr.build_adjustment(
  uuid,
  text,
  text,
  text,
  text,
  text,
  numeric,
  wtr.adjustment_type,
  text
) TO wtr_user;

这是失败的表:

CREATE TABLE wtr.received_inventory_transfer (
  id uuid UNIQUE NOT NULL DEFAULT uuid_generate_v1(),
  created_at timestamp NOT NULL DEFAULT current_timestamp,
  updated_at timestamp NOT NULL DEFAULT current_timestamp,
  vendor_id uuid NOT NULL,
  reporting_period_id uuid NOT NULL,
  inventory_lot_id uuid NOT NULL,
  transfer_date DATE NOT NULL,
  quantity_received NUMERIC(50,2) NOT NULL,
  CONSTRAINT pk_received_inventory_transfer PRIMARY KEY (id)
);
--||--
GRANT select, insert, update, delete ON TABLE wtr.received_inventory_transfer TO wtr_user;
--||--
ALTER TABLE wtr.received_inventory_transfer ADD CONSTRAINT fk_received_inventory_transfer_vendor FOREIGN KEY ( vendor_id ) REFERENCES wtr.vendor( id );
--||--
ALTER TABLE wtr.received_inventory_transfer ADD CONSTRAINT fk_received_inventory_transfer_reporting_period FOREIGN KEY ( reporting_period_id ) REFERENCES wtr.reporting_period( id );
--||--
ALTER TABLE wtr.received_inventory_transfer ADD CONSTRAINT fk_received_inventory_transfer_inventory_lot FOREIGN KEY ( inventory_lot_id ) REFERENCES wtr.inventory_lot( id );
--||--
ALTER TABLE wtr.received_inventory_transfer ENABLE ROW LEVEL SECURITY;
--||--
CREATE POLICY select_received_inventory_transfer ON wtr.received_inventory_transfer FOR SELECT USING (vendor_id = wtr.current_vendor_id());
--||--
CREATE FUNCTION wtr.fn_timestamp_update_received_inventory_transfer() RETURNS trigger AS $$
BEGIN
  NEW.updated_at = current_timestamp;
  RETURN NEW;
END; $$ LANGUAGE plpgsql;
--||--
CREATE TRIGGER tg_timestamp_update_received_inventory_transfer
    BEFORE UPDATE ON wtr.received_inventory_transfer
    FOR EACH ROW
    EXECUTE PROCEDURE wtr.fn_timestamp_update_received_inventory_transfer();
--||--

以及相关的失败功能:

CREATE OR REPLACE FUNCTION wtr.build_received_inventory_transfers(
  _reporting_period_id uuid,
  _transfer_date text
--  _received_inventory_transfers jsonb
)
RETURNS wtr.received_inventory_transfer as $$
DECLARE
  _vendor_id uuid;
  _inventory_lot wtr.inventory_lot;
  _received_inventory_transfer_info jsonb;
  _received_inventory_transfer wtr.received_inventory_transfer;
  _quantity numeric(50,2);
BEGIN
 _vendor_id := wtr.current_vendor_id();

-- this call is currently hard coded for debug purposes
   _inventory_lot := wtr.find_or_build_existing_inventory_lot(
     'tacos',
     'N/A',
     '1234123412341234',
     'Hash'
   );

-- again, this is hard-coded for debug purposes
RAISE EXCEPTION 'v: %, rp: %, il: %, td: %, q: %',
      _vendor_id,
      _reporting_period_id,
      _inventory_lot.id,
      _transfer_date::DATE,
      20
;

-- this is the call that fails
    INSERT INTO wtr.received_inventory_transfer(
      vendor_id,
      reporting_period_id,
      inventory_lot_id,
      transfer_date,
      quantity_received
    )
    SELECT
      _vendor_id,
      _reporting_period_id,
      _inventory_lot.id,
      _transfer_date::DATE,
      20
    RETURNING *
    INTO _received_inventory_transfer;

    RETURN _received_inventory_transfer;
  END;
$$ language plpgsql;
--||--
GRANT execute ON FUNCTION wtr.build_received_inventory_transfers(
  uuid,
  text
--  jsonb
) TO wtr_user;

current_vendor_id函数使用服务器传入的jwt令牌声明,即postgraphile。
在insert语句中,调用失败:

new row violates row-level security policy for table 
\"received_inventory_transfer\"",

此信息就是日志将显示给我的全部信息。

我认为我的真正问题是 - 如何进一步调试RLS策略?如果我只启用RLS,但没有创建选择策略,我会遇到同样的失败。

1 个答案:

答案 0 :(得分:0)

当然,接下来我想通了:

CREATE POLICY insert_received_inventory_transfer
  ON wtr.received_inventory_transfer
  FOR INSERT
  WITH CHECK (vendor_id = wtr.current_vendor_id());