stormpath-rails 1.1.2.beta → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/.rubocop.yml +22 -0
  5. data/.travis.yml +6 -3
  6. data/Gemfile +10 -3
  7. data/README.md +139 -142
  8. data/Rakefile +9 -9
  9. data/app/assets/stylesheets/stormpath.css.scss +3 -2
  10. data/app/controllers/stormpath/rails/base_controller.rb +25 -6
  11. data/app/controllers/stormpath/rails/change_password/create_controller.rb +68 -0
  12. data/app/controllers/stormpath/rails/change_password/new_controller.rb +38 -0
  13. data/app/controllers/stormpath/rails/forgot_password/create_controller.rb +37 -0
  14. data/app/controllers/stormpath/rails/forgot_password/new_controller.rb +14 -0
  15. data/app/controllers/stormpath/rails/login/create_controller.rb +60 -0
  16. data/app/controllers/stormpath/rails/login/new_controller.rb +20 -0
  17. data/app/controllers/stormpath/rails/logout/create_controller.rb +61 -0
  18. data/app/controllers/stormpath/rails/oauth2/create_controller.rb +82 -0
  19. data/app/controllers/stormpath/rails/oauth2/new_controller.rb +11 -0
  20. data/app/controllers/stormpath/rails/profile/show_controller.rb +15 -0
  21. data/app/controllers/stormpath/rails/register/create_controller.rb +86 -0
  22. data/app/controllers/stormpath/rails/register/new_controller.rb +20 -0
  23. data/app/controllers/stormpath/rails/verify_email/create_controller.rb +37 -0
  24. data/app/controllers/stormpath/rails/verify_email/show_controller.rb +51 -0
  25. data/app/forms/stormpath/rails/login_form.rb +60 -0
  26. data/app/forms/stormpath/rails/registration_form.rb +106 -0
  27. data/app/forms/stormpath/rails/registration_form_fields.rb +71 -0
  28. data/app/helpers/social_helper.rb +2 -1
  29. data/app/serializers/stormpath/rails/account_serializer.rb +32 -0
  30. data/app/serializers/stormpath/rails/form_serializer.rb +37 -0
  31. data/app/serializers/stormpath/rails/login_new_serializer.rb +11 -0
  32. data/app/serializers/stormpath/rails/profile_serializer.rb +71 -0
  33. data/app/serializers/stormpath/rails/registration_form_serializer.rb +11 -0
  34. data/app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb +48 -0
  35. data/app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb +27 -0
  36. data/app/services/stormpath/rails/account_from_access_token.rb +33 -0
  37. data/app/services/stormpath/rails/account_login.rb +28 -0
  38. data/app/services/stormpath/rails/account_login_with_stormpath_token.rb +32 -0
  39. data/app/services/stormpath/rails/client_credentials_authentication.rb +40 -0
  40. data/app/services/stormpath/rails/controller_authentication/from_basic_auth.rb +45 -0
  41. data/app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb +34 -0
  42. data/app/services/stormpath/rails/controller_authentication/from_cookies.rb +71 -0
  43. data/app/services/stormpath/rails/controller_authentication.rb +44 -0
  44. data/app/services/stormpath/rails/delete_access_token.rb +48 -0
  45. data/app/services/stormpath/rails/delete_refresh_token.rb +11 -0
  46. data/app/services/stormpath/rails/forgot_password_token_verification.rb +31 -0
  47. data/app/services/stormpath/rails/password_change.rb +17 -0
  48. data/app/services/stormpath/rails/refresh_token_authentication.rb +28 -0
  49. data/app/services/stormpath/rails/resend_email_verification.rb +33 -0
  50. data/app/services/stormpath/rails/send_password_reset_email.rb +33 -0
  51. data/app/services/stormpath/rails/token_cookie_setter.rb +84 -0
  52. data/app/services/stormpath/rails/verify_email_token.rb +27 -0
  53. data/app/views/{passwords/forgot_change.html.erb → stormpath/rails/change_password/new.html.erb} +4 -10
  54. data/app/views/{passwords/forgot.html.erb → stormpath/rails/forgot_password/new.html.erb} +14 -4
  55. data/app/views/{layouts → stormpath/rails/layouts}/stormpath.html.erb +3 -3
  56. data/app/views/stormpath/rails/login/_form.html.erb +45 -0
  57. data/app/views/stormpath/rails/login/new.html.erb +12 -0
  58. data/app/views/stormpath/rails/register/_form.html.erb +19 -0
  59. data/app/views/{users → stormpath/rails/register}/new.html.erb +3 -3
  60. data/app/views/stormpath/rails/shared/_input.html.erb +15 -0
  61. data/app/views/stormpath/rails/verify_email/new.html.erb +49 -0
  62. data/bin/console +3 -3
  63. data/bin/rails +1 -1
  64. data/bin/rake +2 -2
  65. data/bin/rspec +2 -2
  66. data/config/initializers/assets.rb +3 -1
  67. data/lib/generators/stormpath/install/install_generator.rb +1 -92
  68. data/lib/generators/stormpath/install/templates/default_config.yml +229 -0
  69. data/lib/generators/stormpath/views/USAGE +0 -0
  70. data/lib/generators/stormpath/views/views_generator.rb +2 -2
  71. data/lib/stormpath/rails/client.rb +8 -85
  72. data/lib/stormpath/rails/config/account_store_verification.rb +45 -0
  73. data/lib/stormpath/rails/config/application_resolution.rb +76 -0
  74. data/lib/stormpath/rails/config/dynamic_configuration.rb +50 -0
  75. data/lib/stormpath/rails/config/read_file.rb +35 -0
  76. data/lib/stormpath/rails/configuration.rb +30 -35
  77. data/lib/stormpath/rails/content_type_negotiator.rb +50 -0
  78. data/lib/stormpath/rails/controller.rb +36 -5
  79. data/lib/stormpath/rails/errors/invalid_sptoken_error.rb +9 -0
  80. data/lib/stormpath/rails/errors/no_sptoken_error.rb +13 -0
  81. data/lib/stormpath/rails/router.rb +75 -0
  82. data/lib/stormpath/rails/routing_constraint.rb +9 -0
  83. data/lib/stormpath/rails/social.rb +6 -6
  84. data/lib/stormpath/rails/version.rb +2 -1
  85. data/lib/stormpath/rails.rb +9 -19
  86. data/lib/stormpath-rails.rb +1 -0
  87. data/stormpath-rails.gemspec +13 -11
  88. metadata +96 -54
  89. data/app/controllers/stormpath/rails/omniauth_controller.rb +0 -11
  90. data/app/controllers/stormpath/rails/passwords_controller.rb +0 -56
  91. data/app/controllers/stormpath/rails/sessions_controller.rb +0 -52
  92. data/app/controllers/stormpath/rails/users_controller.rb +0 -65
  93. data/app/views/passwords/edit.html.erb +0 -0
  94. data/app/views/passwords/email_sent.html.erb +0 -15
  95. data/app/views/passwords/forgot_change_failed.html.erb +0 -14
  96. data/app/views/passwords/forgot_complete.html.erb +0 -19
  97. data/app/views/sessions/_facebook_login_form.erb +0 -31
  98. data/app/views/sessions/_form.html.erb +0 -31
  99. data/app/views/sessions/_google_login_form.html.erb +0 -3
  100. data/app/views/sessions/_social_auth.html.erb +0 -7
  101. data/app/views/sessions/new.html.erb +0 -21
  102. data/app/views/users/_form.html.erb +0 -43
  103. data/app/views/users/verification_complete.html.erb +0 -20
  104. data/app/views/users/verification_email_sent.html.erb +0 -15
  105. data/app/views/users/verification_failed.html.erb +0 -14
  106. data/app/views/users/verification_resend.html.erb +0 -14
  107. data/config/routes.rb +0 -16
  108. data/lib/generators/stormpath/install/templates/db/migrate/add_stormpath_to_users.rb +0 -21
  109. data/lib/generators/stormpath/install/templates/db/migrate/create_users.rb +0 -12
  110. data/lib/generators/stormpath/install/templates/stormpath.rb +0 -4
  111. data/lib/generators/stormpath/install/templates/user.rb +0 -3
  112. data/lib/generators/stormpath/routes/routes_generator.rb +0 -23
  113. data/lib/generators/stormpath/routes/templates/routes.rb +0 -5
  114. data/lib/stormpath/rails/account.rb +0 -6
  115. data/lib/stormpath/rails/account_status.rb +0 -28
  116. data/lib/stormpath/rails/authentication.rb +0 -72
  117. data/lib/stormpath/rails/authentication_status.rb +0 -22
  118. data/lib/stormpath/rails/session.rb +0 -37
  119. data/lib/stormpath/rails/user.rb +0 -25
  120. data/lib/stormpath/rails/user_config/api_key.rb +0 -17
  121. data/lib/stormpath/rails/user_config/application.rb +0 -12
  122. data/lib/stormpath/rails/user_config/facebook.rb +0 -16
  123. data/lib/stormpath/rails/user_config/forgot_password.rb +0 -12
  124. data/lib/stormpath/rails/user_config/google.rb +0 -16
  125. data/lib/stormpath/rails/user_config/id_site.rb +0 -13
  126. data/lib/stormpath/rails/user_config/login.rb +0 -13
  127. data/lib/stormpath/rails/user_config/logout.rb +0 -13
  128. data/lib/stormpath/rails/user_config/register.rb +0 -13
  129. data/lib/stormpath/rails/user_config/verify_email.rb +0 -14
  130. data/lib/stormpath/testing/helpers.rb +0 -49
@@ -0,0 +1,71 @@
1
+ module Stormpath
2
+ module Rails
3
+ class RegistrationFormFields
4
+ PREDEFINED_FIELD_NAMES = [
5
+ :given_name,
6
+ :middle_name,
7
+ :surname,
8
+ :username,
9
+ :email,
10
+ :password,
11
+ :confirm_password
12
+ ].freeze
13
+
14
+ class << self
15
+ def required_field_names
16
+ required_fields.keys
17
+ end
18
+
19
+ def enabled_field_names
20
+ enabled_fields.keys
21
+ end
22
+
23
+ def predefined_enabled_field_names
24
+ enabled_field_names & PREDEFINED_FIELD_NAMES
25
+ end
26
+
27
+ def custom_enabled_field_names
28
+ enabled_field_names - PREDEFINED_FIELD_NAMES
29
+ end
30
+
31
+ def required_fields
32
+ enabled_fields
33
+ .select { |_field, properties| properties[:required] }
34
+ end
35
+
36
+ def enabled_fields
37
+ register_form_fields
38
+ .select { |_field, properties| properties[:enabled] }
39
+ end
40
+
41
+ def confirm_password_enabled?
42
+ form_fields_config.confirm_password.enabled
43
+ end
44
+
45
+ def register_form_fields
46
+ form_fields_config.to_h
47
+ end
48
+
49
+ def given_name_disabled?
50
+ !form_fields_config.given_name.enabled
51
+ end
52
+
53
+ def given_name_not_required?
54
+ !form_fields_config.given_name.required
55
+ end
56
+
57
+ def surname_disabled?
58
+ !form_fields_config.surname.enabled
59
+ end
60
+
61
+ def surname_not_required?
62
+ !form_fields_config.surname.required
63
+ end
64
+
65
+ def form_fields_config
66
+ Stormpath::Rails.config.web.register.form.fields
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,6 +1,7 @@
1
+ # Legacy but will be used when social logins start.
1
2
  module SocialHelper
2
3
  def box_class
3
- facebook_login_enabled? ? 'small col-sm-8' : 'large col-sm-12'
4
+ facebook_login_enabled? ? 'small col-sm-8' : 'large col-sm-12'
4
5
  end
5
6
 
6
7
  def label_class
@@ -0,0 +1,32 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountSerializer
4
+ attr_reader :account
5
+
6
+ def self.to_h(account)
7
+ new(account).to_h
8
+ end
9
+
10
+ def initialize(account)
11
+ @account = account
12
+ end
13
+
14
+ def to_h
15
+ {
16
+ account: {
17
+ href: account.href,
18
+ username: account.username,
19
+ modifiedAt: account.modified_at,
20
+ status: account.status,
21
+ createdAt: account.created_at,
22
+ email: account.email,
23
+ middleName: account.middle_name,
24
+ surname: account.surname,
25
+ givenName: account.given_name,
26
+ fullName: account.full_name
27
+ }
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ module Stormpath
2
+ module Rails
3
+ class FormSerializer
4
+ def self.to_h
5
+ new.to_h
6
+ end
7
+
8
+ def to_h
9
+ {
10
+ form: {
11
+ fields: form_fields
12
+ },
13
+ accountStores: []
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def config
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def form_fields
24
+ config
25
+ .form
26
+ .fields
27
+ .to_h
28
+ .select { |_field, properties| properties[:enabled] && properties[:visible] }
29
+ .each { |_field, properties| properties.delete(:enabled) }
30
+ .each { |_field, properties| properties.delete(:visible) }
31
+ .deep_transform_keys { |key| key.to_s.camelize(:lower).to_sym }
32
+ .sort_by { |field, _properties| config.form.field_order.index(field.to_s) || Float::INFINITY }
33
+ .map { |field, properties| properties.merge(name: field) }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ module Stormpath
2
+ module Rails
3
+ class LoginNewSerializer < FormSerializer
4
+ private
5
+
6
+ def config
7
+ Stormpath::Rails.config.web.login
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,71 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ProfileSerializer
4
+ attr_reader :account_href
5
+
6
+ def self.to_h(account)
7
+ new(account).to_h
8
+ end
9
+
10
+ def initialize(account)
11
+ @account_href = account.href
12
+ end
13
+
14
+ def to_h
15
+ @to_h ||= AccountSerializer.to_h(account).deep_merge(account: expanded_resources_hash)
16
+ end
17
+
18
+ private
19
+
20
+ def expansions
21
+ Stormpath::Rails
22
+ .config
23
+ .web
24
+ .me
25
+ .expand
26
+ .to_h
27
+ .select { |_relation, should_expand| should_expand == true }
28
+ .keys
29
+ end
30
+
31
+ def expansion_resource
32
+ Stormpath::Resource::Expansion.new(*expansions)
33
+ end
34
+
35
+ def expanded_resources_hash
36
+ {}.tap do |hash|
37
+ expansions.each do |expansion|
38
+ expanded_resource = account.send(expansion)
39
+ expansion_name = expansion.to_s.camelize(:lower).to_sym
40
+
41
+ hash[expansion_name] = if expanded_resource.is_a?(Stormpath::Resource::Collection)
42
+ expanded_resource.map do |single_resource|
43
+ properties_serializer(single_resource)
44
+ end
45
+ else
46
+ properties_serializer(expanded_resource)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def properties_serializer(resource)
53
+ resource.send(:materialize)
54
+ properties = resource.properties
55
+
56
+ if resource.is_a?(Stormpath::Resource::CustomData)
57
+ properties
58
+ else
59
+ properties.delete_if { |_key, value| value.is_a?(Hash) }
60
+ properties.transform_keys do |key|
61
+ key.to_s.camelize(:lower).to_sym
62
+ end
63
+ end
64
+ end
65
+
66
+ def account
67
+ @account ||= Stormpath::Rails::Client.client.accounts.get(account_href, expansion_resource)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,11 @@
1
+ module Stormpath
2
+ module Rails
3
+ class RegistrationFormSerializer < FormSerializer
4
+ private
5
+
6
+ def config
7
+ Stormpath::Rails.config.web.register
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountFromAccessToken
4
+ class LocalAccountResolution
5
+ attr_reader :access_token
6
+
7
+ def initialize(access_token)
8
+ @access_token = access_token
9
+ @application = Client.application
10
+ validate_jwt
11
+ end
12
+
13
+ def account
14
+ Stormpath::Rails::Client.client.accounts.get(account_href)
15
+ end
16
+
17
+ private
18
+
19
+ def account_href
20
+ jwt_data.first['sub']
21
+ end
22
+
23
+ def jwt_data
24
+ begin
25
+ @jwt_data ||= JWT.decode(access_token, ENV['STORMPATH_API_KEY_SECRET'])
26
+ rescue JWT::ExpiredSignature
27
+ raise Stormpath::Oauth::Error, :jwt_expired
28
+ end
29
+ end
30
+
31
+ def validate_jwt
32
+ validate_jwt_is_an_access_token
33
+ validate_jwt_has_a_valid_issuer
34
+ end
35
+
36
+ def validate_jwt_has_a_valid_issuer
37
+ return if jwt_data.first['iss'] == Stormpath::Rails::Client.application.href
38
+ raise DifferentIssuerError
39
+ end
40
+
41
+ def validate_jwt_is_an_access_token
42
+ return if jwt_data.second['stt'] == 'access'
43
+ raise AuthenticationWithRefreshTokenAttemptError
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountFromAccessToken
4
+ class StormpathAccountResolution
5
+ attr_reader :access_token, :application
6
+
7
+ def initialize(access_token)
8
+ @access_token = access_token
9
+ @application = Client.application
10
+ validate_jwt_is_access_token
11
+ end
12
+
13
+ def account
14
+ Stormpath::Oauth::VerifyAccessToken.new(application).verify(access_token).account
15
+ end
16
+
17
+ def validate_jwt_is_access_token
18
+ raise AuthenticationWithRefreshTokenAttemptError if jwt_data.second['stt'] != 'access'
19
+ end
20
+
21
+ def jwt_data
22
+ @jwt_data ||= JWT.decode(access_token, ENV['STORMPATH_API_KEY_SECRET'])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountFromAccessToken
4
+ attr_reader :access_token
5
+
6
+ NoAccessToken = Class.new(ArgumentError)
7
+ AuthenticationWithRefreshTokenAttemptError = Class.new(ArgumentError)
8
+ DifferentIssuerError = Class.new(ArgumentError)
9
+
10
+ def initialize(access_token)
11
+ raise(NoAccessToken) if access_token.nil?
12
+ @access_token = access_token
13
+ end
14
+
15
+ def account
16
+ @account ||= resolution_class.new(access_token).account
17
+ end
18
+
19
+ private
20
+
21
+ def resolution_class
22
+ case Stormpath::Rails.config.web.oauth2.password.validation_strategy.to_sym
23
+ when :local
24
+ LocalAccountResolution
25
+ when :stormpath
26
+ StormpathAccountResolution
27
+ else
28
+ raise ArgumentError, 'Invalid validation strategy'
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountLogin
4
+ attr_reader :cookie_jar, :login, :password
5
+
6
+ def self.call(cookie_jar, login, password)
7
+ new(cookie_jar, login, password).call
8
+ end
9
+
10
+ def initialize(cookie_jar, login, password)
11
+ @cookie_jar = cookie_jar
12
+ @login = login
13
+ @password = password
14
+ end
15
+
16
+ def call
17
+ form.save!
18
+ TokenCookieSetter.call(cookie_jar, form.authentication_result)
19
+ end
20
+
21
+ private
22
+
23
+ def form
24
+ @form ||= LoginForm.new(login, password)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ module Stormpath
2
+ module Rails
3
+ class AccountLoginWithStormpathToken
4
+ def self.call(cookie_jar, account, application, api_key)
5
+ new(cookie_jar, account, application, api_key).call
6
+ end
7
+
8
+ def initialize(cookie_jar, account, application, api_key)
9
+ @cookie_jar = cookie_jar
10
+ @account = account
11
+ @application = application
12
+ @api_key = api_key
13
+ end
14
+
15
+ def call
16
+ TokenCookieSetter.call(cookie_jar, authentication_result)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :cookie_jar, :account, :application, :api_key
22
+
23
+ def authentication_result
24
+ @authentication_result ||= application.authenticate_oauth(stormpath_grant_request)
25
+ end
26
+
27
+ def stormpath_grant_request
28
+ Stormpath::Oauth::StormpathGrantRequest.new(account, application, api_key)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ClientCredentialsAuthentication
4
+ include ActiveModel::Model
5
+ BASIC_PATTERN = /^Basic /
6
+ attr_accessor :api_key_id, :api_key_secret
7
+
8
+ class FormError < ArgumentError
9
+ def status
10
+ 401
11
+ end
12
+ end
13
+
14
+ def initialize(authorization_header)
15
+ raise FormError if authorization_header !~ BASIC_PATTERN
16
+
17
+ self.api_key_id, self.api_key_secret = Base64.decode64(
18
+ authorization_header.gsub(BASIC_PATTERN, '')
19
+ ).split(':')
20
+ end
21
+
22
+ validates :api_key_id, presence: true
23
+ validates :api_key_secret, presence: true
24
+
25
+ def save!
26
+ raise(FormError, errors.full_messages.first) if invalid?
27
+ Client.application.authenticate_oauth(client_credentials_grant_request)
28
+ end
29
+
30
+ private
31
+
32
+ def client_credentials_grant_request
33
+ Stormpath::Oauth::ClientCredentialsGrantRequest.new(
34
+ api_key_id,
35
+ api_key_secret
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ControllerAuthentication
4
+ class FromBasicAuth
5
+ attr_reader :authorization_header
6
+
7
+ def initialize(authorization_header)
8
+ @authorization_header = authorization_header
9
+ end
10
+
11
+ def authenticate!
12
+ raise UnauthenticatedRequest if fetched_api_key.nil?
13
+ raise UnauthenticatedRequest if fetched_api_key.secret != api_key_secret
14
+ fetched_api_key.account
15
+ end
16
+
17
+ private
18
+
19
+ def fetched_api_key
20
+ @fetched_api_key ||= Client.application.api_keys.search(id: api_key_id).first
21
+ end
22
+
23
+ def api_key_id
24
+ decoded_authorization_header.first
25
+ end
26
+
27
+ def api_key_secret
28
+ decoded_authorization_header.last
29
+ end
30
+
31
+ def decoded_authorization_header
32
+ @decoded_authorization_header ||= begin
33
+ api_key_and_secret = Base64.decode64(basic_authorization_header).split(':')
34
+ raise UnauthenticatedRequest if api_key_and_secret.count != 2
35
+ api_key_and_secret
36
+ end
37
+ end
38
+
39
+ def basic_authorization_header
40
+ authorization_header.gsub(BASIC_PATTERN, '')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ControllerAuthentication
4
+ class FromBearerAuth
5
+ attr_reader :authorization_header
6
+
7
+ RESCUE_CLASSES = [
8
+ Stormpath::Oauth::Error,
9
+ JWT::DecodeError,
10
+ AccountFromAccessToken::AuthenticationWithRefreshTokenAttemptError,
11
+ AccountFromAccessToken::DifferentIssuerError
12
+ ].freeze
13
+
14
+ def initialize(authorization_header)
15
+ @authorization_header = authorization_header
16
+ end
17
+
18
+ def authenticate!
19
+ begin
20
+ AccountFromAccessToken.new(bearer_access_token).account
21
+ rescue *RESCUE_CLASSES
22
+ raise UnauthenticatedRequest
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def bearer_access_token
29
+ authorization_header.gsub(BEARER_PATTERN, '')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,71 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ControllerAuthentication
4
+ class FromCookies
5
+ OAUTH_ERROR_CODE_RANGE = (10_000...10_100)
6
+
7
+ attr_reader :cookies
8
+
9
+ def initialize(cookies)
10
+ @cookies = cookies
11
+ end
12
+
13
+ def authenticate!
14
+ begin
15
+ AccountFromAccessToken.new(access_token_cookie).account
16
+ rescue AccountFromAccessToken::NoAccessToken, Stormpath::Oauth::Error, JWT::DecodeError
17
+ delete_access_token_cookie
18
+ fetch_account_from_refresh_token
19
+ rescue Stormpath::Error => error
20
+ raise unless OAUTH_ERROR_CODE_RANGE.include?(error.code)
21
+ delete_access_token_cookie
22
+ fetch_account_from_refresh_token
23
+ rescue AccountFromAccessToken::AuthenticationWithRefreshTokenAttemptError, AccountFromAccessToken::DifferentIssuerError
24
+ delete_access_token_cookie
25
+ delete_refresh_token_cookie
26
+ raise UnauthenticatedRequest
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def fetch_account_from_refresh_token
33
+ raise(UnauthenticatedRequest) if refresh_token_cookie.blank?
34
+ begin
35
+ result = RefreshTokenAuthentication.new(refresh_token_cookie).save!
36
+ TokenCookieSetter.new(cookies, result).call
37
+ AccountFromAccessToken.new(result.access_token).account
38
+ rescue Stormpath::Error => error
39
+ raise unless OAUTH_ERROR_CODE_RANGE.include?(error.code)
40
+ delete_refresh_token_cookie
41
+ raise UnauthenticatedRequest
42
+ end
43
+ end
44
+
45
+ def access_token_cookie
46
+ cookies[ACCESS_TOKEN_COOKIE_NAME]
47
+ end
48
+
49
+ def refresh_token_cookie
50
+ cookies[REFRESH_TOKEN_COOKIE_NAME]
51
+ end
52
+
53
+ def access_token_cookie=(value)
54
+ cookies[ACCESS_TOKEN_COOKIE_NAME] = value
55
+ end
56
+
57
+ def refresh_token_cookie=(value)
58
+ cookies[REFRESH_TOKEN_COOKIE_NAME] = value
59
+ end
60
+
61
+ def delete_access_token_cookie
62
+ cookies.delete(ACCESS_TOKEN_COOKIE_NAME)
63
+ end
64
+
65
+ def delete_refresh_token_cookie
66
+ cookies.delete(REFRESH_TOKEN_COOKIE_NAME)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ module Stormpath
2
+ module Rails
3
+ class ControllerAuthentication
4
+ UnauthenticatedRequest = Class.new(StandardError)
5
+ BEARER_PATTERN = /^Bearer /
6
+ BASIC_PATTERN = /^Basic /
7
+ ACCESS_TOKEN_COOKIE_NAME = Stormpath::Rails.config.web.access_token_cookie.name
8
+ REFRESH_TOKEN_COOKIE_NAME = Stormpath::Rails.config.web.refresh_token_cookie.name
9
+
10
+ attr_reader :cookies, :authorization_header
11
+
12
+ def initialize(cookies, authorization_header)
13
+ @cookies = cookies
14
+ @authorization_header = authorization_header
15
+ end
16
+
17
+ def authenticate!
18
+ if any_auth_cookie_present?
19
+ FromCookies.new(cookies).authenticate!
20
+ elsif bearer_authorization_header?
21
+ FromBearerAuth.new(authorization_header).authenticate!
22
+ elsif basic_authorization_header?
23
+ FromBasicAuth.new(authorization_header).authenticate!
24
+ else
25
+ raise UnauthenticatedRequest
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def bearer_authorization_header?
32
+ authorization_header =~ BEARER_PATTERN
33
+ end
34
+
35
+ def any_auth_cookie_present?
36
+ cookies[ACCESS_TOKEN_COOKIE_NAME] || cookies[REFRESH_TOKEN_COOKIE_NAME]
37
+ end
38
+
39
+ def basic_authorization_header?
40
+ authorization_header =~ BASIC_PATTERN
41
+ end
42
+ end
43
+ end
44
+ end