devise-stormpath 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +10 -0
- data/app/controllers/devise/stormpath_passwords_controller.rb +9 -0
- data/config/locales/en.yml +10 -0
- data/devise-stormpath.gemspec +2 -1
- data/lib/devise-stormpath.rb +6 -4
- data/lib/devise/{stormpath/model.rb → models/stormpath_authenticatable.rb} +4 -0
- data/lib/devise/models/stormpath_recoverable.rb +66 -0
- data/lib/devise/stormpath/rails.rb +9 -0
- data/lib/devise/stormpath/routes.rb +8 -0
- data/lib/devise/stormpath/version.rb +1 -1
- data/lib/devise/{stormpath/strategy.rb → strategies/stormpath_authenticatable.rb} +0 -0
- data/spec/devise/{stormpath/model_spec.rb → models/stormpath_authenticatable_spec.rb} +5 -8
- data/spec/devise/models/stormpath_recoverable_spec.rb +42 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/resource_error.rb +2 -0
- metadata +23 -10
data/README.md
CHANGED
@@ -10,3 +10,13 @@ In the Gemfile for your application:
|
|
10
10
|
In devise model:
|
11
11
|
|
12
12
|
devise :stormpath_authenticatable
|
13
|
+
|
14
|
+
Password reset
|
15
|
+
--------------
|
16
|
+
|
17
|
+
Model:
|
18
|
+
|
19
|
+
devise :stormpath_authenticatable, :stormpath_recoverable
|
20
|
+
|
21
|
+
Setup Password Reset Workflow at https://api.stormpath.com
|
22
|
+
Set Base URL to //<app host>/<devise scope>/password/edit (i.e. https://example.com/users/password/edit)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#TODO Customize messages
|
2
|
+
|
3
|
+
en:
|
4
|
+
devise:
|
5
|
+
stormpath_passwords:
|
6
|
+
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
|
7
|
+
updated: 'Your password was changed successfully. You are now signed in.'
|
8
|
+
updated_not_active: 'Your password was changed successfully.'
|
9
|
+
send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
|
10
|
+
no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
|
data/devise-stormpath.gemspec
CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.summary = 'Devise extension to allow authentication via Stormpath'
|
9
9
|
s.email = 'liquidautumn@gmail.com'
|
10
|
+
s.homepage = "http://www.stormpath.com"
|
10
11
|
s.description = s.summary
|
11
12
|
s.author = 'Denis Grankin'
|
12
13
|
|
@@ -16,7 +17,7 @@ Gem::Specification.new do |s|
|
|
16
17
|
s.require_paths = ["lib"]
|
17
18
|
|
18
19
|
s.add_dependency('devise')
|
19
|
-
s.add_dependency('stormpath-rails')
|
20
|
+
s.add_dependency('stormpath-rails', '~> 0.4.0')
|
20
21
|
s.add_dependency('activesupport')
|
21
22
|
|
22
23
|
s.add_development_dependency('rake', '~> 10.0.2')
|
data/lib/devise-stormpath.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
require 'devise'
|
2
1
|
require 'stormpath-rails'
|
3
2
|
|
4
|
-
require 'devise
|
3
|
+
require 'devise'
|
4
|
+
require 'devise/stormpath/routes'
|
5
|
+
require 'devise/stormpath/rails'
|
6
|
+
require 'devise/strategies/stormpath_authenticatable'
|
5
7
|
|
6
8
|
Warden::Strategies.add(:stormpath_authenticatable, Devise::Strategies::StormpathAuthenticatable)
|
7
9
|
|
8
|
-
Devise.add_module(:stormpath_authenticatable,
|
9
|
-
|
10
|
+
Devise.add_module(:stormpath_authenticatable, :route => :session, :strategy => true, :controller => :sessions, :model => 'devise/models/stormpath_authenticatable')
|
11
|
+
Devise.add_module(:stormpath_recoverable, :route => :password, :controller => :stormpath_passwords, :model => 'devise/models/stormpath_recoverable')
|
@@ -5,6 +5,10 @@ module Devise
|
|
5
5
|
module StormpathAuthenticatable
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
+
def self.required_fields(klass)
|
9
|
+
[:current_password, :password, :password_confirmation]
|
10
|
+
end
|
11
|
+
|
8
12
|
included do
|
9
13
|
attr_accessor :password_confirmation, :password
|
10
14
|
attr_reader :current_password
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
module StormpathRecoverable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def self.required_fields(klass)
|
7
|
+
[:reset_password_token, :password, :password_confirmation]
|
8
|
+
end
|
9
|
+
|
10
|
+
included do
|
11
|
+
attr_accessible :reset_password_token, :password_confirmation
|
12
|
+
attr_accessor :reset_password_token
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def after_password_reset
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def send_reset_password_instructions(attributes={})
|
22
|
+
begin
|
23
|
+
identifier = attributes[:email] || attributes[:username]
|
24
|
+
raise RuntimeError.new "Email or username required" unless identifier
|
25
|
+
account = ::Stormpath::Rails::Client.send_password_reset_email(identifier)
|
26
|
+
return self.where(stormpath_url: account.get_href).first
|
27
|
+
rescue RuntimeError => error
|
28
|
+
build_invalid_account(attributes, error)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset_password_by_token(attributes={})
|
33
|
+
begin
|
34
|
+
validate_attributes(attributes)
|
35
|
+
account = ::Stormpath::Rails::Client.verify_password_reset_token(attributes[:reset_password_token])
|
36
|
+
account.set_password attributes[:password]
|
37
|
+
account.save
|
38
|
+
self.where(stormpath_url: account.get_href).first
|
39
|
+
rescue RuntimeError => error
|
40
|
+
build_invalid_account(attributes, error)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_invalid_account(attributes, error)
|
45
|
+
u = self.new(attributes)
|
46
|
+
u.errors[:base] << error.message
|
47
|
+
u
|
48
|
+
end
|
49
|
+
|
50
|
+
#TODO work on better error handling and move strings to locales
|
51
|
+
def validate_attributes(attributes)
|
52
|
+
raise RuntimeError.new "Password reset token required" unless attributes[:reset_password_token]
|
53
|
+
raise RuntimeError.new "Password should match confirmation" unless attributes[:password] == attributes[:password_confirmation]
|
54
|
+
raise RuntimeError.new "Password required" unless attributes[:password] && !attributes[:password].empty?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#mimic default devise recoverable
|
61
|
+
class Mapping
|
62
|
+
def recoverable?
|
63
|
+
@recoverable ||= self.modules.any? { |m| m.to_s =~ /recoverable/ }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
ActionDispatch::Routing::Mapper.class_eval do
|
2
|
+
protected
|
3
|
+
|
4
|
+
def devise_password(mapping, controllers)
|
5
|
+
resource :password, :only => [:new, :create, :edit, :update],
|
6
|
+
:path => mapping.path_names[:password], :controller => controllers[:stormpath_passwords]
|
7
|
+
end
|
8
|
+
end
|
File without changes
|
@@ -1,18 +1,15 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "devise/
|
2
|
+
require "devise/models/stormpath_authenticatable"
|
3
3
|
|
4
|
-
class User
|
5
|
-
include Devise::Models::StormpathAuthenticatable
|
6
|
-
end
|
7
|
-
|
8
|
-
class ResourceError < Exception
|
9
|
-
end
|
10
4
|
|
11
5
|
describe Devise::Models::StormpathAuthenticatable do
|
6
|
+
class User
|
7
|
+
include Devise::Models::StormpathAuthenticatable
|
8
|
+
end
|
12
9
|
|
13
10
|
let(:user) { mock("user") }
|
14
11
|
|
15
|
-
describe "
|
12
|
+
describe "::authenticate_with_stormpath" do
|
16
13
|
it "should return user if authenticated on stormpath and local user exists with returned href" do
|
17
14
|
Stormpath::Rails::Client.should_receive(:authenticate_account).with("username", "password").and_return(mock("account", get_href: "user href"))
|
18
15
|
User.should_receive(:where).with(stormpath_url: "user href").and_return([user])
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "devise/models/stormpath_recoverable"
|
3
|
+
|
4
|
+
describe Devise::Models::StormpathRecoverable do
|
5
|
+
class User
|
6
|
+
def self.attr_accessible(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
include Devise::Models::StormpathRecoverable
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:base) { mock("base") }
|
13
|
+
let(:errors) { mock("errors", :[] => base) }
|
14
|
+
let(:user) { mock("user", errors: errors) }
|
15
|
+
|
16
|
+
describe "::send_reset_password_instructions" do
|
17
|
+
it "should return user if password reset email sent and local user exists with returned href" do
|
18
|
+
Stormpath::Rails::Client.should_receive(:send_password_reset_email).with("john@example.com").and_return(mock("account", get_href: "user href"))
|
19
|
+
User.should_receive(:where).with(stormpath_url: "user href").and_return([user])
|
20
|
+
User.send_reset_password_instructions(email: "john@example.com").should == user
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return errored user instance if no email provided" do
|
24
|
+
Stormpath::Rails::Client.should_receive(:send_password_reset_email).and_raise(ResourceError.new("Error"))
|
25
|
+
User.stub(:new).and_return(user)
|
26
|
+
base.should_receive(:<<).with("Error")
|
27
|
+
User.send_reset_password_instructions(email: "").should == user
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "::reset_password_by_token" do
|
32
|
+
let(:account) { mock("account", get_href: "user href") }
|
33
|
+
|
34
|
+
it "should update password at Stormpath and return user if password reset token is valid" do
|
35
|
+
Stormpath::Rails::Client.should_receive(:verify_password_reset_token).with("token").and_return(account)
|
36
|
+
account.should_receive(:set_password).with("password")
|
37
|
+
account.should_receive(:save)
|
38
|
+
User.should_receive(:where).with(stormpath_url: "user href").and_return([user])
|
39
|
+
User.reset_password_by_token(reset_password_token: "token", password: "password", password_confirmation: "password").should == user
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-stormpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: devise
|
@@ -32,17 +32,17 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: 0.4.0
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 0.4.0
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: activesupport
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,15 +136,22 @@ files:
|
|
136
136
|
- LICENSE
|
137
137
|
- README.md
|
138
138
|
- Rakefile
|
139
|
+
- app/controllers/devise/stormpath_passwords_controller.rb
|
140
|
+
- config/locales/en.yml
|
139
141
|
- devise-stormpath.gemspec
|
140
142
|
- lib/devise-stormpath.rb
|
141
|
-
- lib/devise/
|
142
|
-
- lib/devise/
|
143
|
+
- lib/devise/models/stormpath_authenticatable.rb
|
144
|
+
- lib/devise/models/stormpath_recoverable.rb
|
145
|
+
- lib/devise/stormpath/rails.rb
|
146
|
+
- lib/devise/stormpath/routes.rb
|
143
147
|
- lib/devise/stormpath/version.rb
|
144
|
-
-
|
148
|
+
- lib/devise/strategies/stormpath_authenticatable.rb
|
149
|
+
- spec/devise/models/stormpath_authenticatable_spec.rb
|
150
|
+
- spec/devise/models/stormpath_recoverable_spec.rb
|
145
151
|
- spec/spec_helper.rb
|
146
152
|
- spec/support/client.rb
|
147
|
-
|
153
|
+
- spec/support/resource_error.rb
|
154
|
+
homepage: http://www.stormpath.com
|
148
155
|
licenses: []
|
149
156
|
post_install_message:
|
150
157
|
rdoc_options: []
|
@@ -156,12 +163,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
163
|
- - ! '>='
|
157
164
|
- !ruby/object:Gem::Version
|
158
165
|
version: '0'
|
166
|
+
segments:
|
167
|
+
- 0
|
168
|
+
hash: 434371363033819234
|
159
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
170
|
none: false
|
161
171
|
requirements:
|
162
172
|
- - ! '>='
|
163
173
|
- !ruby/object:Gem::Version
|
164
174
|
version: '0'
|
175
|
+
segments:
|
176
|
+
- 0
|
177
|
+
hash: 434371363033819234
|
165
178
|
requirements: []
|
166
179
|
rubyforge_project:
|
167
180
|
rubygems_version: 1.8.24
|