Class: Cerbos::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/cerbos/client.rb

Overview

A client for interacting with the Cerbos policy decision point (PDP) server over gRPC.

An instance of the client may be shared between threads. However, due to an issue in the underlying grpc gem, it's not possible to use the client before and after process forks. If your application runs on a forking webserver (for example, Puma in clustered mode), then you'll need to ensure that you only create client instances in the child (worker) processes.

Instance Method Summary collapse

Constructor Details

#initialize(target, tls:, grpc_channel_args: {}, on_validation_error: :return, playground_instance: nil, timeout: nil) ⇒ Client

Create a client for interacting with the Cerbos PDP server over gRPC.

Examples:

Connect via TCP with no encryption

client = Cerbos::Client.new("localhost:3593", tls: false)

Connect via a Unix socket with no encryption

client = Cerbos::Client.new("unix:/var/run/cerbos.grpc.sock", tls: false)

Connect to the hosted demo PDP to experiment in the playground

client = Cerbos::Client.new("demo-pdp.cerbos.cloud", tls: Cerbos::TLS.new, playground_instance: "gE623b0180QlsG5a4QIN6UOZ6f3iSFW2")

Raise an error when input fails schema validation

client = Cerbos::Client.new("localhost:3593", tls: false, on_validation_error: :raise)

Invoke a callback when input fails schema validation

client = Cerbos::Client.new("localhost:3593", tls: false, on_validation_error: ->(validation_errors) { do_something_with validation_errors })

Parameters:

  • target (String)

    Cerbos PDP server address ("host", "host:port", or "unix:/path/to/socket").

  • tls (TLS, MutualTLS, false)

    gRPC connection encryption settings (false for plaintext).

  • grpc_channel_args (Hash{String, Symbol => String, Integer}) (defaults to: {})

    low-level settings for the gRPC channel (see available keys in the gRPC documentation).

  • on_validation_error (:return, :raise, #call) (defaults to: :return)

    action to take when input fails schema validation (:return to return the validation errors in the response, :raise to raise Error::ValidationFailed, or a callback to invoke).

  • playground_instance (String, nil) (defaults to: nil)

    identifier of the playground instance to use when prototyping against the hosted demo PDP.

  • timeout (Numeric, nil) (defaults to: nil)

    timeout for gRPC calls, in seconds (nil to never time out).



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/cerbos/client.rb', line 33

def initialize(target, tls:, grpc_channel_args: {}, on_validation_error: :return, playground_instance: nil, timeout: nil)
  @on_validation_error = on_validation_error

  handle_errors do
    credentials = tls ? tls.to_channel_credentials : :this_channel_is_insecure

    unless playground_instance.nil?
      credentials = credentials.compose(GRPC::Core::CallCredentials.new(->(*) { {"playground-instance" => playground_instance} }))
    end

    channel_args = grpc_channel_args.merge({
      "grpc.primary_user_agent" => [grpc_channel_args["grpc.primary_user_agent"], "cerbos-sdk-ruby/#{VERSION}"].compact.join(" ")
    })

    @cerbos_service = Protobuf::Cerbos::Svc::V1::CerbosService::Stub.new(
      target,
      credentials,
      channel_args: channel_args,
      timeout: timeout
    )
  end
end

Instance Method Details

#allow?(principal:, resource:, action:, aux_data: nil, request_id: SecureRandom.uuid) ⇒ Boolean

Check if a principal is allowed to perform an action on a resource.

Examples:

client.allow?(
  principal: {id: "[email protected]", roles: ["USER"]},
  resource: {kind: "document", id: "1"},
  action: "view"
) # => true

Parameters:

  • principal (Input::Principal, Hash)

    the principal to check.

  • resource (Input::Resource, Hash)

    the resource to check.

  • action (String)

    the action to check.

  • aux_data (Input::AuxData, Hash, nil) (defaults to: nil)

    auxiliary data.

  • request_id (String) (defaults to: SecureRandom.uuid)

    identifier for tracing the request.

Returns:

  • (Boolean)


72
73
74
75
76
77
78
79
80
# File 'lib/cerbos/client.rb', line 72

def allow?(principal:, resource:, action:, aux_data: nil, request_id: SecureRandom.uuid)
  check_resource(
    principal: principal,
    resource: resource,
    actions: [action],
    aux_data: aux_data,
    request_id: request_id
  ).allow?(action)
end

#check_resource(principal:, resource:, actions:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid) ⇒ Output::CheckResources::Result

Check a principal's permissions on a resource.

Examples:

decision = client.check_resource(
  principal: {id: "[email protected]", roles: ["USER"]},
  resource: {kind: "document", id: "1"},
  actions: ["view", "edit"]
)

decision.allow?("view") # => true

Parameters:

  • principal (Input::Principal, Hash)

    the principal to check.

  • resource (Input::Resource, Hash)

    the resource to check.

  • actions (Array<String>)

    the actions to check.

  • aux_data (Input::AuxData, Hash, nil) (defaults to: nil)

    auxiliary data.

  • include_metadata (Boolean) (defaults to: false)

    true to include additional metadata (Output::CheckResources::Result::Metadata) in the results.

  • request_id (String) (defaults to: SecureRandom.uuid)

    identifier for tracing the request.

Returns:



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/cerbos/client.rb', line 101

def check_resource(principal:, resource:, actions:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid)
  handle_errors do
    check_resources(
      principal: principal,
      resources: [Input::ResourceCheck.new(resource: resource, actions: actions)],
      aux_data: aux_data,
      include_metadata: ,
      request_id: request_id
    ).find_result(resource)
  end
end

#check_resources(principal:, resources:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid) ⇒ Output::CheckResources

Check a principal's permissions on a set of resources.

Examples:

decision = client.check_resources(
  principal: {id: "[email protected]", roles: ["USER"]},
  resources: [
    {
      resource: {kind: "document", id: "1"},
      actions: ["view", "edit"]
    },
    {
      resource: {kind: "image", id: "1"},
      actions: ["delete"]
    }
  ]
)

decision.allow?(resource: {kind: "document", id: "1"}, action: "view") # => true

Parameters:

  • principal (Input::Principal, Hash)

    the principal to check.

  • resources (Array<Input::ResourceCheck, Hash>)

    the resources and actions to check.

  • aux_data (Input::AuxData, Hash, nil) (defaults to: nil)

    auxiliary data.

  • include_metadata (Boolean) (defaults to: false)

    true to include additional metadata (Output::CheckResources::Result::Metadata) in the results.

  • request_id (String) (defaults to: SecureRandom.uuid)

    identifier for tracing the request.

Returns:



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/cerbos/client.rb', line 139

def check_resources(principal:, resources:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid)
  handle_errors do
    request = Protobuf::Cerbos::Request::V1::CheckResourcesRequest.new(
      principal: Input.coerce_required(principal, Input::Principal).to_protobuf,
      resources: Input.coerce_array(resources, Input::ResourceCheck).map(&:to_protobuf),
      aux_data: Input.coerce_optional(aux_data, Input::AuxData)&.to_protobuf,
      include_meta: ,
      request_id: request_id
    )

    response = perform_request(@cerbos_service, :check_resources, request)

    Output::CheckResources.from_protobuf(response).tap do |output|
      handle_validation_errors output
    end
  end
end

#plan_resources(principal:, resource:, action:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid) ⇒ Output::PlanResources

Produce a query plan that can be used to obtain a list of resources on which a principal is allowed to perform a particular action.

Examples:

plan = client.plan_resources(
  principal: {id: "[email protected]", roles: ["USER"]},
  resource: {kind: "document"},
  action: "view"
)

plan.conditional? # => true
plan.condition # => #<Cerbos::Output::PlanResources::Expression ...>

Parameters:

  • principal (Input::Principal, Hash)

    the principal for whom to plan.

  • resource (Input::ResourceQuery, Hash)

    partial details of the resources for which to plan.

  • action (String)

    the action for which to plan.

  • aux_data (Input::AuxData, Hash, nil) (defaults to: nil)

    auxiliary data.

  • include_metadata (Boolean) (defaults to: false)

    true to include additional metadata (Output::CheckResources::Result::Metadata) in the results.

  • request_id (String) (defaults to: SecureRandom.uuid)

    identifier for tracing the request.

Returns:



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/cerbos/client.rb', line 177

def plan_resources(principal:, resource:, action:, aux_data: nil, include_metadata: false, request_id: SecureRandom.uuid)
  handle_errors do
    request = Protobuf::Cerbos::Request::V1::PlanResourcesRequest.new(
      principal: Input.coerce_required(principal, Input::Principal).to_protobuf,
      resource: Input.coerce_required(resource, Input::ResourceQuery).to_protobuf,
      action: action,
      aux_data: Input.coerce_optional(aux_data, Input::AuxData)&.to_protobuf,
      include_meta: ,
      request_id: request_id
    )

    response = perform_request(@cerbos_service, :plan_resources, request)

    Output::PlanResources.from_protobuf(response)
  end
end

#server_infoOutput::ServerInfo

Retrieve information about the Cerbos PDP server.

Returns:



197
198
199
200
201
202
203
204
205
# File 'lib/cerbos/client.rb', line 197

def server_info
  handle_errors do
    request = Protobuf::Cerbos::Request::V1::ServerInfoRequest.new

    response = perform_request(@cerbos_service, :server_info, request)

    Output::ServerInfo.from_protobuf(response)
  end
end