Class: Conjur::API

Inherits:
Object
  • Object
show all
Includes:
Cast, Escape, LogSource
Defined in:
lib/conjur/base.rb,
lib/conjur/core-api.rb,
lib/conjur/api/audit.rb,
lib/conjur/api/authn.rb,
lib/conjur/api/hosts.rb,
lib/conjur/api/roles.rb,
lib/conjur/api/users.rb,
lib/conjur/layer-api.rb,
lib/conjur/api/groups.rb,
lib/conjur/api/layers.rb,
lib/conjur-api/version.rb,
lib/conjur/api/pubkeys.rb,
lib/conjur/api/secrets.rb,
lib/conjur/pubkeys-api.rb,
lib/conjur/api/deputies.rb,
lib/conjur/api/resources.rb,
lib/conjur/api/variables.rb

Overview

This class provides access to the Conjur services.

Constant Summary collapse

VERSION =
"4.16.0"

Instance Attribute Summary collapse

Audit Service collapse

Authentication Methods collapse

Directory: Hosts collapse

Authorization: Roles collapse

Directory: Users collapse

Directory: Groups collapse

Directory: Layers collapse

Public Keys Service collapse

Directory: Deputies collapse

Authorization: Resources collapse

Directory: Variables collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LogSource

#log

Methods included from Escape

#fully_escape, #path_escape, #query_escape

Constructor Details

#initialize(username, api_key, token) ⇒ API

Note:

You should use new_from_token or new_from_key instead of calling this method directly.

Create a new instance from a username and api key or a token.

This method requires that you pass either a username and api_key or a token Hash.

Parameters:

  • username (String)

    the username to authenticate as

  • api_key (String)

    the api key or password to use when authenticating

  • token (Hash)

    the token to use when making authenticated requuests.



156
157
158
159
160
161
162
# File 'lib/conjur/base.rb', line 156

def initialize username, api_key, token
  @username = username
  @api_key = api_key
  @token = token

  raise "Expecting ( username and api_key ) or token" unless ( username && api_key ) || token
end

Instance Attribute Details

#api_keyString (readonly)

The api key used to create this instance. This is only present when you created the api with new_from_key.#

Returns:

  • (String)

    the api key, or nil if this instance was created from a token.



168
169
170
# File 'lib/conjur/base.rb', line 168

def api_key
  @api_key
end

Class Method Details

.authenticate(username, password) ⇒ String

The Conjur authenticate operation exchanges Conjur credentials for a token. The token can then be used to authenticate further API calls.

You will generally not need to use this method, as the API manages tokens automatically for you.

Parameters:

  • username (String)

    The username or host id for which we want a token

  • password (String)

    The password or api key

Returns:

  • (String)

    A JSON formatted authentication token.



82
83
84
85
86
87
# File 'lib/conjur/api/authn.rb', line 82

def authenticate username, password
  if Conjur.log
    Conjur.log << "Authenticating #{username}\n"
  end
  JSON::parse(RestClient::Resource.new(Conjur::Authn::API.host)["users/#{fully_escape username}/authenticate"].post password, content_type: 'text/plain')
end

.login(username, password) ⇒ String

The Conjur login operation exchanges a username and a password for an api key. The api key is preferable for storage and use in code, as it can be rotated and has far greater entropy than a user memorizable password.

  • Note that this method works only for Users. While Hosts possess Conjur identities, they do not have passwords.
  • If you pass an api key to this method instead of a password, it will simply return the API key.
  • This method uses Basic Auth to send the credentials.

Examples:

bob_api_key = Conjur::API.('bob', 'bob_password')
bob_api_key == Conjur::API.('bob', bob_api_key)  # => true

Parameters:

  • username (String)

    The username or login for the Conjur User.

  • password (String)

    The password or api key to authenticate with.

Returns:

  • (String)

    the API key.

Raises:

  • (RestClient::Exception)

    when the request fails or the identity provided is invalid.



48
49
50
51
52
53
# File 'lib/conjur/api/authn.rb', line 48

def  username, password
  if Conjur.log
    Conjur.log << "Logging in #{username} via Basic authentication\n"
  end
  RestClient::Resource.new(Conjur::Authn::API.host, user: username, password: password)['users/login'].get
end

.login_cas(username, password, cas_api_url) ⇒ String

This method logs in via CAS. It is similar to the login method, the only difference being that you need a cas_api_url, provided by the administrator of your CAS service.

Parameters:

  • username (String)

    the Conjur username

  • password (String)

    the Conjur password

  • cas_api_url (String)

    the url of the CAS service

Returns:

  • (String)

    a CAS ticket

See Also:



65
66
67
68
69
70
71
72
# File 'lib/conjur/api/authn.rb', line 65

def  username, password, cas_api_url
  if Conjur.log
    Conjur.log << "Logging in #{username} via CAS authentication\n"
  end
  require 'cas_rest_client'
  client = CasRestClient.new(:username => username, :password => password, :uri => [ cas_api_url, 'v1', 'tickets' ].join('/'), :use_cookies => false)
  client.get("#{Conjur::Authn::API.host}/users/login").body
end

.new_from_key(username, api_key) ⇒ Conjur::API

Create a new Conjur::API instance from a username and a password or api key.

Examples:

Create an API with valid credentials

api = Conjur::API.new_from_key 'admin', '<admin password>'
api.current_role # => 'conjur:user:admin'
api.token['data'] # => 'admin'

Authentication is lazy

api = Conjur::API.new_from_key 'admin', 'wrongpassword'   # succeeds
api.user 'foo' # raises a 401 error

Parameters:

  • username (String)

    the username to use when making authenticated requests.

  • api_key (Sring)

    the api key or password for username

Returns:

  • (Conjur::API)

    an api that will authenticate with the given username and api key.



105
106
107
# File 'lib/conjur/base.rb', line 105

def new_from_key(username, api_key)
  self.new username, api_key, nil
end

.new_from_token(token) ⇒ Conjur::API

Create a new Conjur::API instance from a token issued by the Conjur authentication service

Generally, you will have a Conjur identitiy (username and api key), and create an Conjur::API instance for the identity using new_from_key. This method is useful when you are performing authorization checks given a token. For example, a Conjur gateway that requires you to prove that you can 'read' a resource named 'super-secret' might get the token from a request header, create an Conjur::API instance with this method, and use Resource#permitted? to decide whether to accept and forward the request.

Note that Conjur tokens are issued as JSON. This method expects to get the token as a parsed JSON Hash. When sending tokens as headers, you will normally use base64 encoded strings. Authorization headers used by Conjur have the form 'Token token="#{b64encode token.to_json}"', but this format is in no way required.

Examples:

A simple gatekeeper

RESOURCE_NAME = 'protected-service'

def handle_request request
  token_header = request.header 'X-Conjur-Token'
  token = JSON.parse Base64.b64decode(token_header)

  api = Conjur::API.new_from_token token
  raise Forbidden unless api.resource(RESOURCE_NAME).permitted? 'read'

  proxy_to_service request
end

Parameters:

  • token (Hash)

    the authentication token as parsed JSON to use when making authenticated requests

Returns:

  • (Conjur::API)

    an api that will authenticate with the token



139
140
141
# File 'lib/conjur/base.rb', line 139

def new_from_token(token)
  self.new nil, nil, token
end

.update_password(username, password, new_password)

This method returns an undefined value.

Change a user's password. To do this, you must have the user's current password. This does not change or rotate api keys. However, you can use the user's api key as the current password, if the user was not created with a password.

Parameters:

  • username (String)

    the name of the user whose password we want to change

  • password (String)

    the user's current password or api key

  • new_password (String)

    the new password for the user.



97
98
99
100
101
102
# File 'lib/conjur/api/authn.rb', line 97

def update_password username, password, new_password
  if Conjur.log
    Conjur.log << "Updating password for #{username}\n"
  end
  RestClient::Resource.new(Conjur::Authn::API.host, user: username, password: password)['users/password'].put new_password
end

Instance Method Details

#add_public_key(username, key) ⇒ Object

Add an SSH public key for username.

Key Format

This method will raise an exception if key is not of the format "<algorithm> <data> <name>" (that is, key.split(\s+)).length must be 3). The <name> field is used by the service to identify individual keys for a user.

Permissions

You must have permission to 'update' the pubkeys service resource. When the Conjur appliance is configured, it creates the pubkeys service resource with this identifier '<organizational account>:service:pubkeys-1.0/public-keys'.

Rather than granting permissions to this resource directly to user roles, we recommend that you add them to the 'key-managers' group, whose unqualified identifier is 'pubkeys-1.0/key-managers', which has permission to add public keys.

Hiding Existence

Because attackers could use this method to determine the existence of Conjur users, it will not raise an error if the user does not exist.

Examples:

add a user's public key

# Check that the user exists so that we can fail when he doesn't.  Otherwise, this method
# will silently fail.
raise "No such user!" unless api.user('bob').exists?

# Add a key from a file
key = File.read('/path/to/public/key.pub')
api.add_public_key('bob', key)

Parameters:

  • username (String)

    the name of the Conjur

  • key (String)

    an SSH formated public key

Returns:

  • void

Raises:

  • RestClient::BadRequest when the key is not in the correct format.



134
135
136
# File 'lib/conjur/api/pubkeys.rb', line 134

def add_public_key username, key
  public_keys_resource(username).post key
end

#audit(options = {}, &block) ⇒ Array<Hash>

Return up to 100 audit events visible to the current authorized role.

An audit event is visible to a role if that role or one of it's ancestors is in the event's :roles field, or the role has a privilege any of the event's :resources field.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :till (Time, nil)

    only show events before this time

  • :since (Time, nil)

    only show events after this time

  • :follow (Boolean)

    block the current thread and call block with Array of audit events as the occur.

Returns:

  • (Array<Hash>)

    the audit events

See Also:



42
43
44
# File 'lib/conjur/api/audit.rb', line 42

def audit options={}, &block
  audit_event_feed "", options, &block
end

#audit_resource(resource, options = {}, &block) ⇒ Array<Hash>

Return up to 100 audit events visible to the current role and related to the given resource.

See #audit for the conditions under which an event is visible to a role.

An event is said to be "related to" a role iff the role is a member of the event's :roles field.

Parameters:

  • resource (Conjur::Resource, String, #resourceid)

    the resource to audit (when a string is given, it must be of the form 'account:kind:id').

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :till (Time, nil)

    only show events before this time

  • :since (Time, nil)

    only show events after this time

  • :follow (Boolean)

    block the current thread and call block with Array of audit events as the occur.

Returns:

  • (Array<Hash>)

    the audit events



81
82
83
# File 'lib/conjur/api/audit.rb', line 81

def audit_resource resource, options={}, &block
  audit_event_feed "resources/#{CGI.escape cast(resource, :resourceid)}", options, &block
end

#audit_role(role, options = {}, &block) ⇒ Array<Hash>

Return up to 100 audit events visible to the current role and related to the given role.

See #audit for the conditions under which an event is visible to a role.

An event is said to be "related to" a role iff the role is a member of the event's :roles field.

Parameters:

  • role (Conjur::Role, String, #roleid)

    the role to audit (if a string is given, it must be of the form 'account:kind:id').

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :till (Time, nil)

    only show events before this time

  • :since (Time, nil)

    only show events after this time

  • :follow (Boolean)

    block the current thread and call block with Array of audit events as the occur.

Returns:

  • (Array<Hash>)

    the audit events



62
63
64
# File 'lib/conjur/api/audit.rb', line 62

def audit_role role, options={}, &block
  audit_event_feed "roles/#{CGI.escape cast(role, :roleid)}", options, &block
end

#create_deputy(options = {}) ⇒ Conjur::Deputy

Create a Conjur deputy.

Deputies are used internally by Conjur services that need to perform actions as a particular role. While the deputies API is stable, it isn't intended for use by end users.

Parameters:

  • options (Hash) (defaults to: {})

    options for deputy creation

Options Hash (options):

  • :id (String)

    the unqualified id for the new deputy. If not present, the deputy will be given a randomly generated id.

Returns:

Raises:

  • (RestClient::Conflict)

    if a deputy already exists with the given id.



40
41
42
# File 'lib/conjur/api/deputies.rb', line 40

def create_deputy options = {}
  standard_create Conjur::Core::API.host, :deputy, nil, options
end

#create_group(id, options = {}) ⇒ Conjur::Group

Create a new group with the given identifier.

Groups can be created with a gidnumber attribute, which is used when mapping LDAP/ActiveDirectory groups to Conjur groups, and when performing PAM authentication to assign a unix GID.

Examples:

group = api.create_group 'cats'
puts group.attributes
# Output
{"id"=>"cats",
  "userid"=>"admin",
  "ownerid"=>"conjur:user:admin",
  "gidnumber"=>nil,
  "roleid"=>"conjur:group:cats",
  "resource_identifier"=>"conjur:group:cats"}

Create a group with a GID number.

group = api.create_group 'dogs', gidnumber: 1337
puts group.attributes['gidnumber']
# Output
1337

Parameters:

  • id (String)

    the identifier for this group

  • options (Hash) (defaults to: {})

    options for group creation

Options Hash (options):

  • :gidnumber (FixNum)

    gidnumber to assign to this group (if not present, the group will not have a gidnumber, in contrast to Conjur User instances).

Returns:



69
70
71
# File 'lib/conjur/api/groups.rb', line 69

def create_group(id, options = {})
  standard_create Conjur::Core::API.host, :group, id, options
end

#create_host(options = nil) ⇒ Conjur::Host

Create a new host asset.

By default this method will create a host with a random id. However, you may create a host with a specific name by passing an :id option.

Permissions

  • Any Conjur role may perform this method without an :ownerid option. The new hosts owner will be the current role.
  • If you pass an `:ownerid option, you must be a member of the given role.

Examples:

# Create a host with a random id
anon = api.create_host
anon.id # => "wyzg17"

# Create a host with a given id
foo = api.create_host id: 'foo'
foo.id # => "foo"

# Trying to create a new host named foo fails
foo2 = api.create_host id: 'foo' # raises RestClient::Conflict

# Create a host owned by user 'alice' (assuming we're authenticated as
# a role of which alice is a member).
alice_host = api.create_host id: "host-for-alice", ownerid: 'conjur:user:ailce'
alice_host.ownerid # => "conjur:user:alice"

Parameters:

  • options (Hash, nil) (defaults to: nil)

    options for the new host

Options Hash (options):

  • :id (String)

    the id for the new host

  • :ownerid (String)

    set the new hosts owner to this role

Returns:

Raises:

  • RestClient::Conflict when id is given and a host with that id already exists.

  • RestClient::Forbidden when ownerid is given and the owner role does not exist, or you are not a member of the owner role.



80
81
82
# File 'lib/conjur/api/hosts.rb', line 80

def create_host options = nil
  standard_create Conjur::Core::API.host, :host, nil, options
end

#create_layer(id, options = {}) ⇒ Conjur::Layer

Create a new layer with the given id

Examples:

# create a new layer named 'webservers'
webservers = api.create_layer 'webservices'

# create layer is *not* idempotent
api.create_layer 'webservices' # raises RestClient::Conflict

# create a layer owned by user 'alice'
api.create_layer 'webservices', ownerid: 'alice'
api.owner # => 'conjur:user:alice'

Parameters:

  • id (String)

    an unqualified id for the layer.

Returns:



22
23
24
# File 'lib/conjur/api/layers.rb', line 22

def create_layer(id, options = {})
  standard_create Conjur::API.layer_asset_host, :layer, id, options
end

#create_resource(identifier, options = {}) ⇒ Conjur::Role

Create a Conjur Resource. Resources are entities on which roles have permissions. A resource might represent a secret, a web service route, or be part of a higher level construct such as a user or group.

If :acting_as is not present in options, you will be the owner of the new role. If it is present, your role must be a member of the given role (see Role#member_of?).

Examples:

Create an abstract resource to represent a web service route

# Notice that we can omit the account in the identifier
service_resource = api.create_resource 'web-service:list-gadgets'
service_resource.resource_id # => 'conjur:web-service:list-gadgets'

# In a gatekeeper for the web service, we can use the resource to control access
get '/gadgets' do
  # We'll assume that we've verified the Conjur authn token in the request, and stored the
  # corresponding identifier in `request_role_id`
  halt(403) unless api.resource('conjur:web-service:list-gadgets').permitted? 'read', request_role_id
  render_json find_gadgets
end

Create a role owned by another role

alice = api.role('user:alice')
api.current_role.member_of? alice # true, the operation will fail if this is false
res = api.create_resource 'example:owned', acting_as: 'user:alice'
res.owner # "conjur:user:alice"

Parameters:

  • identifier (String)

    an id of the form "<account>:<kind>:<id>" or "<kind>:<id>"

  • options (Hash) (defaults to: {})

    options for the request

Options Hash (options):

  • :acting_as (String, #role_id)

    the role-ish thing or role id that will own the new resource

Returns:



58
59
60
61
62
# File 'lib/conjur/api/resources.rb', line 58

def create_resource(identifier, options = {})
  resource(identifier).tap do |r|
    r.create(options)
  end
end

#create_role(role, options = {}) ⇒ Conjur::Role

Create a Role with the given id.

Permissions

  • All Conjur roles can create new roles.
  • The creator role (either the current role or the role given by the :acting_as option) is made a member of the new role. The new role is also made a member of itself.
  • If you give an :acting_as option, you must be a (transitive) member of the :acting_as role.
  • The new role is granted to the creator role with admin option: that is, the creator role is able to grant the created role to other roles.

Examples:

Basic role creation

# Current role is 'user:jon', assume the organizational account is 'conjur'
 api.current_role # => 'conjur:user:jon'

# Create a Conjur actor to control the permissions of a chron job (rebuild_indices)
role = api.create_role 'robot:rebuild_indices'
role.role_id # => "conjur:robot:rebuild_indices"
role.members.map{ |grant| grant.member.role_id } # => ['conjur:user:jon', 'conjur:robot:rebuild_indices']
api.role('user:jon').admin_of?(role) # => true

Parameters:

  • role (String)

    a qualified role identifier for the new role

  • options (Hash) (defaults to: {})

    options for the action

Options Hash (options):

  • :acting_as (String)

    the resource will effectively be created by this role

Returns:

Raises:

  • (RestClient::MethodNotAllowed)

    if the role already exists. Note that this differs from the RestClient::Conflict exception raised when trying to create existing high level (user, group, etc.) Conjur assets.



79
80
81
82
83
# File 'lib/conjur/api/roles.rb', line 79

def create_role(role, options = {})
  role(role).tap do |r|
    r.create(options)
  end
end

#create_user(login, options = {}) ⇒ Conjur::User

Create a Conjur User. Conjur users are identities for humans.

When you create a user for the first time, the returned object will have an api_key field. You can then use this to set a password for the user if you want to. Note that when the user is fetched later with the #user method, it will not have an api_key. Use it or lose it.

Permissions

Any authenticated role may call this method.

Examples:

Create a user 'alice' and set her password to 'frogger'

alice = api.create_user 'alice', password: 'frogger'

# Now we can login as 'alice'.
alice_api = Conjur::API.new_from_key 'alice', 'frogger'
alice_api.current_role # => 'conjur:user:alice'

Create a user and save her api_key for later use

alice = api.create_user 'alice' # note that we're not giving a password
save_api_key 'alice', alice.api_key

Parameters:

  • login (String)

    the login for the new user

  • options (Hash) (defaults to: {})

    options for user creation

Options Hash (options):

  • :acting_as (String)

    Qualified id of a role to perform the action as

  • :uidnumber (String, Integer)

    UID number to assign to the new user. If not given, one will be generated.

  • :password (String)

    when present, the user will be given a password in addition to a randomly generated api key.

Returns:

Raises:

  • (RestClient::Conflict)

    If the user already exists, or a user with the given uidnumber exists.



56
57
58
# File 'lib/conjur/api/users.rb', line 56

def create_user(, options = {})
  standard_create Conjur::Core::API.host, :user, nil, options.merge(login: )
end

#create_variable(mime_type, kind, options = {}) ⇒ Conjur::Variable

Create a Conjur Variable. See Variable for operations on Conjur variables.

Permissions

Any authenticated role may call this method

Examples:

Create a variable to store a database connection string

db_uri = "mysql://username:[email protected]/mydb"
var = api.create_variable 'text/plain', 'mysql-connection-string', id: 'production/mysql/uri'
var.add_value db_uri

# Alternatively, we could have done this:
var = api.create_variable 'text/plain', 'mysql-connection-string',
      id: 'production/mysql/uri',
      value: db_uri

Create a variable with a unique random id

var = api.create_variable 'text/plain', 'secret'
var.id # => 'kngeqg'

Parameters:

  • mime_type (String)

    MIME type for the variable value, used to set the "Content-Type"header when serving the variable's value. Must be non-empty.

  • kind (String)

    user defined kind for the variable. This is useful as a simple way to document the variable's purpose. Must be non-empty

  • options (Hash) (defaults to: {})

    options for the new variable

Options Hash (options):

  • :id (String)

    specify an id for the new variable. Must be non-empty.

  • :value (String)

    specify an initial value for the variable

Returns:

Raises:

  • (RestClient::Conflict)

    if you give an :id option and the variable already exists

  • (RestClient::UnprocessableEntity)

    if mime_type, kind, or options[:id] is the empty string.



57
58
59
# File 'lib/conjur/api/variables.rb', line 57

def create_variable(mime_type, kind, options = {})
  standard_create Conjur::Core::API.host, :variable, nil, options.merge(mime_type: mime_type, kind: kind)
end

#credentialsHash

Credentials that can be merged with options to be passed to RestClient::Resource HTTP request methods. These include a username and an Authorization header containing the authentication token.

Returns:

  • (Hash)

    the options.

Raises:

  • (RestClient::Unauthorized)

    if fetching the token fails.

See Also:

  • Conjur::API.{{#token}


210
211
212
# File 'lib/conjur/base.rb', line 210

def credentials
  { headers: { authorization: "Token token=\"#{Base64.strict_encode64 token.to_json}\"" }, username: username }
end

#current_roleConjur::Role

Return a Role object representing the role (typically a user or host) that this api is authenticated as. This is derived either from the login argument to new_from_key or from the contents of the token given to new_from_token.

Examples:

Current role for a user

api = Conjur::API.new_from_key 'jon', 'somepassword'
api.current_role.roleid # => 'conjur:user:jon'

Current role for a host

host = api.create_host id: 'exapmle-host'

# Host and User have an `api` method that returns an api with their credentials.  Note
# that this only works with a newly created host or user, which has an `api_key` attribute.
host.api.current_role.roleid # => 'conjur:host:example-host'

Returns:

  • (Conjur::Role)

    the authenticated role for this API instance



130
131
132
# File 'lib/conjur/api/roles.rb', line 130

def current_role
  role_from_username username
end

#delete_public_key(username, keyname)

This method returns an undefined value.

Delete a specific public key for a user.

Permissions

You must have permission to 'update' the pubkeys service resource. When the Conjur appliance is configured, it creates the pubkeys service resource with this identifier '<organizational account>:service:pubkeys-1.0/public-keys'.

Rather than granting permissions to this resource directly to user roles, we recommend that you add them to the 'key-managers' group, whose unqualified identifier is 'pubkeys-1.0/key-managers', which has permission to add public keys.

Hiding Existence

Because attackers could use this method to determine the existence of Conjur users, it will not raise an error if the user does not exist.

Examples:

Delete all public keys for 'bob'


api.public_key_names('bob').count # => 6
api.public_key_names('bob').each do |keyname|
  api.delete_public_key 'bob', keyname
end
api.public_key_names('bob').count # => 0

Parameters:

  • username (String)

    the Conjur username/login

  • keyname (String)

    the individual key to delete.



166
167
168
# File 'lib/conjur/api/pubkeys.rb', line 166

def delete_public_key username, keyname
  public_keys_resource(username, keyname).delete
end

#deputy(id) ⇒ Conjur::Deputy

Find a Conjur deputy by id. Deputies are used internally by Conjur services that need to perform actions as a particular role. While the deputies API is stable, it isn't intended for use by end users.

Parameters:

  • id (String)

    the deputy's unqualified id

Returns:



53
54
55
# File 'lib/conjur/api/deputies.rb', line 53

def deputy id
  standard_show Conjur::Core::API.host, :deputy, id
end

#find_groups(options) ⇒ Array<String>

Find groups by GID. Note that gidnumbers are not unique for groups.

Examples:

dogs = api.create_group 'dogs', gidnumber: 42
cats = api.create_group 'cats', gidnumber: 42
api.find_groups gidnumber: 42
# => ['cats', 'dogs']
groups = api.find_groups(gidnumber: 42).map{|id| api.group(id)}
groups.map(&:class) # => [Conjur::Group, Conjur::Group]

Parameters:

  • options (Hash)

    search criteria

Options Hash (options):

  • :gidnumber (Integer)

    GID number

Returns:

  • (Array<String>)

    group names matching the criteria



106
107
108
# File 'lib/conjur/api/groups.rb', line 106

def find_groups options
  JSON.parse(RestClient::Resource.new(Conjur::Core::API.host, credentials)["groups/search?#{options.to_query}"].get)
end

#group(id) ⇒ Conjur::Group

Fetch a group with the given id. Note that the id is unqualified -- it must not contain account or id parts. For example,

Examples:

group = api.create_group 'fish'
right = api.group 'fish'
wrong = api.group 'conjur:group:fish'
right.exists? # => true
wrong.exists? # => false

Parameters:

  • id (String)

    the identifier of the group

Returns:



87
88
89
# File 'lib/conjur/api/groups.rb', line 87

def group id
  standard_show Conjur::Core::API.host, :group, id
end

#groups(options = {}) ⇒ Array<Conjur::Group>

List all Conjur groups visible to the current role. This method does not support advanced query options. If you want those, use #resources with the :kind option set to 'group'.

Examples:

api.groups.count # => 163 (yikes!)

Parameters:

  • options (Hash) (defaults to: {})

    included for compatibility. Do not use this parameter!

Returns:



37
38
39
# File 'lib/conjur/api/groups.rb', line 37

def groups(options={})
  standard_list Conjur::Core::API.host, :group, options
end

#host(id) ⇒ Conjur::Host

Get a host by its unqualified id.

Like other Conjur methods, this will return a Host whether or not the record is found, and you must use the Exists#exists? method to check this.

Examples:

api.create_host id: 'foo'
foo = api.host "foo" # => returns a Conjur::Host
puts foo.resourceid # => "conjur:host:foo"
puts foo.id # => "foo"
mistake = api.host "doesnotexist" # => Also returns a Conjur::Host
foo.exists? # => true
mistake.exists? # => false

Parameters:

  • id (String)

    the unqualified id of the host

Returns:

  • (Conjur::Host)

    an object representing the host, which may or may not exist.



181
182
183
# File 'lib/conjur/base.rb', line 181

def host
  self.class.host
end

#layer(id) ⇒ Conjur::Layer

Get a layer by its unqualified id.

Like other Conjur methods, this will return a Layer whether or not the record is found, and you must use the Exists#exists? method to check this.

Examples:

api.create_layer id: 'foo'
foo = api.layer "foo" # => returns a Conjur::Layer
puts foo.resourceid # => "conjur:layer:foo"
puts foo.id # => "foo"
mistake = api.layer "doesnotexist" # => Also returns a Conjur::Layer
foo.exists? # => true
mistake.exists? # => false

Parameters:

  • id (String)

    the unqualified id of the layer

Returns:

  • (Conjur::Layer)

    an object representing the layer, which may or may not exist.



56
57
58
# File 'lib/conjur/api/layers.rb', line 56

def layer id
  standard_show Conjur::API.layer_asset_host, :layer, id
end

#layers(options = {}) ⇒ Array<Conjur::Layer>

Get all layers visible to the current role.

The options parameter is only included for backwards compatibility and has no effect. You should call this method without arguments.

Parameters:

  • options (Hash) (defaults to: {})

    deprecated, unused

Returns:

  • (Array<Conjur::Layer>)

    all layers visible to the current role



34
35
36
# File 'lib/conjur/api/layers.rb', line 34

def layers options={}
  standard_list Conjur::API.layer_asset_host, :layer, options
end

#public_key(username, keyname) ⇒ String

Fetch a specific key by name. The key name is the last token in the public key itself, typically formatted as '<login>@<hostname>'.

Permissions

You do not need any special permissions to call this method, since public keys are, well, public.

Examples:

Get bob's key for 'bob@somehost'

key = begin
  api.public_key 'bob', 'bob@somehost'
rescue RestClient::ResourceNotFound
  puts "Key or user not found!"
  # Deal with it
end

Parameters:

  • username (String)

    A Conjur username

  • keyname (String)

    The name or identifier of the key

Returns:

  • (String)

    the public key

Raises:

  • (RestClient::ResourceNotFound)

    if the user or key does not exist.



69
70
71
# File 'lib/conjur/api/pubkeys.rb', line 69

def public_key username, keyname
  public_keys_resource(username, keyname).get
end

#public_key_names(username) ⇒ Array<String>

List the public key names for the given user.

If the given user does not exist, an empty Array will be returned. This is to prevent attackers from determining whether a user exists.

Permissions

You do not need any special permissions to call this method, since public keys are, well, public.

Examples:

List the names of public keys for 'otto'

api.public_key_names('otto').each{|n| puts n}
# otto@somehost
# admin@someotherhost

A non existent user has no public keys

user = api.user('doesnotexist')
user.exists? # => false
user.public_key_names # => []

Parameters:

  • username (String)

    the Conjur username

Returns:

  • (Array<String>)

    the names of the user's public keys



94
95
96
# File 'lib/conjur/api/pubkeys.rb', line 94

def public_key_names username
  public_keys(username).lines.map{|s| s.split(' ')[-1]}
end

#public_keys(username) ⇒ String

Fetch all public keys for the user. This method returns a newline delimited String for compatibility with the authorized_keys SSH format.

If the given user does not exist, an empty String will be returned. This is to prevent attackers from determining whether a user exists.

Permissions

You do not need any special permissions to call this method, since public keys are, well, public.

Examples:

puts api.public_keys('jon')
# ssh-rsa [big long string] jon@albert
# ssh-rsa [big long string] jon@conjurops

Parameters:

  • username (String)

    the unqualified Conjur username

Returns:

  • (String)

    newline delimited public keys



45
46
47
# File 'lib/conjur/api/pubkeys.rb', line 45

def public_keys username
  public_keys_resource(username).get
end

#resource(identifier) ⇒ Conjur::Resource

Find a resource by it's id. The id given to this method must be qualified by a kind, but the account is optional.

Permissions

The resource must be visible to the current role. This is the case if the current role is the owner of the resource, or has any privilege on it.

Examples:

Find or create a resource

def find_or_create_resource resource_id
   resource = api.resource resource_id
   unless resource.exists?
     resource = api.create_resource resource_id
   end
   resource
 end

 # ...
 example_resource = find_or_create_resource 'example:find-or-create'
 example_resource.exists? # always true

Parameters:

  • identifier (String)

    a qualified resource identifier, optionally including an account

Returns:



87
88
89
# File 'lib/conjur/api/resources.rb', line 87

def resource identifier
  Resource.new(Conjur::Authz::API.host, credentials)[self.class.parse_resource_id(identifier).join('/')]
end

#resources(opts = {}) ⇒ Array<Conjur::Resource>

Find all resources visible to the current role that match the given search criteria.

Conjur supports full text search over the identifiers and annotation values of resources. For example, if opts[:search] is "pubkeys", any resource with an id containing "pubkeys" or an annotation whose value contains "pubkeys" will match.

Notes

  • Annotation keys are not indexed for full text search.
  • Conjur indexes the content of ids and annotation values by word.
  • Only resources visible to the current role (either owned by that role or having a privilege on it) are returned.
  • If you do not provide :offset or :limit, all records will be returned. For systems with a huge number of resources, you may want to paginate as shown in the example below.
  • If :offset is provided and :limit is not, 10 records starting at :offset will be returned. You may choose an arbitrarily large number for :limit, but the same performance considerations apply as when omitting :offset and :limit.

Examples:

Search for resources annotated with the text "WebService Route"

webservice_routes = api.resources search: "WebService Route"

# Check that it worked:
webservice_routes.each do |resource|
   searchable = [resource.annotations.to_h.values, resource.resource_id]
   raise "FAILED" unless searchable.flatten.any?{|s| s.include? "WebService Route"}
end

Restrict the search to 'group' resources

groups = api.resources kind: 'group'

# Correct behavior:
expect(groups.all?{|g| g.kind == 'group'}).to be_true

Get every single resource in a performant way

resources = []
limit = 25
offset = 0
until (batch = api.resources limit: limit, offset: offset).empty?
  offset += batch.length
  resources.concat results
end
# do something with your resources

Parameters:

  • opts (Hash) (defaults to: {})

    search criteria

Options Hash (opts):

  • :search (String)

    find resources whose ids or annotations contain this string

  • :kind (String)

    find resources whose kind matches this string

  • :limit (Integer)

    the maximum number of records to return (Conjur may return fewer)

  • :offset (Integer)

    offset of the first record to return

Returns:



141
142
143
144
145
146
147
148
149
150
# File 'lib/conjur/api/resources.rb', line 141

def resources opts = {}
  opts = { host: Conjur::Authz::API.host, credentials: credentials }.merge opts
  opts[:account] ||= Conjur.
  
  Resource.all(opts).map do |result|
    resource(result['id']).tap do |r|
      r.attributes = result
    end
  end
end

#role(role) ⇒ Conjur::Role

Return a Role representing a role with the given id. Note that the Role may or may not exist (see Exists#exists?).

Permissions

Because this method returns roles that may or may not exist, it doesn't require any permissions to call it: in fact, it does not perform an HTTP request (except for authentication if necessary).

Examples:

Create and show a role

api.create_role 'cat:iggy'
iggy = api.role 'cat:iggy'
iggy.exists? # true
iggy.members.map(&:member).map(&:roleid) # => ['conjur:user:admin']
api.current_role.roleid # => 'conjur:user:admin' # creator role is a member of created role.

No permissions are required to call this method

api.current_role # => "user:no-access"

# current role is only a member of itself, so it can't see other roles.
api.current_role.memberships.count # => 1
admin = api.role 'user:admin' # OK
admin.exists? # => true
admin.members # => RestClient::Forbidden: 403 Forbidden

Parameters:

  • role (String)

    the id of the role, which must contain at least kind and id tokens (account is optional).

Returns:



110
111
112
# File 'lib/conjur/api/roles.rb', line 110

def role role
  Role.new(Conjur::Authz::API.host, credentials)[self.class.parse_role_id(role).join('/')]
end

#role_graph(roles, options = {}) ⇒ Conjur::Graph

Fetch a Graph representing the relationships of a given role or roles. Such graphs are transitive, and follow the normal permissions for role visibility.

Parameters:

  • roles (Array<Conjur::Role, String>, String, Conjur::Role)

    role or or array of roles roles whose relationships we're interested in

  • options (Hash) (defaults to: {})

    options for the request

Options Hash (options):

  • :ancestors (Boolean)

    Whether to return ancestors of the given roles (true by default)

  • :descendants (Boolean)

    Whether to return descendants of the given roles (true by default)

  • :as_role (Conjur::Role, String)

    Only roles visible to this role will be included in the graph

Returns:

  • (Conjur::Graph)

    An object representing the role memberships digraph



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/conjur/api/roles.rb', line 38

def role_graph roles, options = {}
  roles = [roles] unless roles.kind_of? Array
  roles.map!{|r| normalize_roleid(r) }
  options[:as_role] = normalize_roleid(options[:as_role]) if options.include?(:as_role)
  options.reverse_merge! as_role: normalize_roleid(current_role), descendants: true, ancestors: true

  query = {from_role: options.delete(:as_role)}
    .merge(options.slice(:ancestors, :descendants))
    .merge(roles: roles).to_query
  Conjur::Graph.new RestClient::Resource.new(Conjur::Authz::API.host, credentials)["#{Conjur.}/roles?#{query}"].get
end

#tokenHash

Note:

calling this method on an Conjur::API instance created with new_from_token will have

The token used to authenticate requests made with the api. The token will be fetched if it hasn't already, or if it has expired. Accordingly, this method may raise a RestClient::Unauthorized exception if the credentials are invalid.

undefined behavior if the token is expired.

Returns:

  • (Hash)

    the authentication token as a Hash

Raises:

  • (RestClient::Unauthorized)

    if the username and api key are invalid.



194
195
196
197
198
199
200
201
202
# File 'lib/conjur/base.rb', line 194

def token
  @token = nil unless token_valid?

  @token ||= Conjur::API.authenticate(@username, @api_key)

  fail "obtained token is invalid" unless token_valid? # sanity check

  return @token
end

#user(login) ⇒ Conjur::User

Return an object representing a user with the given login. The User object returned may or may not exist. You can check whether it exists with the Exists#exists? method.

The returned User will not have an api_key.

Permissions

Any authenticated role may call this method.

Parameters:

  • login (String)

    the user's login

Returns:



70
71
72
# File 'lib/conjur/api/users.rb', line 70

def user 
  standard_show Conjur::Core::API.host, :user, 
end

#usernameString

The name of the user as which this api instance is authenticated. This is available whether the api instance was created from credentials or an authentication token.

Returns:

  • (String)

    the login of the current user.



174
175
176
# File 'lib/conjur/base.rb', line 174

def username
  @username || @token['data']
end

#variable(id) ⇒ Conjur::Variable

Retrieve an object representing a Conjur Variable. The Variable returned may or may not exist, and your permissions on the corresponding resource determine the operations you can perform on it.

Permissions

Any authenticated role can call this method.

Parameters:

  • id (String)

    the unqualified id of the variable

Returns:



70
71
72
# File 'lib/conjur/api/variables.rb', line 70

def variable id
  standard_show Conjur::Core::API.host, :variable, id
end

#variable_values(varlist) ⇒ Hash

Fetch the values of a list of variables. This operation is more efficient than fetching the values one by one.

This method will fail unless:

  • All of the variables exist
  • You have permission to 'execute' all of the variables

This method is used to implement the conjur env commands. You may consider using that instead to run your program in an environment with the necessary secrets.

Examples:

Fetch multiple variable values

values = variable_values ['postgres_uri', 'aws_secret_access_key', 'aws_access_key_id']
values # =>
{
   "postgres_uri" => "postgres://..."
   "aws_secret_access_key" => "..."
   "aws_access_key_id" => "..."
}

Parameters:

  • varlist (Array<String>)

    list of variable ids to fetch

Returns:

  • (Hash)

    a hash mapping variable ids to variable values

Raises:

  • (RestClient::Forbidden, RestClient::ResourceNotFound)

    if any of the variables don't exist or aren't accessible.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/conjur/api/variables.rb', line 96

def variable_values(varlist)
  raise ArgumentError, "Variables list must be an array" unless varlist.kind_of? Array 
  raise ArgumentError, "Variables list is empty" if varlist.empty?
  opts = "?vars=#{varlist.map { |v| fully_escape(v) }.join(',')}"
  begin 
    resp = RestClient::Resource.new(Conjur::Core::API.host, self.credentials)['variables/values'+opts].get
    return JSON.parse( resp.body ) 
  rescue RestClient::ResourceNotFound 
    return Hash[ *varlist.map { |v| [ v, variable(v).value ]  }.flatten ]  
  end
end