From bb10acfe1f3dbe35792482ba37e4531d267e5873 Mon Sep 17 00:00:00 2001 From: Owens Ehimen Date: Wed, 22 Apr 2026 12:44:56 -0400 Subject: [PATCH 1/4] COn 1012: Use basic auth for campact_user_service --- campact_user_service.gemspec | 2 -- lib/campact_user_service/client.rb | 32 ++++++++++-------------------- spec/client_spec.rb | 12 +++-------- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/campact_user_service.gemspec b/campact_user_service.gemspec index 7ef2d25..503b253 100644 --- a/campact_user_service.gemspec +++ b/campact_user_service.gemspec @@ -29,8 +29,6 @@ Gem::Specification.new do |spec| # Runtime dependencies spec.add_dependency "faraday", "~> 2.14" spec.add_dependency "json", "~> 2.1" - spec.add_dependency "rotp", "~> 6" - # Development dependencies spec.add_development_dependency "byebug" spec.add_development_dependency "faraday-detailed_logger", "~> 2.1" diff --git a/lib/campact_user_service/client.rb b/lib/campact_user_service/client.rb index cdb0e2d..95da0bb 100644 --- a/lib/campact_user_service/client.rb +++ b/lib/campact_user_service/client.rb @@ -1,6 +1,6 @@ +require 'base64' require 'faraday' require 'json' -require 'rotp' require 'campact_user_service/response_error' module CampactUserService @@ -8,12 +8,12 @@ class Client TIMEOUT = 60.freeze OPEN_TIMEOUT = 20.freeze - attr_reader :connection, :host, :port, :topt_authorization + attr_reader :connection, :host, :port, :basic_auth def initialize(options) @host = options.fetch(:host) @port = options[:port] - @topt_authorization = options[:topt_authorization] + @basic_auth = options[:basic_auth] faraday_options = default_faraday_options.merge(options.delete(:faraday) || {}) adapter = faraday_options.delete(:adapter) || Faraday.default_adapter @@ -44,8 +44,8 @@ def request(verb, path, options) req.body = options[:body] end - if topt_authorization - req.headers['authorization'] = authorization(topt_authorization) + if basic_auth + req.headers['authorization'] = authorization(basic_auth) end end @@ -93,23 +93,11 @@ def format_cookies(cookies) end end - def authorization(totp_options) - user = totp_options.fetch(:user) - secret = totp_options.fetch(:secret) - - token = [user, auth_pass(secret)].join(':') - - "Token #{token}" - end - - def auth_pass(secret) - totp_secret = ROTP::Base32.encode(secret) - - ROTP::TOTP.new(totp_secret, { - digest: 'sha256', - digits: 8, - interval: 30 - }).now + def authorization(basic_auth_options) + user = basic_auth_options.fetch(:user) + password = basic_auth_options.fetch(:password) + credentials = Base64.strict_encode64("#{user}:#{password}") + "Basic #{credentials}" end end end diff --git a/spec/client_spec.rb b/spec/client_spec.rb index c6b6409..8f44e99 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -131,19 +131,13 @@ subject.get_request('/foo/bar', cookies: {'foo' => 'bar', 'xyz' => 'abc'}) end - it 'should set TOTP authorization header' do + it 'should set Basic Auth authorization header' do allow(response).to receive(:status).and_return(200) allow(response).to receive(:body).and_return(nil) - totp_secret = ROTP::Base32.encode('shh! a secret!') + expect(headers_builder).to receive(:[]=).with('authorization', 'Basic ' + Base64.strict_encode64('api_user:s3cr3t')) - totp = double - expect(totp).to receive(:now).and_return('totp_token') - expect(ROTP::TOTP).to receive(:new).with(totp_secret, hash_including(digest: 'sha256', digits: 8, interval: 30)).and_return(totp) - - expect(headers_builder).to receive(:[]=).with('authorization', 'Token api_user:totp_token') - - subject = CampactUserService::Client.new(host: 'demo.campact.de', topt_authorization: {user: 'api_user', secret: 'shh! a secret!'}) + subject = CampactUserService::Client.new(host: 'demo.campact.de', basic_auth: {user: 'api_user', password: 's3cr3t'}) subject.get_request('/foo/bar') end From 75d51006bb805c671041377a93e04d81d16699e7 Mon Sep 17 00:00:00 2001 From: Owens Ehimen Date: Wed, 22 Apr 2026 12:46:59 -0400 Subject: [PATCH 2/4] bump version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7e961f9..2533cac 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.3.2 \ No newline at end of file +4.3.3 \ No newline at end of file From 2be250828a6c42d4bb3b6966e04903d51f579f72 Mon Sep 17 00:00:00 2001 From: Owens Ehimen Date: Wed, 22 Apr 2026 14:44:47 -0400 Subject: [PATCH 3/4] Use Faraday for basic auth --- VERSION | 2 +- lib/campact_user_service/client.rb | 11 +---------- spec/client_spec.rb | 30 +++++++++++++++++++----------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/VERSION b/VERSION index 2533cac..e91d9be 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.3.3 \ No newline at end of file +4.3.3 diff --git a/lib/campact_user_service/client.rb b/lib/campact_user_service/client.rb index 95da0bb..eddf103 100644 --- a/lib/campact_user_service/client.rb +++ b/lib/campact_user_service/client.rb @@ -1,4 +1,3 @@ -require 'base64' require 'faraday' require 'json' require 'campact_user_service/response_error' @@ -20,6 +19,7 @@ def initialize(options) @connection = Faraday.new(endpoint, faraday_options) do |faraday| faraday.adapter adapter faraday.request :json + faraday.request :authorization, :basic, basic_auth[:user], basic_auth[:password] if basic_auth end end @@ -44,9 +44,6 @@ def request(verb, path, options) req.body = options[:body] end - if basic_auth - req.headers['authorization'] = authorization(basic_auth) - end end case response.status @@ -93,11 +90,5 @@ def format_cookies(cookies) end end - def authorization(basic_auth_options) - user = basic_auth_options.fetch(:user) - password = basic_auth_options.fetch(:password) - credentials = Base64.strict_encode64("#{user}:#{password}") - "Basic #{credentials}" - end end end diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 8f44e99..f1dfff0 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -1,3 +1,4 @@ +require 'base64' require 'spec_helper' describe CampactUserService::Client do @@ -131,17 +132,6 @@ subject.get_request('/foo/bar', cookies: {'foo' => 'bar', 'xyz' => 'abc'}) end - it 'should set Basic Auth authorization header' do - allow(response).to receive(:status).and_return(200) - allow(response).to receive(:body).and_return(nil) - - expect(headers_builder).to receive(:[]=).with('authorization', 'Basic ' + Base64.strict_encode64('api_user:s3cr3t')) - - subject = CampactUserService::Client.new(host: 'demo.campact.de', basic_auth: {user: 'api_user', password: 's3cr3t'}) - - subject.get_request('/foo/bar') - end - it 'should parse JSON response on successful response' do allow(response).to receive(:status).and_return(200) allow(response).to receive(:body).and_return({a_field: 'foo', another_field: 'bar'}.to_json) @@ -155,6 +145,24 @@ end end + context 'with HTTP connection stubbed' do + before(:each) do + WebMock.disable_net_connect! + end + + it 'should set Basic Auth authorization header' do + stub_get = + stub_request(:get, 'https://demo.campact.de/foo/bar') + .with(headers: {'Authorization' => 'Basic ' + Base64.strict_encode64('api_user:s3cr3t')}) + .to_return(status: 200, body: '{}') + + subject = CampactUserService::Client.new(host: 'demo.campact.de', basic_auth: {user: 'api_user', password: 's3cr3t'}) + subject.get_request('/foo/bar') + + assert_requested(stub_get) + end + end + describe '#delete_request' do let(:connection) { double } let(:request_builder) { double } From 7d7deb10e772663521c24025041dd65e360112d3 Mon Sep 17 00:00:00 2001 From: Owens Ehimen Date: Wed, 22 Apr 2026 14:48:55 -0400 Subject: [PATCH 4/4] add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b15db96..b5f3808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [4.3.3] - 2026-04-22 +- Switch to Basic Auth from TOTP auth + ## [4.3.2] - 2026-02-09 ### Dependency updates