Làm cách nào tôi có thể giả mạo inet_client_addr () để kiểm tra đơn vị trong PostgreSQL?


7

Tôi có một thủ tục được lưu trữ đơn giản mà giá trị trả về phụ thuộc vào giá trị của inet_client_addr(). Làm cách nào tôi có thể ghi đè inet_client_addr()cho mục đích kiểm tra đơn vị khi kiểm tra quy trình được lưu trữ của mình?

Giải pháp duy nhất tôi nghĩ ra cho đến nay là tạo một hàm bao bọc xung quanh inet_client_addr():

CREATE FUNCTION my_inet_client_addr() RETURNS INET AS $$
    SELECT inet_client_addr();
$$ LANGUAGE sql;

Sau đó sử dụng nó trong chức năng của tôi:

CREATE local_connection() RETURNS BOOLEAN AS $$
    SELECT my_inet_client_addr() = '127.0.0.1';
$$ LANGUAGE sql;

Sau đó, trong bài kiểm tra đơn vị của tôi, tôi có thể xác định lại my_inet_client_addr():

BEGIN;
SELECT PLAN(2);
REPLACE FUNCTION my_inet_client_addr() RETURNS INET AS $$
    SELECT '127.0.0.1'::INET;
$$ LANGUAGE sql;

is(local_connection(),TRUE,'Connection from 127.0.0.1 is local');

REPLACE FUNCTION my_inet_client_addr() RETURNS INET AS $$
    SELECT '192.168.1.1'::INET;
$$ LANGUAGE sql;

is(local_connection(),FALSE,'Connection from 192.168.1.1. is not local');

ROLLBACK;

Có cách nào để thực hiện tương tự mà không có chức năng bao bọc my_inet_client_addr()?


tiêm phụ thuộc? your_procedure( inet_client_addr() )thay vì một cuộc gọi ngầm đến nó, không yêu cầu chế nhạo / ghi đè.
xenoterracide

@xenoterracide: Điều đó có thể hoạt động ... mặc dù nó chắc chắn sẽ gây phiền nhiễu, và sẽ chạm vào rất nhiều mã.
Flimzy

Tôi quên nếu trong pssql có hay không chữ ký là cực kỳ quan trọng, nhưng bạn cũng có thể thực hiện nó như một tham số tùy chọn vì vậy nếu nó được truyền vào thì nó sử dụng giá trị được truyền, nếu không sử dụng inet_client_addr()hoặc nếu chữ ký rất quan trọng thì có sig không có thông số phụ, giao cho người có. Dù bằng cách nào cũng bảo tồn API hiện có trong khi cho phép kiểm tra logic lõi.
xenoterracide

@xenoterracide: Chữ ký rất quan trọng, nhưng sau đó tôi có thể tạo một local_connection(INET)hàm (lấy tham số), lần lượt được bao bọc bởi một local_connection()hàm đi qua inet_client_addr(). Đây có lẽ là một phương pháp sạch hơn, sẽ bảo tồn API hiện có.
Flimzy

Câu trả lời:


7

inet_client_addr()là một chức năng thông tin hệ thống.
Nó nằm trong lược đồ pg_cataloggiống như các hàm dựng sẵn khác (ngoại trừ các mô đun bổ sung).

pg_catalogtự động là một phần của search_path. Mỗi tài liệu:

Ngoài publiccác lược đồ do người dùng tạo và, các cơ sở dữ liệu chứa một pg_cataloglược đồ chứa các bảng hệ thống và tất cả các kiểu dữ liệu, hàm và toán tử tích hợp. pg_catalogluôn luôn là một phần hiệu quả của con đường tìm kiếm. Nếu nó không được đặt tên rõ ràng trong đường dẫn thì nó sẽ được tìm kiếm ngầm trước khi tìm kiếm các lược đồ của đường dẫn. Điều này đảm bảo rằng các tên tích hợp sẽ luôn có thể tìm thấy. Tuy nhiên, bạn có thể đặt rõ ràng pg_catalogở cuối đường dẫn tìm kiếm của mình nếu bạn muốn có tên do người dùng xác định ghi đè tên tích hợp.

Nhấn mạnh đậm của tôi.
Vì vậy, chúng tôi tạo một lược đồ chuyên dụng và đặt nó trước pg_catalog trong search_path:

CREATE SCHEMA override;

CREATE OR REPLACE FUNCTION override.inet_client_addr()
  RETURNS inet AS
$func$
SELECT '127.0.0.1'::inet
$func$ language sql STABLE;
SET search_path = override, pg_catalog, public;

Sau đó, cuộc gọi của bạn sẽ tìm thấy chức năng ghi đè tùy chỉnh của bạn trước tiên:

SELECT inet_client_addr();

Câu đố SQL

Hãy chắc chắn rằng, người dùng không có đặc quyền không thể tạo các đối tượng trong overridelược đồ hoặc họ có thể chơi tất cả các loại thủ thuật trên bạn. Đó không phải là trường hợp mặc định. Mỗi tài liệu:

Không có đặc quyền nào được cấp cho PUBLIC theo mặc định trên các bảng, cột, lược đồ hoặc không gian bảng.

Nhấn mạnh đậm của tôi.

Cần thận trọng nếu cùng một người dùng được phép tạo các đối tượng trong cơ sở dữ liệu.
Mỗi tài liệu:

Lược đồ đầu tiên có tên trong đường dẫn tìm kiếm được gọi là lược đồ hiện tại. Ngoài việc là lược đồ đầu tiên được tìm kiếm, nó cũng là lược đồ trong đó các bảng mới sẽ được tạo nếu CREATE TABLElệnh không chỉ định tên lược đồ.

Luôn luôn chỉ định một tên lược đồ cho CREATEcác lệnh và không cho phép đối tượng tất cả theo mặc định để loại trừ các lỗi.


1
darnit, tôi đã thử nhưng sử dụng tùy chỉnh, công khai thay vì tùy chỉnh, pg_catalog, công khai và nó không hoạt động :) Câu trả lời tốt.
Neil McGuigan

@NeilMcGuigan: Bạn đã đi đúng hướng. +1 cho câu trả lời của bạn.
Erwin Brandstetter

Tôi cũng đã thử cách tiếp cận của Neil, ... xác định rõ ràng pg_catalogtrong đường dẫn tìm kiếm là phần còn thiếu. Cảm ơn!
Flimzy

3

Phải là postgresngười dùng hoặc khác Superusercho tôi. Chỉ cần create schemađặc quyền cho câu trả lời của Erwin.

bắt đầu kiểm tra:

alter function inet_client_addr() rename to _inet_client_addr;

create function inet_client_addr() returns inet language sql stable cost 1 as '
  select ''192.168.0.1''::inet;
';

select inet_client_addr();

kiểm tra kết thúc

alter function inet_client_addr() rename to inet_client_addr_mock;

alter function _inet_client_adds() rename to inet_client_addr;

--the regular function:
select inet_client_addr();

+1 Không phải là một giải pháp tồi, nhưng tôi đã chọn chấp nhận câu trả lời của Erin vì tôi nghĩ nó mạnh mẽ hơn một chút.
Flimzy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.