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.

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

  • :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

  • :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)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/jamf/api/connection/connect.rb', line 161

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.



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/jamf/api/connection/connect.rb', line 261

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.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/jamf/api/connection/connect.rb', line 215

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



280
281
282
283
# File 'lib/jamf/api/connection/connect.rb', line 280

def logout
  @token&.invalidate
  disconnect
end

#update_refreshed_token(subcnx) ⇒ Object

always use the current token, which by default will auto-refresh



249
250
251
252
253
# File 'lib/jamf/api/connection/connect.rb', line 249

def update_refreshed_token(subcnx)
  return if subcnx.headers['Authorization'] == "Bearer #{@token.token}"

  subcnx.authorization :Bearer, @token.token
end

#validate_connected(subcnx) ⇒ Object

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



241
242
243
244
245
246
# File 'lib/jamf/api/connection/connect.rb', line 241

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

  update_refreshed_token(subcnx)
end