Module: Jamf::Connection::Connect

Included in:
Jamf::Connection
Defined in:
lib/jamf/api/connection/connect.rb

Overview

This module defines constants and methods used for processing the connection parameters, acquiring passwords and tokens, and creating the connection objects to the Classic and Jamf Pro APIs. It also defines the disconnection methods

Instance Method Summary collapse

Instance Method Details

#connect(url = nil, **params) ⇒ String Also known as: login

Connect to the both the Classic and Jamf Pro APIs

IMPORTANT: http (non-SSL, unencrypted) connections are not allowed.

The first parameter may be a URL (must be https) from which the host & port will be used, and if present, the user and password E.g.

connect 'https://myuser:[email protected]:8443'

which is the same as:

connect host: 'host.domain.edu', port: 8443, user: 'myuser', pw: 'pass'

When using a URL, other parameters below may be specified, however host: and port: parameters will be ignored, since they came from the URL, as will user: and :pw, if they are present in the URL. If the URL doesn’t contain user and pw, they can be provided via the parameters, or left to default values.

### Passwords

The pw: parameter also accepts the symbols :prompt, and :stdin

If :prompt, the user is promted on the commandline to enter the password for the :user.

If :stdin, the password is read from the first line of stdin

If :stdinX, (where X is an integer) the password is read from the Xth line of stdin.see Jamf.stdin

If omitted, and running from an interactive terminal, the user is prompted as with :prompt

### Tokens Instead of a user and password, you may specify a valid ‘token:’, which is either:

A Jamf::Connection::Token object, which can be extracted from an active Jamf::Connection via its #token method

or

A valid token string e.g. “eyJhdXR…6EKoo” from any source can also be used.

When using an existing token or token string, the username used to create the token will be read from the server. However, if you don’t also provide the users password using the pw: parameter, then the pw_fallback option will always be false.

### Default values

Any values available via JSS.config will be used if they are not provided in the parameters. See Jamf::Configuration. If there are no config values then a built-in default is used if available.

### API Clients

As of Jamf Pro 10.49, API connections can be made using “API Clients” which are assigned to various “API Roles”, as well as regular Jamf Pro accounts.

Connections made with API Client credentials are different from regular connections:

- Their expiration period can vary based on the Client definition
- The expirations are usually quite short, less than the default 30 min. session timeout
- They cannot be kept alive, they will become invalid when the expiration time arrives.
- The API endpoints and data exchange used for making API Client connections are
  different from those used by normal connections.

To make a connection using an API Client, pass in the client_id: and client_secret: instead of user: and pw:

Parameters:

  • url (String) (defaults to: nil)

    The URL to use for the connection. Must be ‘https’. The host, port, and (if provided), user and spassword will be extracted. Any of those params explicitly provided will be ignored if present in the url

  • params (Hash)

    the keyed parameters for connection.

Options Hash (**params):

  • :host (String)

    the hostname of the JSS API server, required if not defined in JSS.config

  • :server_path (String)

    If your JSS is not at the root of the server, e.g. if it’s at

    https://myjss.myserver.edu:8443/dev_mgmt/jssweb
    

    rather than

    https://myjss.myserver.edu:8443/
    

    then use this parameter to specify the path below the root e.g:

    server_path: 'dev_mgmt/jssweb'
    
  • :user (String)

    a JSS user who has API privs, required if not defined in Jamf::CONFIG. NOTE: To use an API Client (Jamf pro 10.49 and up), provide client_id: instead of user:

  • :client_id (String)

    The Client ID of an “API Client” available in Jamf Pro 10.49 and up. Use this instead of user:

  • :client_secret (String)

    The Client Secret of an “API Client” available in Jamf Pro 10.49 and up. Use this instead of pw:

  • :pw (String, Symbol)

    The user’s password, :prompt, or :stdin If :prompt, the user is promted on the commandline to enter the password If :stdin#, the password is read from a line of std in represented by the digit at #, so :stdin3 reads the passwd from the third line of standard input. Defaults to line 1, if no digit is supplied. see Jamf.stdin NOTE: To use an API Client (Jamf pro 10.49 and up), provide client_secret: instead of pw:

  • :port (Integer)

    the port number to connect with, defaults to 443 for Jamf Cloud hosts, 8443 for on-prem hosts

  • :ssl_version (String, Symbol)

    The SSL version to use. Default is TLSv1_2

  • :verify_cert (Boolean)

    should SSL certificates be verified. Defaults to true.

  • :open_timeout (Integer)

    the number of seconds to wait for an initial response, defaults to 60

  • :timeout (Integer)

    the number of seconds before an API call times out, defaults to 60

  • :keep_alive (Boolean)

    Should the token for the connection for be automatically refreshed before it expires? Default is true

  • :token_refresh_buffer (Integer)

    If keep_alive, refresh the token this many seconds before it expires. Must be >= Jamf::Connection::Token::MIN_REFRESH_BUFFER, which is the default

  • :pw_fallback (Boolean)

    If keep_alive, should the passwd be cached in memory and used to create a new token, if there are problems with the normal token refresh process?

  • :sticky_session (Boolean)

    Use a ‘sticky session’? Default is false. The hostname of Jamf Cloud urls does not point to a single https server, but any node of a cluster. Those nodes often take time to see changes made in other node. Sometimes, its important to perform a series of API actions to the same node, to avoid sync-timing problems between node. Setting sticky_session to true will cause all communication for this Connection to go through the one specific node it first connected ith. This is only relevant to Jamf Cloud connections, and will raise an exception is used with on-prem Jamf Pro servers. NOTE: It is not always appropriate to use this feature, and inapproriate use may negatively impact server performance. For more info, see developer.jamf.com/developer-guide/docs/sticky-sessions-for-jamf-cloud

Returns:

  • (String)

    connection description, the output of #to_s

Raises:

  • (ArgumentError)


187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/jamf/api/connection/connect.rb', line 187

def connect(url = nil, **params)
  raise ArgumentError, 'No url or connection parameters provided' if url.nil? && params.empty?

  # reset all values, flush caches
  disconnect

  # If there's a Token object in :token, this sets @token,
  # and adds host, port, user from that token
  parse_token params

  # Get host, port, user and pw from a URL, add to params if needed
  parse_url url, params

  # apply defaults from config, client, and then ruby-jss itself.
  apply_default_params params

  # Once we're here, all params have been parsed & defaulted into the
  # params hash, so make sure we have the minimum needed params for a connection
  verify_basic_params params

  # it there's no @token yet, get one from a token string or a password
  create_token_if_needed(params)

  # We have to have a usable connection to do this, so it has to come after
  # all the stuff above
  verify_server_version

  @timeout = params[:timeout]
  @open_timeout = params[:open_timeout]

  @connect_time = Time.now
  @name ||= "#{user}@#{host}:#{port}"

  @c_base_url = base_url + Jamf::Connection::CAPI_RSRC_BASE
  @jp_base_url = base_url + Jamf::Connection::JPAPI_RSRC_BASE

  # the faraday connection objects
  @c_cnx = create_classic_connection
  @jp_cnx = create_jp_connection

  # set the connection objects to sticky if desired. enforce booleans
  self.sticky_session = params[:sticky_session] ? true : false

  @connected = true

  to_s
end

#disconnectvoid

This method returns an undefined value.

With a REST connection, there isn’t any real “connection” to disconnect from So to disconnect, we just unset all our credentials.



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/jamf/api/connection/connect.rb', line 278

def disconnect
  flushcache
  @token&.stop_keep_alive

  @connect_time = nil
  @jp_cnx = nil
  @c_cnx = nil
  @c_base_url = nil
  @jp_base_url = nil
  @server_path = nil
  @token = nil
  @sticky_session_cookie = nil
  @sticky_session = nil
  @connected = false
  :disconnected
end

#enable_sticky_session(headers) ⇒ Object

If a sticky_session was requested when the connection was made, and we are connected to a jamf cloud server, the token’s http response contains the cookie we need to send with every request to ensure a stickey session.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/jamf/api/connection/connect.rb', line 241

def enable_sticky_session(headers)
  # commas separate the cookies
  raw_cookies = headers[Jamf::Connection::SET_COOKIE_HEADER].split(/\s*,\s*/)

  raw_cookies.each do |rc|
    # semicolons separate the attributes of the cookie,
    # with its name and value being the first pair.
    cookie_data = rc.split(/\s*;\s*/).first

    # attribute name and value are separated by '='
    cookie_name, cookie_value = cookie_data.split('=')
    next unless cookie_name == Jamf::Connection::STICKY_SESSION_COOKIE_NAME

    @sticky_session_cookie = "#{Jamf::Connection::STICKY_SESSION_COOKIE_NAME}=#{cookie_value}"
    jp_cnx.headers[Jamf::Connection::COOKIE_HEADER] = @sticky_session_cookie
    c_cnx.headers[Jamf::Connection::COOKIE_HEADER] = @sticky_session_cookie
    return @sticky_session_cookie
  end
  # be sure to return nil if there was no appropriate cookie,
  # which means we aren't using Jamf Cloud

  nil
end

#logoutObject

Same as disconnect, but invalidates the token on the server first



297
298
299
300
# File 'lib/jamf/api/connection/connect.rb', line 297

def logout
  @token&.invalidate
  disconnect
end

#validate_connectedObject

raise exception if not connected, and make sure we’re using the current token



267
268
269
270
# File 'lib/jamf/api/connection/connect.rb', line 267

def validate_connected
  using_dft = 'Jamf.cnx' if self == Jamf.cnx
  raise Jamf::InvalidConnectionError, "Connection '#{@name}' Not Connected. Use #{using_dft}.connect first." unless connected?
end