Skip to content

Commit 75aae12

Browse files
authored
feat: Added support for Authenticated Datafiles (#255)
* fiirst version. unit tests pending * added unit tests * fixed rubocop errors * added changelog entry * fixed typo in changelog * removed a duplicated test * added documentation comment and updated readme * added a fullstop. honestly just to run the tests again. * updated the private datafile url * fixed unit test
1 parent 1e4247b commit 75aae12

File tree

6 files changed

+59
-10
lines changed

6 files changed

+59
-10
lines changed

.rubocop_todo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Lint/HandleExceptions:
1414
# Offense count: 8
1515
# Configuration parameters: CountKeywordArgs.
1616
Metrics/ParameterLists:
17-
Max: 12
17+
Max: 13
1818

1919
# Offense count: 2
2020
Naming/AccessorMethodName:

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Optimizely Ruby SDK Changelog
22

3+
## [Unreleased]
4+
- Added support for authenticated datafiles. `HTTPProjectConfigManager` now accepts `datafile_access_token` to be able to fetch authenticated datafiles.
5+
36
## 3.4.0
47
January 23rd, 2020
58

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ The `HTTPConfigManager` asynchronously polls for datafiles from a specified URL
8787
logger: nil,
8888
error_handler: nil,
8989
skip_json_validation: false,
90-
notification_center: notification_center
90+
notification_center: notification_center,
91+
datafile_access_token: nil
9192
)
9293
~~~~~~
9394
**Note:** You must provide either the `sdk_key` or URL. If you provide both, the URL takes precedence.
@@ -110,6 +111,9 @@ Boolean flag used to start the `AsyncScheduler` for datafile polling if set to `
110111
**blocking_timeout**
111112
The blocking timeout period is used to specify a maximum time to wait for initial bootstrapping. Valid blocking timeout period is between 1 and 2592000 seconds. Default is 15 seconds.
112113
114+
**datafile_access_token**
115+
An access token sent in an authorization header with the request to fetch private datafiles.
116+
113117
You may also provide your own logger, error handler, or notification center.
114118
115119

lib/optimizely/config_manager/http_project_config_manager.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class HTTPProjectConfigManager < ProjectConfigManager
5151
# error_handler - Provides a handle_error method to handle exceptions.
5252
# skip_json_validation - Optional boolean param which allows skipping JSON schema
5353
# validation upon object invocation. By default JSON schema validation will be performed.
54+
# datafile_access_token - access token used to fetch private datafiles
5455
def initialize(
5556
sdk_key: nil,
5657
url: nil,
@@ -63,10 +64,12 @@ def initialize(
6364
logger: nil,
6465
error_handler: nil,
6566
skip_json_validation: false,
66-
notification_center: nil
67+
notification_center: nil,
68+
datafile_access_token: nil
6769
)
6870
@logger = logger || NoOpLogger.new
6971
@error_handler = error_handler || NoOpErrorHandler.new
72+
@access_token = datafile_access_token
7073
@datafile_url = get_datafile_url(sdk_key, url, url_template)
7174
@polling_interval = nil
7275
polling_interval(polling_interval)
@@ -153,6 +156,7 @@ def request_config
153156
headers = {}
154157
headers['Content-Type'] = 'application/json'
155158
headers['If-Modified-Since'] = @last_modified if @last_modified
159+
headers['Authorization'] = "Bearer #{@access_token}" unless @access_token.nil?
156160

157161
response = Helpers::HttpUtils.make_request(
158162
@datafile_url, :get, nil, headers, Helpers::Constants::CONFIG_MANAGER['REQUEST_TIMEOUT']
@@ -288,7 +292,7 @@ def get_datafile_url(sdk_key, url, url_template)
288292
end
289293

290294
unless url
291-
url_template ||= Helpers::Constants::CONFIG_MANAGER['DATAFILE_URL_TEMPLATE']
295+
url_template ||= @access_token.nil? ? Helpers::Constants::CONFIG_MANAGER['DATAFILE_URL_TEMPLATE'] : Helpers::Constants::CONFIG_MANAGER['AUTHENTICATED_DATAFILE_URL_TEMPLATE']
292296
begin
293297
return (url_template % sdk_key)
294298
rescue

lib/optimizely/helpers/constants.rb

+1
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ module Constants
364364

365365
CONFIG_MANAGER = {
366366
'DATAFILE_URL_TEMPLATE' => 'https://cdn.optimizely.com/datafiles/%s.json',
367+
'AUTHENTICATED_DATAFILE_URL_TEMPLATE' => 'https://config.optimizely.com/datafiles/auth/%s.json',
367368
# Default time in seconds to block the 'config' method call until 'config' instance has been initialized.
368369
'DEFAULT_BLOCKING_TIMEOUT' => 15,
369370
# Default config update interval of 5 minutes

spec/config_manager/http_project_config_manager_spec.rb

+43-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@
1616
# limitations under the License.
1717
#
1818
require 'spec_helper'
19-
require 'optimizely/config_manager/http_project_config_manager'
20-
require 'optimizely/error_handler'
21-
require 'optimizely/exceptions'
22-
require 'optimizely/helpers/constants'
23-
require 'optimizely/helpers/validator'
24-
require 'optimizely/logger'
19+
2520
describe Optimizely::HTTPProjectConfigManager do
2621
let(:config_body_JSON) { OptimizelySpec::VALID_CONFIG_BODY_JSON }
2722
let(:error_handler) { Optimizely::RaiseErrorHandler.new }
@@ -468,4 +463,46 @@
468463
expect(@http_project_config_manager.optimizely_config['revision']).to eq('81')
469464
end
470465
end
466+
467+
describe 'datafile authentication' do
468+
it 'should add authorization header when auth token is provided' do
469+
allow(Optimizely::Helpers::HttpUtils).to receive(:make_request)
470+
@http_project_config_manager = Optimizely::HTTPProjectConfigManager.new(
471+
sdk_key: 'valid_sdk_key',
472+
datafile_access_token: 'the-token'
473+
)
474+
sleep 0.1
475+
expect(Optimizely::Helpers::HttpUtils).to have_received(:make_request).with(anything, anything, anything, hash_including('Authorization' => 'Bearer the-token'), anything)
476+
end
477+
478+
it 'should use authenticated datafile url when auth token is provided' do
479+
allow(Optimizely::Helpers::HttpUtils).to receive(:make_request).and_return(VALID_SDK_KEY_CONFIG_JSON)
480+
@http_project_config_manager = Optimizely::HTTPProjectConfigManager.new(
481+
sdk_key: 'valid_sdk_key',
482+
datafile_access_token: 'the-token'
483+
)
484+
sleep 0.1
485+
expect(Optimizely::Helpers::HttpUtils).to have_received(:make_request).with('https://config.optimizely.com/datafiles/auth/valid_sdk_key.json', any_args)
486+
end
487+
488+
it 'should use public datafile url when auth token is not provided' do
489+
allow(Optimizely::Helpers::HttpUtils).to receive(:make_request).and_return(VALID_SDK_KEY_CONFIG_JSON)
490+
@http_project_config_manager = Optimizely::HTTPProjectConfigManager.new(
491+
sdk_key: 'valid_sdk_key'
492+
)
493+
sleep 0.1
494+
expect(Optimizely::Helpers::HttpUtils).to have_received(:make_request).with('https://cdn.optimizely.com/datafiles/valid_sdk_key.json', any_args)
495+
end
496+
497+
it 'should prefer user provided template url over defaults' do
498+
allow(Optimizely::Helpers::HttpUtils).to receive(:make_request).and_return(VALID_SDK_KEY_CONFIG_JSON)
499+
@http_project_config_manager = Optimizely::HTTPProjectConfigManager.new(
500+
sdk_key: 'valid_sdk_key',
501+
datafile_access_token: 'the-token',
502+
url_template: 'http://awesomeurl'
503+
)
504+
sleep 0.1
505+
expect(Optimizely::Helpers::HttpUtils).to have_received(:make_request).with('http://awesomeurl', any_args)
506+
end
507+
end
471508
end

0 commit comments

Comments
 (0)