From 2e8abe4da1e436172d8dbfacb13f079600e74cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Thu, 27 Oct 2016 14:46:51 +0200 Subject: [PATCH 01/10] Replace existing code for controller authentication with the Ruby SDK implementation --- Gemfile | 1 + .../rails/controller_authentication.rb | 19 +++++++++++++++++-- .../services/controller_authenticaton_spec.rb | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index f7c25da..3c4f34b 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gemspec gem 'sqlite3', '~> 1.3' gem 'sass-rails' +gem 'stormpath-sdk', git: 'https://github.com/stormpath/stormpath-sdk-ruby' group :development do gem 'pry' diff --git a/app/services/stormpath/rails/controller_authentication.rb b/app/services/stormpath/rails/controller_authentication.rb index f4bd39c..cd1e543 100644 --- a/app/services/stormpath/rails/controller_authentication.rb +++ b/app/services/stormpath/rails/controller_authentication.rb @@ -18,9 +18,16 @@ def authenticate! if any_auth_cookie_present? FromCookies.new(cookies).authenticate! elsif bearer_authorization_header? - FromBearerAuth.new(authorization_header).authenticate! + Stormpath::Authentication::HttpBearerAuthentication.new( + Stormpath::Rails::Client.application, + authorization_header, + local: validation_strategy + ).authenticate!.account elsif basic_authorization_header? - FromBasicAuth.new(authorization_header).authenticate! + Stormpath::Authentication::HttpBasicAuthentication.new( + Stormpath::Rails::Client.application, + authorization_header + ).authenticate!.account else raise UnauthenticatedRequest end @@ -39,6 +46,14 @@ def any_auth_cookie_present? def basic_authorization_header? authorization_header =~ BASIC_PATTERN end + + def validation_strategy + if Stormpath::Rails.config.web.oauth2.password.validation_strategy == 'stormpath' + true + else + false + end + end end end end diff --git a/spec/services/controller_authenticaton_spec.rb b/spec/services/controller_authenticaton_spec.rb index a4644e2..64ffca7 100644 --- a/spec/services/controller_authenticaton_spec.rb +++ b/spec/services/controller_authenticaton_spec.rb @@ -392,6 +392,7 @@ end it 'retrieves the account from access token' do + binding.pry current_account = controller_authenticator.authenticate! expect(current_account).to eq(account) end From e8d2ee80b8e9118c77cf44a4f9bf77cf260a5122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Thu, 27 Oct 2016 16:00:02 +0200 Subject: [PATCH 02/10] Remove binding.pry from spec --- spec/services/controller_authenticaton_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/services/controller_authenticaton_spec.rb b/spec/services/controller_authenticaton_spec.rb index 64ffca7..a4644e2 100644 --- a/spec/services/controller_authenticaton_spec.rb +++ b/spec/services/controller_authenticaton_spec.rb @@ -392,7 +392,6 @@ end it 'retrieves the account from access token' do - binding.pry current_account = controller_authenticator.authenticate! expect(current_account).to eq(account) end From 04aa5b7a752a7982a10c0710a2ed069b97615da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Mon, 31 Oct 2016 10:56:27 +0100 Subject: [PATCH 03/10] Delete excess classes for account verification and resolution and adjust specs --- .../rails/account_from_access_token.rb | 8 ++-- .../local_account_resolution.rb | 48 ------------------- .../stormpath_account_resolution.rb | 27 ----------- .../from_basic_auth.rb | 45 ----------------- .../from_bearer_auth.rb | 34 ------------- .../controller_authentication/from_cookies.rb | 3 ++ .../services/controller_authenticaton_spec.rb | 48 +++++++++---------- 7 files changed, 31 insertions(+), 182 deletions(-) delete mode 100644 app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb delete mode 100644 app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb delete mode 100644 app/services/stormpath/rails/controller_authentication/from_basic_auth.rb delete mode 100644 app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb diff --git a/app/services/stormpath/rails/account_from_access_token.rb b/app/services/stormpath/rails/account_from_access_token.rb index 9a3514e..f127156 100644 --- a/app/services/stormpath/rails/account_from_access_token.rb +++ b/app/services/stormpath/rails/account_from_access_token.rb @@ -13,17 +13,17 @@ def initialize(access_token) end def account - @account ||= resolution_class.new(access_token).account + @account ||= resolution_instance.verify(access_token).account end private - def resolution_class + def resolution_instance case Stormpath::Rails.config.web.oauth2.password.validation_strategy.to_sym when :local - LocalAccountResolution + Stormpath::Oauth::VerifyAccessToken.new(Client.application, local: true) when :stormpath - StormpathAccountResolution + Stormpath::Oauth::VerifyAccessToken.new(Client.application) else raise ArgumentError, 'Invalid validation strategy' end diff --git a/app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb b/app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb deleted file mode 100644 index e90a502..0000000 --- a/app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb +++ /dev/null @@ -1,48 +0,0 @@ -module Stormpath - module Rails - class AccountFromAccessToken - class LocalAccountResolution - attr_reader :access_token - - def initialize(access_token) - @access_token = access_token - @application = Client.application - validate_jwt - end - - def account - Stormpath::Rails::Client.client.accounts.get(account_href) - end - - private - - def account_href - jwt_data.first['sub'] - end - - def jwt_data - begin - @jwt_data ||= JWT.decode(access_token, ENV['STORMPATH_API_KEY_SECRET']) - rescue JWT::ExpiredSignature - raise Stormpath::Oauth::Error, :jwt_expired - end - end - - def validate_jwt - validate_jwt_is_an_access_token - validate_jwt_has_a_valid_issuer - end - - def validate_jwt_has_a_valid_issuer - return if jwt_data.first['iss'] == Stormpath::Rails::Client.application.href - raise DifferentIssuerError - end - - def validate_jwt_is_an_access_token - return if jwt_data.second['stt'] == 'access' - raise AuthenticationWithRefreshTokenAttemptError - end - end - end - end -end diff --git a/app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb b/app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb deleted file mode 100644 index f7d4a3c..0000000 --- a/app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Stormpath - module Rails - class AccountFromAccessToken - class StormpathAccountResolution - attr_reader :access_token, :application - - def initialize(access_token) - @access_token = access_token - @application = Client.application - validate_jwt_is_access_token - end - - def account - Stormpath::Oauth::VerifyAccessToken.new(application).verify(access_token).account - end - - def validate_jwt_is_access_token - raise AuthenticationWithRefreshTokenAttemptError if jwt_data.second['stt'] != 'access' - end - - def jwt_data - @jwt_data ||= JWT.decode(access_token, ENV['STORMPATH_API_KEY_SECRET']) - end - end - end - end -end diff --git a/app/services/stormpath/rails/controller_authentication/from_basic_auth.rb b/app/services/stormpath/rails/controller_authentication/from_basic_auth.rb deleted file mode 100644 index c4d939d..0000000 --- a/app/services/stormpath/rails/controller_authentication/from_basic_auth.rb +++ /dev/null @@ -1,45 +0,0 @@ -module Stormpath - module Rails - class ControllerAuthentication - class FromBasicAuth - attr_reader :authorization_header - - def initialize(authorization_header) - @authorization_header = authorization_header - end - - def authenticate! - raise UnauthenticatedRequest if fetched_api_key.nil? - raise UnauthenticatedRequest if fetched_api_key.secret != api_key_secret - fetched_api_key.account - end - - private - - def fetched_api_key - @fetched_api_key ||= Client.application.api_keys.search(id: api_key_id).first - end - - def api_key_id - decoded_authorization_header.first - end - - def api_key_secret - decoded_authorization_header.last - end - - def decoded_authorization_header - @decoded_authorization_header ||= begin - api_key_and_secret = Base64.decode64(basic_authorization_header).split(':') - raise UnauthenticatedRequest if api_key_and_secret.count != 2 - api_key_and_secret - end - end - - def basic_authorization_header - authorization_header.gsub(BASIC_PATTERN, '') - end - end - end - end -end diff --git a/app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb b/app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb deleted file mode 100644 index a93005c..0000000 --- a/app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Stormpath - module Rails - class ControllerAuthentication - class FromBearerAuth - attr_reader :authorization_header - - RESCUE_CLASSES = [ - Stormpath::Oauth::Error, - JWT::DecodeError, - AccountFromAccessToken::AuthenticationWithRefreshTokenAttemptError, - AccountFromAccessToken::DifferentIssuerError - ].freeze - - def initialize(authorization_header) - @authorization_header = authorization_header - end - - def authenticate! - begin - AccountFromAccessToken.new(bearer_access_token).account - rescue *RESCUE_CLASSES - raise UnauthenticatedRequest - end - end - - private - - def bearer_access_token - authorization_header.gsub(BEARER_PATTERN, '') - end - end - end - end -end diff --git a/app/services/stormpath/rails/controller_authentication/from_cookies.rb b/app/services/stormpath/rails/controller_authentication/from_cookies.rb index a01779e..c082e16 100644 --- a/app/services/stormpath/rails/controller_authentication/from_cookies.rb +++ b/app/services/stormpath/rails/controller_authentication/from_cookies.rb @@ -24,6 +24,9 @@ def authenticate! delete_access_token_cookie delete_refresh_token_cookie raise UnauthenticatedRequest + rescue ArgumentError + delete_access_token_cookie + delete_refresh_token_cookie end end diff --git a/spec/services/controller_authenticaton_spec.rb b/spec/services/controller_authenticaton_spec.rb index a4644e2..b785c7f 100644 --- a/spec/services/controller_authenticaton_spec.rb +++ b/spec/services/controller_authenticaton_spec.rb @@ -348,13 +348,13 @@ it 'raises an UnauthenticatedRequest error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(ArgumentError, 'Token is not an access token') end it 'deletes cookies' do begin controller_authenticator.authenticate! - rescue Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest + rescue ArgumentError end expect(controller.send(:cookies)['access_token']).not_to be expect(controller.send(:cookies)['refresh_token']).not_to be @@ -415,10 +415,10 @@ ActionDispatch::Request.new('HTTP_AUTHORIZATION' => "Bearer #{expired_token}") end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Verification error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::VerificationError, 'Signature verification raised') end describe 'with stormpath validation strategy' do @@ -428,10 +428,10 @@ ).to receive(:validation_strategy).and_return('stormpath') end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Verification error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::VerificationError, 'Signature verification raised') end end end @@ -441,10 +441,10 @@ ActionDispatch::Request.new('HTTP_AUTHORIZATION' => "Bearer INVALID-TOKEN") end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Decode error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end describe 'with stormpath validation strategy' do @@ -454,10 +454,10 @@ ).to receive(:validation_strategy).and_return('stormpath') end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Decode error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end end end @@ -467,10 +467,10 @@ ActionDispatch::Request.new('HTTP_AUTHORIZATION' => "Bearer ") end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Decode error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end describe 'with stormpath validation strategy' do @@ -480,10 +480,10 @@ ).to receive(:validation_strategy).and_return('stormpath') end - it 'raises an UnauthenticatedRequest error' do + it 'raises an JWT Decode error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end end end @@ -508,50 +508,50 @@ describe 'with only api key and no secret' do let(:credentials) { Base64.encode64(api_key.id) } - it 'raises an UnauthenticatedRequest error' do + it 'raises a Stormpath error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(Stormpath::Error) end end describe 'with non-existing api key and secret' do let(:credentials) { Base64.encode64("dahgf3q4234fsd:bvcbfgt54332") } - it 'raises an UnauthenticatedRequest error' do + it 'raises an Stormpath error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(Stormpath::Error) end end describe 'with api key and wrong secret' do let(:credentials) { Base64.encode64("#{api_key.id}:2aAbsa3TDFDF") } - it 'raises an UnauthenticatedRequest error' do + it 'raises an Stormpath error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(Stormpath::Error) end end describe 'with un encoded api key and secret' do let(:credentials) { "#{api_key.id}:#{api_key.secret}" } - it 'raises an UnauthenticatedRequest error' do + it 'raises an Stormpath error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(Stormpath::Error) end end describe 'with empty token' do let(:credentials) { '' } - it 'raises an UnauthenticatedRequest error' do + it 'raises an Stormpath error' do expect do controller_authenticator.authenticate! - end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) + end.to raise_error(Stormpath::Error) end end end From 7befd54fc7799f53672e73517da09a6019d73003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Mon, 31 Oct 2016 11:46:49 +0100 Subject: [PATCH 04/10] Remove rescuing ArgumentError --- Gemfile | 2 +- .../stormpath/rails/controller_authentication/from_cookies.rb | 3 --- docs/_themes/stormpath | 1 + 3 files changed, 2 insertions(+), 4 deletions(-) create mode 160000 docs/_themes/stormpath diff --git a/Gemfile b/Gemfile index 3c4f34b..65c5a41 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ gemspec gem 'sqlite3', '~> 1.3' gem 'sass-rails' -gem 'stormpath-sdk', git: 'https://github.com/stormpath/stormpath-sdk-ruby' +gem 'stormpath-sdk' group :development do gem 'pry' diff --git a/app/services/stormpath/rails/controller_authentication/from_cookies.rb b/app/services/stormpath/rails/controller_authentication/from_cookies.rb index c082e16..a01779e 100644 --- a/app/services/stormpath/rails/controller_authentication/from_cookies.rb +++ b/app/services/stormpath/rails/controller_authentication/from_cookies.rb @@ -24,9 +24,6 @@ def authenticate! delete_access_token_cookie delete_refresh_token_cookie raise UnauthenticatedRequest - rescue ArgumentError - delete_access_token_cookie - delete_refresh_token_cookie end end diff --git a/docs/_themes/stormpath b/docs/_themes/stormpath new file mode 160000 index 0000000..65d7663 --- /dev/null +++ b/docs/_themes/stormpath @@ -0,0 +1 @@ +Subproject commit 65d7663dd480d81b5a822b1735a7120cf183d4a0 From 4adf93771bd39e2dc793f5614fac2bcfff3c594f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Mon, 7 Nov 2016 15:37:45 +0100 Subject: [PATCH 05/10] Rescue the UnauthenticatedRequest as it was prior to the basic bearer changes --- spec/services/controller_authenticaton_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/services/controller_authenticaton_spec.rb b/spec/services/controller_authenticaton_spec.rb index 089d9b9..abb0160 100644 --- a/spec/services/controller_authenticaton_spec.rb +++ b/spec/services/controller_authenticaton_spec.rb @@ -348,13 +348,13 @@ it 'raises an UnauthenticatedRequest error' do expect do controller_authenticator.authenticate! - end.to raise_error(ArgumentError, 'Token is not an access token') + end.to raise_error(Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest) end it 'deletes cookies' do begin controller_authenticator.authenticate! - rescue ArgumentError + rescue Stormpath::Rails::ControllerAuthentication::UnauthenticatedRequest end expect(controller.send(:cookies)['access_token']).not_to be expect(controller.send(:cookies)['refresh_token']).not_to be From 6bda65feaab17627ebbd2adb7a331f27b6ea9377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Mon, 7 Nov 2016 16:40:08 +0100 Subject: [PATCH 06/10] Raise the ruby sdk version in the gemspec --- stormpath-rails.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stormpath-rails.gemspec b/stormpath-rails.gemspec index 23b6c01..88c8a94 100644 --- a/stormpath-rails.gemspec +++ b/stormpath-rails.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - spec.add_dependency 'stormpath-sdk', '>= 1.1.5' + spec.add_dependency 'stormpath-sdk', '>= 1.3.1' spec.add_dependency 'virtus' spec.add_dependency 'rails', '>= 3.1' spec.add_dependency 'recursive-open-struct' From ab2d8abc104f077c0d5f9b522114b844ff95add5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Tue, 8 Nov 2016 16:02:13 +0100 Subject: [PATCH 07/10] Change application url in .travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3555950..19cebac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ after_success: - if [ "$CURRENT_HASH" = "$RELEASE_HASH" ]; then DEPLOY_DOCS=true; fi env: global: - - STORMPATH_APPLICATION_URL=https://api.stormpath.com/v1/applications/4BiS1Hc1LuBEbszdDrOwyz + - STORMPATH_APPLICATION_URL=https://api.stormpath.com/v1/applications/4xz3y2Hrid4aqp5YwbNTvk - secure: VMjIMI42vIPTMPTr0fnzSPiIjzuSAnT7iNWjhAXP9WsdaCmxwHp1vOlry4QuX8DzpKHv2MQubeUN/UA227Nk1xn+CVu9mujWOqvvjmL9m20wMJvwT4ctn7zG+FJK76id9TEyx0mCTlH4ZrRoDMGfM9yzhpsg8FtSebBDdHxePaM= - secure: IhR6H9qxmxCDNbLK0ebYuIXQRsGA/JhD6In4V/hnSMJ8lPi2kwRn6eKclNCHGNjcy6QF1V5vddKIfKOkFFZvIyP26reygTX1g5Mfa8SqTGKh3DAW4WP+T+yaE4z4UBDK1zZpbV0Zbkw/HC0xeD8UPnjRzERX1LVZp1qeEjhQrks= - secure: a5woUmOQPRW6FBQBaxKJATfggUD/BVTBfeRaS07u1SQOpMoGJZLY0m29PVx4fHwRD1E7ho31YIeH8wk1vMMrimIHSdE1B4pm4n8bUTi/gDFwavXq9KgTdH8f6Eli37nAXZum78m4NgL9+OlrKeJKCcROdzniZPvFaLrnOwBGzVs= From 6f06d8c8717d6dc43599fadd6636ddd262d03f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Thu, 10 Nov 2016 13:14:20 +0100 Subject: [PATCH 08/10] Add authentication spec for the controller.rb mixin --- Gemfile | 1 - .../rails/account_from_access_token.rb | 2 +- lib/stormpath/rails/controller.rb | 2 +- spec/spec_helper.rb | 6 +- spec/stormpath/authentication_spec.rb | 149 ++++++++++++++++++ spec/support/stormpath_testing_helpers.rb | 18 +++ 6 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 spec/stormpath/authentication_spec.rb diff --git a/Gemfile b/Gemfile index 65c5a41..f7c25da 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,6 @@ gemspec gem 'sqlite3', '~> 1.3' gem 'sass-rails' -gem 'stormpath-sdk' group :development do gem 'pry' diff --git a/app/services/stormpath/rails/account_from_access_token.rb b/app/services/stormpath/rails/account_from_access_token.rb index f127156..617f84f 100644 --- a/app/services/stormpath/rails/account_from_access_token.rb +++ b/app/services/stormpath/rails/account_from_access_token.rb @@ -8,7 +8,7 @@ class AccountFromAccessToken DifferentIssuerError = Class.new(ArgumentError) def initialize(access_token) - raise(NoAccessToken) if access_token.nil? + raise(NoAccessToken) if access_token.blank? @access_token = access_token end diff --git a/lib/stormpath/rails/controller.rb b/lib/stormpath/rails/controller.rb index 2fe56b4..2a14177 100644 --- a/lib/stormpath/rails/controller.rb +++ b/lib/stormpath/rails/controller.rb @@ -15,7 +15,7 @@ module Controller def current_account @current_account ||= begin ControllerAuthentication.new(cookies, request.headers['Authorization']).authenticate! - rescue ControllerAuthentication::UnauthenticatedRequest + rescue ControllerAuthentication::UnauthenticatedRequest, Stormpath::Error, JWT::DecodeError nil end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4379e25..ecaf5b1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -53,9 +53,7 @@ RSpec.configure do |config| config.use_transactional_fixtures = true config.include FactoryGirl::Syntax::Methods - config.include Stormpath::Testing::Helpers, type: :request - config.include Stormpath::Testing::Helpers, type: :feature - config.include Stormpath::Testing::Helpers, type: :service + config.include Stormpath::Testing::Helpers config.include Rails.application.routes.url_helpers, type: :service config.include MatchJson::Matchers config.include Capybara::DSL, type: :feature @@ -85,4 +83,4 @@ Capybara::RackTest::Driver.new(app, headers: { 'HTTP_ACCEPT' => 'text/html' }) end -Rails.application.routes.default_url_options[:host]= 'localhost:3000' +Rails.application.routes.default_url_options[:host]= 'localhost:3000' diff --git a/spec/stormpath/authentication_spec.rb b/spec/stormpath/authentication_spec.rb new file mode 100644 index 0000000..a468b25 --- /dev/null +++ b/spec/stormpath/authentication_spec.rb @@ -0,0 +1,149 @@ +require 'spec_helper' + +describe Stormpath::Rails::Controller, vcr: true, type: :request do + shared_examples 'a restricting controller' do + it 'should redirect to login uri' do + get_profile + expect(response).to redirect_to('/login?next=/me') + end + + it 'should have status 302' do + get_profile + expect(response.status).to eq 302 + end + end + + shared_examples 'a profile controller' do + it 'should return account' do + get_profile + expect(JSON.parse(response.body)['account']['email']).to eq account.email + end + + it 'should respond with 200' do + get_profile + expect(response.status).to eq 200 + end + end + + let(:application) { test_application } + let(:directory) { test_client.directories.first } + let(:account_attrs) { FactoryGirl.attributes_for(:account) } + let(:account) { application.accounts.create(account_attrs) } + let(:application2) { test_client.applications.create(name: 'ruby sdk another test app') } + let(:directory2) { test_client.directories.create(name: 'ruby sdk another test dir') } + let(:map_another_directory) { map_account_store(application2, directory2, 0, true, true) } + let(:account2) { application2.accounts.create(account_attrs) } + let(:expired_token) do + 'eyJraWQiOiI2VTRIWk1IR0VZMEpHV1ZITjBVVU81QkdXIiwiYWxnIjoiSFMyNTYifQ.eyJqdGkiOiI0MTFwUFh6QlQ1Qmo4ckM2VVZBbGRQIiwiaWF0IjoxNDY0MTc3NzMyLCJpc3MiOiJodHRwczovL2FwaS5zdG9ybXBhdGguY29tL3YxL2FwcGxpY2F0aW9ucy8zblpsTEtWTUlPUHU3MVlDN1RGUjBvIiwic3ViIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hY2NvdW50cy80MDMxTkF2UU9HNEZJMldXSjhRNjExIiwiZXhwIjoxNDY0MTgxMzMyLCJydGkiOiI0MTFwUFVmNllVc2tXMjZGSUZKVjFMIn0.ltcEQqkVnMutBQItQehVn2ckXwsxnBjfTucFIuoGVNY' + end + let(:aquire_token) { application.authenticate_oauth(password_grant_request) } + let(:access_token) { aquire_token.access_token } + let(:api_key) { account.api_keys.create({}) } + let(:encoded_api_key) { Base64.encode64("#{api_key.id}:#{api_key.secret}") } + + let(:get_profile) do + get '/me', {}, header => value + end + + describe 'from cookies' do + let(:header) { 'HTTP_COOKIE' } + + context 'without access token' do + let(:value) { 'access_token=' } + it_should_behave_like 'a restricting controller' + end + + context 'expired access token' do + let(:value) { "access_token=#{expired_token}" } + it_should_behave_like 'a restricting controller' + end + + context 'invalid issuer' do + before do + map_another_directory + account2 + end + let(:password_grant_request) do + Stormpath::Oauth::PasswordGrantRequest.new(account2.email, 'Password1337') + end + let(:access_token) { aquire_token.access_token } + let(:aquire_token) { application2.authenticate_oauth(password_grant_request) } + let(:value) { "access_token=#{access_token}" } + after do + account2.delete + directory2.delete + application2.delete + end + it_should_behave_like 'a restricting controller' + end + + context 'valid access token' do + let(:password_grant_request) do + Stormpath::Oauth::PasswordGrantRequest.new(account.email, 'Password1337') + end + let!(:value) { "access_token=#{access_token}" } + it_should_behave_like 'a profile controller' + end + end + + describe 'basic auth' do + let(:header) { 'Authorization' } + + context 'valid authorization_header' do + let(:value) { "Basic #{encoded_api_key}" } + it_should_behave_like 'a profile controller' + end + + context 'without authorization_header' do + let(:value) { 'Basic ' } + it_should_behave_like 'a restricting controller' + end + + context 'with just the api key id as the authorization_header' do + let(:encoded_api_key) { Base64.encode64("#{api_key.id}:") } + let(:value) { "Basic #{encoded_api_key}" } + it_should_behave_like 'a restricting controller' + end + end + + describe 'bearer auth' do + let(:header) { 'Authorization' } + + context 'without access token' do + let(:value) { 'Bearer ' } + it_should_behave_like 'a restricting controller' + end + + context 'expired access token' do + let(:value) { "Bearer #{expired_token}" } + it_should_behave_like 'a restricting controller' + end + + context 'invalid issuer' do + before do + map_another_directory + account2 + end + let(:password_grant_request) do + Stormpath::Oauth::PasswordGrantRequest.new(account2.email, 'Password1337') + end + let(:access_token) { aquire_token.access_token } + let(:aquire_token) { application2.authenticate_oauth(password_grant_request) } + let(:value) { "Bearer #{access_token}" } + after do + account2.delete + directory2.delete + application2.delete + end + it_should_behave_like 'a restricting controller' + end + + context 'valid access token' do + let(:password_grant_request) do + Stormpath::Oauth::PasswordGrantRequest.new(account.email, 'Password1337') + end + let!(:value) { "Bearer #{access_token}" } + it_should_behave_like 'a profile controller' + end + end +end diff --git a/spec/support/stormpath_testing_helpers.rb b/spec/support/stormpath_testing_helpers.rb index 805d0dd..22983d4 100644 --- a/spec/support/stormpath_testing_helpers.rb +++ b/spec/support/stormpath_testing_helpers.rb @@ -18,6 +18,24 @@ def delete_test_account def delete_account(email) Stormpath::Rails::Client.application.accounts.search(email: email).first.delete end + + def test_application + Stormpath::Rails::Client.application + end + + def test_client + Stormpath::Rails::Client.client + end + + def map_account_store(app, store, index, default_account_store, default_group_store) + test_client.account_store_mappings.create( + application: app, + account_store: store, + list_index: index, + is_default_account_store: default_account_store, + is_default_group_store: default_group_store + ) + end end end end From 1412ec89393890ca547858569f72b22f4805381d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Thu, 10 Nov 2016 14:09:20 +0100 Subject: [PATCH 09/10] Create factories for applications, directories and randomize account username even more --- spec/factories.rb | 14 ++++++++++++-- spec/requests/profile/get_spec.rb | 1 - spec/stormpath/authentication_spec.rb | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/spec/factories.rb b/spec/factories.rb index 0064b6e..a78c46a 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -4,12 +4,12 @@ password 'Password1337' given_name { Faker::Name.first_name } surname { Faker::Name.last_name } - username { Faker::Internet.user_name } + username { "#{Faker::Internet.user_name}_#{Faker::Internet.user_name}" } phone_number { Faker::PhoneNumber.cell_phone } end factory :account_without_username, class: Stormpath::Resource::Account do - sequence(:email) { |n| "dev#{n}@example.com" } + sequence(:email) { |n| "dev#{n}@testmail.stormpath.com" } password 'Password1337' given_name { Faker::Name.first_name } surname { Faker::Name.last_name } @@ -18,4 +18,14 @@ factory :unverified_account, parent: :account do status 'UNVERIFIED' end + + factory :directory, class: Stormpath::Resource::Directory do + sequence(:name) { |n| "rails-#{n}-#{Faker::Lorem.word}-directory" } + description 'rails test directory' + end + + factory :application, class: Stormpath::Resource::Application do + sequence(:name) { |n| "rails-#{n}-#{Faker::Lorem.word}-application" } + description 'rails test application' + end end diff --git a/spec/requests/profile/get_spec.rb b/spec/requests/profile/get_spec.rb index 090a44c..893d6e0 100644 --- a/spec/requests/profile/get_spec.rb +++ b/spec/requests/profile/get_spec.rb @@ -6,7 +6,6 @@ def response_body end let(:account) { Stormpath::Rails::Client.application.accounts.create(account_attrs) } - let(:account_attrs) { FactoryGirl.attributes_for(:account) } after { account.delete } diff --git a/spec/stormpath/authentication_spec.rb b/spec/stormpath/authentication_spec.rb index a468b25..0c1825e 100644 --- a/spec/stormpath/authentication_spec.rb +++ b/spec/stormpath/authentication_spec.rb @@ -29,8 +29,8 @@ let(:directory) { test_client.directories.first } let(:account_attrs) { FactoryGirl.attributes_for(:account) } let(:account) { application.accounts.create(account_attrs) } - let(:application2) { test_client.applications.create(name: 'ruby sdk another test app') } - let(:directory2) { test_client.directories.create(name: 'ruby sdk another test dir') } + let(:application2) { test_client.applications.create(FactoryGirl.attributes_for(:application)) } + let(:directory2) { test_client.directories.create(FactoryGirl.attributes_for(:directory)) } let(:map_another_directory) { map_account_store(application2, directory2, 0, true, true) } let(:account2) { application2.accounts.create(account_attrs) } let(:expired_token) do From 35603c02690c58c936bd7650efa012fddbfc7661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20=C4=86ilimkovi=C4=87?= Date: Thu, 10 Nov 2016 14:26:06 +0100 Subject: [PATCH 10/10] Delete accounts in after callback in specs --- spec/stormpath/authentication_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/stormpath/authentication_spec.rb b/spec/stormpath/authentication_spec.rb index 0c1825e..e4d60df 100644 --- a/spec/stormpath/authentication_spec.rb +++ b/spec/stormpath/authentication_spec.rb @@ -40,11 +40,12 @@ let(:access_token) { aquire_token.access_token } let(:api_key) { account.api_keys.create({}) } let(:encoded_api_key) { Base64.encode64("#{api_key.id}:#{api_key.secret}") } - let(:get_profile) do get '/me', {}, header => value end + after { account.delete } + describe 'from cookies' do let(:header) { 'HTTP_COOKIE' }