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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -1
- data/.rubocop.yml +22 -0
- data/.travis.yml +6 -3
- data/Gemfile +10 -3
- data/README.md +139 -142
- data/Rakefile +9 -9
- data/app/assets/stylesheets/stormpath.css.scss +3 -2
- data/app/controllers/stormpath/rails/base_controller.rb +25 -6
- data/app/controllers/stormpath/rails/change_password/create_controller.rb +68 -0
- data/app/controllers/stormpath/rails/change_password/new_controller.rb +38 -0
- data/app/controllers/stormpath/rails/forgot_password/create_controller.rb +37 -0
- data/app/controllers/stormpath/rails/forgot_password/new_controller.rb +14 -0
- data/app/controllers/stormpath/rails/login/create_controller.rb +60 -0
- data/app/controllers/stormpath/rails/login/new_controller.rb +20 -0
- data/app/controllers/stormpath/rails/logout/create_controller.rb +61 -0
- data/app/controllers/stormpath/rails/oauth2/create_controller.rb +82 -0
- data/app/controllers/stormpath/rails/oauth2/new_controller.rb +11 -0
- data/app/controllers/stormpath/rails/profile/show_controller.rb +15 -0
- data/app/controllers/stormpath/rails/register/create_controller.rb +86 -0
- data/app/controllers/stormpath/rails/register/new_controller.rb +20 -0
- data/app/controllers/stormpath/rails/verify_email/create_controller.rb +37 -0
- data/app/controllers/stormpath/rails/verify_email/show_controller.rb +51 -0
- data/app/forms/stormpath/rails/login_form.rb +60 -0
- data/app/forms/stormpath/rails/registration_form.rb +106 -0
- data/app/forms/stormpath/rails/registration_form_fields.rb +71 -0
- data/app/helpers/social_helper.rb +2 -1
- data/app/serializers/stormpath/rails/account_serializer.rb +32 -0
- data/app/serializers/stormpath/rails/form_serializer.rb +37 -0
- data/app/serializers/stormpath/rails/login_new_serializer.rb +11 -0
- data/app/serializers/stormpath/rails/profile_serializer.rb +71 -0
- data/app/serializers/stormpath/rails/registration_form_serializer.rb +11 -0
- data/app/services/stormpath/rails/account_from_access_token/local_account_resolution.rb +48 -0
- data/app/services/stormpath/rails/account_from_access_token/stormpath_account_resolution.rb +27 -0
- data/app/services/stormpath/rails/account_from_access_token.rb +33 -0
- data/app/services/stormpath/rails/account_login.rb +28 -0
- data/app/services/stormpath/rails/account_login_with_stormpath_token.rb +32 -0
- data/app/services/stormpath/rails/client_credentials_authentication.rb +40 -0
- data/app/services/stormpath/rails/controller_authentication/from_basic_auth.rb +45 -0
- data/app/services/stormpath/rails/controller_authentication/from_bearer_auth.rb +34 -0
- data/app/services/stormpath/rails/controller_authentication/from_cookies.rb +71 -0
- data/app/services/stormpath/rails/controller_authentication.rb +44 -0
- data/app/services/stormpath/rails/delete_access_token.rb +48 -0
- data/app/services/stormpath/rails/delete_refresh_token.rb +11 -0
- data/app/services/stormpath/rails/forgot_password_token_verification.rb +31 -0
- data/app/services/stormpath/rails/password_change.rb +17 -0
- data/app/services/stormpath/rails/refresh_token_authentication.rb +28 -0
- data/app/services/stormpath/rails/resend_email_verification.rb +33 -0
- data/app/services/stormpath/rails/send_password_reset_email.rb +33 -0
- data/app/services/stormpath/rails/token_cookie_setter.rb +84 -0
- data/app/services/stormpath/rails/verify_email_token.rb +27 -0
- data/app/views/{passwords/forgot_change.html.erb → stormpath/rails/change_password/new.html.erb} +4 -10
- data/app/views/{passwords/forgot.html.erb → stormpath/rails/forgot_password/new.html.erb} +14 -4
- data/app/views/{layouts → stormpath/rails/layouts}/stormpath.html.erb +3 -3
- data/app/views/stormpath/rails/login/_form.html.erb +45 -0
- data/app/views/stormpath/rails/login/new.html.erb +12 -0
- data/app/views/stormpath/rails/register/_form.html.erb +19 -0
- data/app/views/{users → stormpath/rails/register}/new.html.erb +3 -3
- data/app/views/stormpath/rails/shared/_input.html.erb +15 -0
- data/app/views/stormpath/rails/verify_email/new.html.erb +49 -0
- data/bin/console +3 -3
- data/bin/rails +1 -1
- data/bin/rake +2 -2
- data/bin/rspec +2 -2
- data/config/initializers/assets.rb +3 -1
- data/lib/generators/stormpath/install/install_generator.rb +1 -92
- data/lib/generators/stormpath/install/templates/default_config.yml +229 -0
- data/lib/generators/stormpath/views/USAGE +0 -0
- data/lib/generators/stormpath/views/views_generator.rb +2 -2
- data/lib/stormpath/rails/client.rb +8 -85
- data/lib/stormpath/rails/config/account_store_verification.rb +45 -0
- data/lib/stormpath/rails/config/application_resolution.rb +76 -0
- data/lib/stormpath/rails/config/dynamic_configuration.rb +50 -0
- data/lib/stormpath/rails/config/read_file.rb +35 -0
- data/lib/stormpath/rails/configuration.rb +30 -35
- data/lib/stormpath/rails/content_type_negotiator.rb +50 -0
- data/lib/stormpath/rails/controller.rb +36 -5
- data/lib/stormpath/rails/errors/invalid_sptoken_error.rb +9 -0
- data/lib/stormpath/rails/errors/no_sptoken_error.rb +13 -0
- data/lib/stormpath/rails/router.rb +75 -0
- data/lib/stormpath/rails/routing_constraint.rb +9 -0
- data/lib/stormpath/rails/social.rb +6 -6
- data/lib/stormpath/rails/version.rb +2 -1
- data/lib/stormpath/rails.rb +9 -19
- data/lib/stormpath-rails.rb +1 -0
- data/stormpath-rails.gemspec +13 -11
- metadata +96 -54
- data/app/controllers/stormpath/rails/omniauth_controller.rb +0 -11
- data/app/controllers/stormpath/rails/passwords_controller.rb +0 -56
- data/app/controllers/stormpath/rails/sessions_controller.rb +0 -52
- data/app/controllers/stormpath/rails/users_controller.rb +0 -65
- data/app/views/passwords/edit.html.erb +0 -0
- data/app/views/passwords/email_sent.html.erb +0 -15
- data/app/views/passwords/forgot_change_failed.html.erb +0 -14
- data/app/views/passwords/forgot_complete.html.erb +0 -19
- data/app/views/sessions/_facebook_login_form.erb +0 -31
- data/app/views/sessions/_form.html.erb +0 -31
- data/app/views/sessions/_google_login_form.html.erb +0 -3
- data/app/views/sessions/_social_auth.html.erb +0 -7
- data/app/views/sessions/new.html.erb +0 -21
- data/app/views/users/_form.html.erb +0 -43
- data/app/views/users/verification_complete.html.erb +0 -20
- data/app/views/users/verification_email_sent.html.erb +0 -15
- data/app/views/users/verification_failed.html.erb +0 -14
- data/app/views/users/verification_resend.html.erb +0 -14
- data/config/routes.rb +0 -16
- data/lib/generators/stormpath/install/templates/db/migrate/add_stormpath_to_users.rb +0 -21
- data/lib/generators/stormpath/install/templates/db/migrate/create_users.rb +0 -12
- data/lib/generators/stormpath/install/templates/stormpath.rb +0 -4
- data/lib/generators/stormpath/install/templates/user.rb +0 -3
- data/lib/generators/stormpath/routes/routes_generator.rb +0 -23
- data/lib/generators/stormpath/routes/templates/routes.rb +0 -5
- data/lib/stormpath/rails/account.rb +0 -6
- data/lib/stormpath/rails/account_status.rb +0 -28
- data/lib/stormpath/rails/authentication.rb +0 -72
- data/lib/stormpath/rails/authentication_status.rb +0 -22
- data/lib/stormpath/rails/session.rb +0 -37
- data/lib/stormpath/rails/user.rb +0 -25
- data/lib/stormpath/rails/user_config/api_key.rb +0 -17
- data/lib/stormpath/rails/user_config/application.rb +0 -12
- data/lib/stormpath/rails/user_config/facebook.rb +0 -16
- data/lib/stormpath/rails/user_config/forgot_password.rb +0 -12
- data/lib/stormpath/rails/user_config/google.rb +0 -16
- data/lib/stormpath/rails/user_config/id_site.rb +0 -13
- data/lib/stormpath/rails/user_config/login.rb +0 -13
- data/lib/stormpath/rails/user_config/logout.rb +0 -13
- data/lib/stormpath/rails/user_config/register.rb +0 -13
- data/lib/stormpath/rails/user_config/verify_email.rb +0 -14
- 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
|
|
@@ -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,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,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
|