Module: Conversant::V3::HttpClient

Included in:
Base
Defined in:
lib/conversant/v3/http_client.rb

Overview

HTTP client module for handling SSO authentication and HTTP requests

This module provides low-level HTTP operations including SSO login flow, cookie management, and authenticated request handling. It's included by Base class and used by all service classes for authentication.

Examples:

Using HttpClient in a service

class MyService < Conversant::V3::Base
  include HttpClient

  def my_api_call
    sessions = authenticate
    request(:get, api_url, nil, headers)
  end
end

Since:

  • 1.0.0

Constant Summary collapse

LOGIN_URL =

Default login URL for SSO authentication

Since:

  • 1.0.0

'https://console.swiftfederation.com/'
PORTAL_SESSION_REDIS_KEY =

Redis key for storing portal SESSION cookie

Since:

  • 1.0.0

'CONVERSANT.V3.PORTAL.SESSION'
SSO_GW_SESSION2_REDIS_KEY =

Redis key for storing SSO_GW_SESSION2 cookie

Since:

  • 1.0.0

'CONVERSANT.V3.PORTAL.SSO_GW_SESSION2'

Instance Method Summary collapse

Instance Method Details

#authenticateHash{Symbol => String}?

Authenticates and returns cached SSO sessions

Wrapper around sso_login that ensures sessions are cached in Redis. This is the primary method used by service classes for authentication.

Examples:

sessions = authenticate
if sessions
  headers['Cookie'] = "SESSION=#{sessions[:session]}; SSO_GW_SESSION2=#{sessions[:sso_gw_session2]}"
end

Returns:

  • (Hash{Symbol => String}, nil)

    Hash with :session and :sso_gw_session2 keys, or nil on failure

Since:

  • 1.0.0



191
192
193
194
195
196
197
198
199
200
201
# File 'lib/conversant/v3/http_client.rb', line 191

def authenticate
  result = 

  if result && result[:session]
    redis.set(PORTAL_SESSION_REDIS_KEY, result[:session], ex: configuration.cache_ttl)
    redis.set(SSO_GW_SESSION2_REDIS_KEY, result[:sso_gw_session2], ex: configuration.cache_ttl) if result[:sso_gw_session2]
    result
  else
    nil
  end
end

Gets the thread-local cookie jar for storing cookies during authentication

The cookie jar is used to maintain cookies across multiple HTTP requests during the SSO login flow. Each thread has its own isolated cookie jar.

Examples:

cookie_jar['SESSION'] = 'abc123'
puts cookie_jar['SESSION'] # => 'abc123'

Returns:

  • (Hash{String => String})

    Cookie name-value pairs

Since:

  • 1.0.0



44
45
46
# File 'lib/conversant/v3/http_client.rb', line 44

def cookie_jar
  Thread.current[:conversant_cookie_jar] ||= {}
end

Sets the thread-local cookie jar

Examples:

self.cookie_jar = { 'SESSION' => 'abc123' }
self.cookie_jar = nil # Clear cookies

Parameters:

  • value (Hash, nil)

    Cookie name-value pairs, or nil to clear

Returns:

  • (Hash, nil)

    The assigned value

Since:

  • 1.0.0



58
59
60
# File 'lib/conversant/v3/http_client.rb', line 58

def cookie_jar=(value)
  Thread.current[:conversant_cookie_jar] = value
end

#debug_log(message) ⇒ void

This method returns an undefined value.

Logs a debug message if debug mode is enabled

Examples:

debug_log "Starting authentication"

Parameters:

  • message (String)

    The message to log

Since:

  • 1.0.0



71
72
73
74
75
# File 'lib/conversant/v3/http_client.rb', line 71

def debug_log(message)
  return unless configuration.debug_mode

  configuration.logger.debug "Conversant::V3 - #{message}"
end

#request(method, url, payload, headers) ⇒ Array(Integer, RestClient::Response)

Makes an authenticated HTTP request

Handles JSON payload serialization and SSL verification based on configuration. All service classes use this method for making API calls.

Examples:

code, response = request(:get, 'https://api.example.com/data', nil, headers)
if code == 200
  data = JSON.parse(response.body)
end

Parameters:

  • method (Symbol)

    HTTP method (:get, :post, :put, :delete, etc.)

  • url (String)

    Full URL to request

  • payload (Hash, String, nil)

    Request payload (auto-converted to JSON if Content-Type matches)

  • headers (Hash{String => String})

    HTTP headers

Returns:

  • (Array(Integer, RestClient::Response))

    Status code and response object

Since:

  • 1.0.0



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/conversant/v3/http_client.rb', line 222

def request(method, url, payload, headers)
  debug_log "[Request] #{method} #{url}"
  debug_log "[Request] Headers: #{headers.inspect}" if configuration.debug_mode

  # Check Content-Type using string key (headers are now plain hash with string keys)
  if headers&.[]('Content-Type') == configuration.default_content_type
    payload = payload&.to_json
  end

  request = RestClient::Request.new(
    method: method,
    url: url,
    payload: payload,
    headers: headers,
    verify_ssl: configuration.verify_ssl
  )

  response = request.execute do |response|
    response
  end

  debug_log "[Response] Status: #{response.code}" if configuration.debug_mode
  [response.code, response]
rescue StandardError => e
  configuration.logger.error "Conversant::V3 - Request exception: #{e.message}"
  [500, nil]
end

#sso_loginHash{Symbol => String}?

Performs SSO login to obtain root SESSION and SSO_GW_SESSION2 cookies

Executes a multi-step SSO authentication flow:

  1. Fetches the login page
  2. Extracts the form action URL
  3. Submits credentials
  4. Extracts and caches session cookies

Sessions are cached in Redis for reuse across all services and customers.

Examples:

sessions = 
if sessions
  puts "SESSION: #{sessions[:session]}"
  puts "SSO_GW_SESSION2: #{sessions[:sso_gw_session2]}"
end

Returns:

  • (Hash{Symbol => String}, nil)

    Hash with :session and :sso_gw_session2 keys, or nil on failure

Since:

  • 1.0.0



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/conversant/v3/http_client.rb', line 97

def 
  session_key = PORTAL_SESSION_REDIS_KEY
  sso_key = SSO_GW_SESSION2_REDIS_KEY

  # Check cache first
  cached_session = redis.get(session_key)
  cached_sso_gw = redis.get(sso_key)

  if cached_session && cached_sso_gw
    debug_log 'Using cached global SSO sessions'
    return {
      session: cached_session,
      sso_gw_session2: cached_sso_gw
    }
  end

  begin
    # Initialize thread-safe cookie jar
    self.cookie_jar = {}

    # Step 1: Get login page and extract form action
    debug_log "[SSO Login - Step 1] Fetching login page: #{LOGIN_URL}"
     = http_get()
    return nil unless 

    debug_log "Login page loaded, status: #{login_page_response[:status]}"

    # Step 2: Parse login form to get action URL
    form_action = extract_form_action([:body])
    unless form_action
      debug_log 'Could not extract form action URL from login page'
      return nil
    end

    debug_log "[SSO Login - Step 2] Form action extracted: #{form_action}"

    # Step 3: Submit credentials
    form_data = URI.encode_www_form(
      username: configuration.swiftserve_identifier_id,
      password: configuration.swiftserve_identifier_hash,
      credentialId: ''
    )

    debug_log '[SSO Login - Step 3] Submitting login form...'
     = http_post(form_action, form_data, {
      'Content-Type' => 'application/x-www-form-urlencoded'
    })

    return nil unless 

    debug_log "Login completed, status: #{login_response[:status]}"

    # Step 4: Extract cookies
    session_cookie = cookie_jar['SESSION']
    sso_gw_session2_cookie = cookie_jar['SSO_GW_SESSION2']

    if session_cookie && sso_gw_session2_cookie
      # Cache the sessions globally
      redis.set(session_key, session_cookie, ex: configuration.cache_ttl)
      redis.set(sso_key, sso_gw_session2_cookie, ex: configuration.cache_ttl)

      configuration.logger.info 'Conversant::V3 - SSO login successful, sessions cached'

      return {
        session: session_cookie,
        sso_gw_session2: sso_gw_session2_cookie
      }
    end

    debug_log 'New SSO login failed - no valid sessions obtained'
    nil

  rescue StandardError => e
    configuration.logger.error "Conversant::V3 - SSO login error: #{e.message}"
    nil
  ensure
    self.cookie_jar = nil
  end
end