stormpath-rails 0.4.4 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ spec/reports
17
17
  test/tmp
18
18
  test/version_tmp
19
19
  tmp/
20
+ spec/fixtures/vcr_cassettes
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ stormpath-rails
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p429
data/.travis.yml CHANGED
@@ -1,8 +1,27 @@
1
+ ---
1
2
  language: ruby
2
3
  rvm:
3
- - 1.9.3
4
+ - 1.9.3
4
5
  gemfile:
5
- - Gemfile
6
+ - Gemfile
6
7
  script: bundle exec rake spec
7
8
  services:
8
- - mongodb
9
+ - mongodb
10
+ env:
11
+ global:
12
+ - secure: |-
13
+ TFLI7BpxBBSoVV5x/tyr1iCqcQHcbzJeQPSR67J32VWbMDjM3mA9mz4SERvK
14
+ j9VD7pEAknEBNpYUYdBR4Ut0m5/0F+XiX1eDOVMbfpmEefJ8e38CgGz7HZbu
15
+ KdaWJhxTL8k/efyvJ+/UVPyzM4M0ADdyZIoDCDgRhj6AG5DqDJs=
16
+ - secure: |-
17
+ eu8VkY1iR5RYHvOobDQ7Miz8aG894F/BR/zEH8c3gpIhs7kItkBy0SKEMi5J
18
+ A1yMlQsONU7aq6pbqiJEiBKSDWf9OOoFBxHYm46fop+xaLVLuuK484O9VzDW
19
+ P6lV6Z06LolZaZsc2ENKf+2qfoO1XdN9gMTWD7QkT4x6OgRWiok=
20
+ - secure: |-
21
+ fMUOQUfUNkEDWmx5d4vIMIbqTuHIX1lu1PmbUnR25hHN9JFZnroxSvsvUlvH
22
+ qB+GCk5q7kMuvqYC+Mbx0Ndb3NSuLSKYGYhHw/39ZyMPHgBhPKQyZuDiK3OJ
23
+ g3Pv8Ot3lScgATu1lm5EzoGfN3ZVlSgmg5PJOwsafVaRlAUaHz4=
24
+ - secure: |-
25
+ UDTunvFjUyTaLHPa3iNOVwdAg37FzfKHRYdOiUoPH3aNA6pOgrtQYzkbhbJA
26
+ chBcZBdD+SnEyY6PmI1NsLzcNrqBP3tdyH4c5vVy3KQAzc5TfU6RocWTrqRP
27
+ FQKm/r0cbpjdydkpEzOKMk77Y56g6MTEk5cGFZjYoqhGKdz66O0=
data/CHANGES.md ADDED
@@ -0,0 +1,11 @@
1
+ stormpath-rails Changelog
2
+ =========================
3
+
4
+ Version 1.0.0.beta
5
+ ------------------
6
+
7
+ Released on June 12, 2013
8
+
9
+ - Removed YML-generator in favor of reading APPLICATION_URL from ENV
10
+ - Allow flexible configuration of API key information (same as SDK client)
11
+ - Using new SDK (1.0.0.beta) API
data/README.md CHANGED
@@ -1,36 +1,88 @@
1
1
  [![Build Status](https://secure.travis-ci.org/stormpath/stormpath-rails.png)](http://travis-ci.org/stormpath/stormpath-rails)
2
2
  [![Code Climate](https://codeclimate.com/github/stormpath/stormpath-rails.png)](https://codeclimate.com/github/stormpath/stormpath-rails)
3
+ # Stormpath Rails Gem
3
4
 
4
- # Ruby on Rails support for Stormpath
5
+ Stormpath is the first easy, secure user management and authentication service for developers.
6
+ This is the Rails gem to ease integration of its features with any Rails-based application.
5
7
 
6
- ## Gem Setup
8
+ ## Setup
7
9
 
8
- Reference gem from Gemfile.
10
+ 1. Install the <code>stormpath-rails</code> gem, either via the command line:
9
11
 
10
- ```ruby
11
- add gem 'stormpath-rails' to Gemfile
12
- ```
12
+ ```
13
+ $ gem install stormpath-rails
14
+ ```
13
15
 
14
- Generate configuration file, then create directory per environment at stormpath and update stormpath.yml with corresponding directory hrefs.
16
+ or adding the gem to your [Bundler][bundler] Gemspec:
15
17
 
16
- ```sh
17
- rails g stormpath:rails:install
18
- ```
18
+ ```
19
+ gem 'stormpath-rails'
20
+ ```
21
+
22
+ or any other preferred dependency.
23
+
24
+ 2. Create a [Stormpath][stormpath] developer account and [create your API Keys][create-api-keys]
25
+ downloading the <code>apiKey.properties</code> file into a <code>.stormpath</code>
26
+ folder under your local home directory. So that the Rails gem knows where to find this file,
27
+ add an environment variable called STORMPATH\_API\_KEY\_FILE\_LOCATION whose value is the full
28
+ path to this new .properties file:
29
+
30
+ ```sh
31
+ export STORMPATH_API_KEY_FILE_LOCATION="/Users/john/.stormpath/apiKey.properties"
32
+ ```
19
33
 
34
+ 3. Create an application and a directory to store your users' accounts through the
35
+ [Stormpath Admin][stormpath-admin] interface. Make sure to add the newly-created
36
+ directory as a Login Source for your newly-created Application.
20
37
 
21
- Generate and run migration, if you're on ActiveRecord. Skip this step for Mongoid.
38
+ 4. Through the [Stormpath Admin][stormpath-admin] interface, note your application's REST URL.
39
+ You'll want to create an environment variable called STORMPATH\_APPLICATION\_URL whose value
40
+ is this URL.
41
+
42
+ 5. Generate and run migration, if you're on ActiveRecord. Skip this step for Mongoid.
43
+ ```sh
44
+ rails g stormpath:rails:migration user
45
+ rake db:migrate
46
+ ```
47
+
48
+ 6. Update your model file.
49
+ ```ruby
50
+ class User < ActiveRecord:Base
51
+ include Stormpath::Rails::Account
52
+ end
53
+ ```
54
+
55
+ ## Testing
56
+
57
+ To run the test suite, simple run:
22
58
 
23
59
  ```sh
24
- rails g stormpath:rails:migration user
25
- rake db:migrate
60
+ $ rake spec
26
61
  ```
27
62
 
28
- Update your model file.
63
+ Note that this will make requests to the Stormpath API; you'll need to have set
64
+ environment variables enabling the client to interact with your Stormpath
65
+ account. You'll also need to have environment variables set that will enable
66
+ the client to interact with a test directory and application.
67
+
68
+ The test run will also generate a code-coverage report, viewable in the
69
+ coverage subdirectory.
70
+
71
+ ## Contributing
72
+
73
+ You can make your own contributions by forking the <code>development</code>
74
+ branch, making your changes, and issuing pull-requests on the
75
+ <code>development</code> branch.
76
+
77
+ ## Building the Gem
78
+
79
+ To build and install the development branch yourself from the latest source:
29
80
 
30
- ```ruby
31
- class User < ActiveRecord:Base
32
- include Stormpath::Rails::Account
33
- end
81
+ ```
82
+ $ git clone git@github.com:stormpath/stormpath-rails.git
83
+ $ cd stormpath-rails
84
+ $ rake gem
85
+ $ gem install pkg/stormpath-rails-{version}.gem
34
86
  ```
35
87
 
36
88
  ## TODO
@@ -40,10 +92,16 @@ end
40
92
  + Preventive validation to not send invalid data to stormpath.
41
93
  + Solve n+1 request problem when requesting account collection.
42
94
 
43
- ## Contributing
95
+ ## Copyright & Licensing
96
+
97
+ Copyright &copy; 2012 Stormpath, Inc. and contributors.
98
+
99
+ This project is licensed under the [Apache 2.0 Open Source License](http://www.apache.org/licenses/LICENSE-2.0).
100
+
101
+ For additional information, please see the full [Project Documentation](https://www.stormpath.com/docs/ruby/product-guide).
44
102
 
45
- 1. Fork it
46
- 2. Create your feature branch (`git checkout -b my-new-feature`)
47
- 3. Commit your changes (`git commit -am 'Add some feature'`)
48
- 4. Push to the branch (`git push origin my-new-feature`)
49
- 5. Create new Pull Request
103
+ [bundler]: http://gembundler.com/
104
+ [stormpath]: http://stormpath.com/
105
+ [create-api-keys]: http://www.stormpath.com/docs/ruby/product-guide#AssignAPIkeys
106
+ [stormpath_bootstrap]: https://github.com/stormpath/stormpath-sdk-ruby/wiki/Bootstrapping-Stormpath
107
+ [stormpath-admin]: https://api.stormpath.com/login
@@ -1,7 +1,5 @@
1
1
  require 'active_support/concern'
2
2
  require "stormpath-sdk"
3
- include Stormpath::Client
4
- include Stormpath::Resource
5
3
 
6
4
  module Stormpath
7
5
  module Rails
@@ -10,6 +8,28 @@ module Stormpath
10
8
 
11
9
  STORMPATH_FIELDS = [ :email, :password, :username, :given_name, :middle_name, :surname, :status ]
12
10
 
11
+ module ClassMethods
12
+ def authenticate username, password
13
+ account = Stormpath::Rails::Client.authenticate_account username, password
14
+ self.where(stormpath_url: account.href).first
15
+ end
16
+
17
+ def send_password_reset_email email
18
+ account = Stormpath::Rails::Client.send_password_reset_email email
19
+ self.where(stormpath_url: account.href).first
20
+ end
21
+
22
+ def verify_password_reset_token token
23
+ account = Stormpath::Rails::Client.verify_password_reset_token token
24
+ self.where(stormpath_url: account.href).first
25
+ end
26
+
27
+ def verify_account_email token
28
+ account = Stormpath::Rails::Client.verify_account_email token
29
+ self.where(stormpath_url: account.href).first
30
+ end
31
+ end
32
+
13
33
  included do
14
34
  #AR specific workaround
15
35
  self.partial_updates = false if self.respond_to?(:partial_updates)
@@ -18,48 +38,83 @@ module Stormpath
18
38
  field(:stormpath_url, type: String) if self.respond_to?(:field)
19
39
  index({ stormpath_url: 1 }, { unique: true }) if self.respond_to?(:index)
20
40
 
21
- attr_accessor *STORMPATH_FIELDS
22
- attr_accessible *STORMPATH_FIELDS
41
+ attr_accessor(*STORMPATH_FIELDS)
42
+ attr_accessible(*STORMPATH_FIELDS)
23
43
 
24
- after_initialize do |user|
25
- return true unless user.stormpath_url
26
- begin
27
- account = Client.find_account(user.stormpath_url)
28
- (STORMPATH_FIELDS - [:password]).each { |field| self.send("#{field}=", account.send("get_#{field}")) }
29
- rescue ResourceError => error
30
- Logger.new(STDERR).warn "Error loading Stormpath account (#{error})"
44
+ before_create :create_account_on_stormpath
45
+ before_update :update_account_on_stormpath
46
+ after_destroy :delete_account_on_stormpath
47
+
48
+ def stormpath_account
49
+ if stormpath_url
50
+ @stormpath_account ||= begin
51
+ Stormpath::Rails::Client.find_account(stormpath_url)
52
+ rescue Stormpath::Error => error
53
+ Stormpath::Rails.logger.warn "Error loading Stormpath account (#{error})"
54
+ end
31
55
  end
32
56
  end
33
57
 
34
- before_create do
35
- begin
36
- account = Stormpath::Rails::Client.create_account!(Hash[*STORMPATH_FIELDS.map { |f| { f => self.send(f) } }.map(&:to_a).flatten])
37
- rescue ResourceError => error
38
- self.errors[:base] << error.to_s
39
- return false
58
+ def stormpath_pre_create_attrs
59
+ @stormpath_pre_create_attrs ||= {}
60
+ end
61
+
62
+ (STORMPATH_FIELDS - [:password]).each do |name|
63
+ define_method(name) do
64
+ if stormpath_account.present?
65
+ stormpath_account.send(name)
66
+ else
67
+ stormpath_pre_create_attrs[name]
68
+ end
40
69
  end
41
- self.stormpath_url = account.get_href
42
70
  end
43
71
 
44
- before_update do
45
- return true unless self.stormpath_url
72
+ STORMPATH_FIELDS.each do |name|
73
+ define_method("#{name}=") do |val|
74
+ if stormpath_account.present?
75
+ stormpath_account.send("#{name}=", val)
76
+ else
77
+ stormpath_pre_create_attrs[name] = val
78
+ end
79
+ end
80
+ end
81
+
82
+ def create_account_on_stormpath
46
83
  begin
47
- Client.update_account!(self.stormpath_url, Hash[*STORMPATH_FIELDS.map { |f| { f => self.send(f) } }.map(&:to_a).flatten])
48
- rescue ResourceError => error
84
+ @stormpath_account = Stormpath::Rails::Client.create_account! stormpath_pre_create_attrs
85
+ stormpath_pre_create_attrs.clear
86
+ self.stormpath_url = @stormpath_account.href
87
+ rescue Stormpath::Error => error
49
88
  self.errors[:base] << error.to_s
50
- return false
89
+ false
51
90
  end
52
91
  end
53
92
 
54
- after_destroy do
55
- return true unless self.stormpath_url
56
- begin
57
- account = Client.delete_account!(self.stormpath_url)
58
- rescue ResourceError => error
59
- Logger.new(STDERR).warn "Error destroying Stormpath account (#{error})"
93
+ def update_account_on_stormpath
94
+ if self.stormpath_url.present?
95
+ begin
96
+ stormpath_account.save
97
+ rescue Stormpath::Error => error
98
+ self.errors[:base] << error.to_s
99
+ false
100
+ end
101
+ else
102
+ true
103
+ end
104
+ end
105
+
106
+ def delete_account_on_stormpath
107
+ if self.stormpath_url.present?
108
+ begin
109
+ stormpath_account.delete
110
+ rescue Stormpath::Error => error
111
+ Stormpath::Rails.logger.warn "Error destroying Stormpath account (#{error})"
112
+ end
113
+ else
114
+ true
60
115
  end
61
116
  end
62
117
  end
63
118
  end
64
119
  end
65
- end
120
+ end
@@ -1,70 +1,99 @@
1
1
  require "stormpath-sdk"
2
- include Stormpath::Client
3
- include Stormpath::Resource
4
- include Stormpath::Authentication
5
2
 
6
3
  module Stormpath
7
4
  module Rails
5
+ class ConfigurationError < StandardError; end
6
+
8
7
  class Client
9
8
  class << self
10
- attr_accessor :connection
9
+ attr_accessor :connection, :root_application
11
10
  end
12
11
 
13
- def self.authenticate_account(login, password)
14
- application = self.ds.get_resource Config[:stormpath_url], ::Application
15
- auth_result = application.authenticate_account ::UsernamePasswordRequest.new(login, password)
16
- auth_result.get_account
12
+ def self.authenticate_account(username, password)
13
+ auth_result = application.authenticate_account(
14
+ Stormpath::Authentication::UsernamePasswordRequest.new(username, password)
15
+ )
16
+ auth_result.account
17
17
  end
18
18
 
19
- def self.send_password_reset_email(login_or_email)
20
- application = self.ds.get_resource Config[:stormpath_url], ::Application
21
- application.send_password_reset_email login_or_email
19
+ def self.send_password_reset_email(email)
20
+ application.send_password_reset_email email
22
21
  end
23
22
 
24
23
  def self.verify_password_reset_token(token)
25
- application = self.ds.get_resource Config[:stormpath_url], ::Application
26
24
  application.verify_password_reset_token token
27
25
  end
28
26
 
29
27
  def self.verify_account_email(token)
30
- self.client.current_tenant.verify_account_email token
28
+ self.client.accounts.verify_email_token token
31
29
  end
32
30
 
33
31
  def self.create_account!(attributes)
34
- account = self.ds.instantiate ::Account
35
- attributes.each { |field, value| account.send("set_#{field}", value) }
36
- self.root_directory.create_account account
32
+ self.application.accounts.create attributes
37
33
  end
38
34
 
39
35
  def self.all_accounts
40
- self.root_directory.get_accounts
36
+ self.application.accounts
41
37
  end
42
38
 
43
39
  def self.find_account(href)
44
- self.ds.get_resource href, ::Account
40
+ self.client.accounts.get href
45
41
  end
46
42
 
47
43
  def self.update_account!(href, attributes)
48
- account = self.ds.get_resource href, ::Account
49
- attributes.each { |field, value| account.send("set_#{field}", value) }
44
+ account = self.find_account href
45
+ attributes.each { |field, value| account.send("#{field}=", value) }
50
46
  account.save
51
47
  end
52
48
 
53
49
  def self.delete_account!(href)
54
- self.ds.delete self.ds.get_resource href, ::Account
55
- end
56
-
57
- def self.root_directory
58
- self.ds.get_resource Config[:root], ::Directory
50
+ self.client.accounts.get(href).delete
59
51
  end
60
52
 
61
53
  def self.ds
62
54
  self.client.data_store
63
55
  end
64
56
 
57
+ def self.application
58
+ self.root_application ||= self.client.applications.get ENV["STORMPATH_APPLICATION_URL"]
59
+ end
60
+
65
61
  def self.client
66
- self.connection ||= ::ClientApplicationBuilder.new.set_application_href(Config[:stormpath_url] || Config[:href]).build
67
- self.connection.client
62
+ unless self.connection
63
+ if ENV['STORMPATH_URL'].nil? && ENV['STORMPATH_APPLICATION_URL'].nil?
64
+ raise ConfigurationError, 'Either STORMPATH_URL or STORMPATH_APPLICATION_URL must be set'
65
+ end
66
+
67
+ composite_url = ENV['STORMPATH_URL']
68
+
69
+ if composite_url
70
+ self.root_application = Stormpath::Resource::Application.load composite_url
71
+ self.connection = self.root_application.client
72
+ else
73
+ self.connection = Stormpath::Client.new client_options
74
+ end
75
+ end
76
+
77
+ self.connection
78
+ end
79
+
80
+ def self.client_options
81
+ Hash.new.tap do |o|
82
+ set_if_not_empty(o, "api_key_file_location", ENV["STORMPATH_API_KEY_FILE_LOCATION"])
83
+ set_if_not_empty(o, "api_key_id_property_name", ENV["STORMPATH_API_KEY_ID_PROPERTY_NAME"])
84
+ set_if_not_empty(o, "api_key_secret_property_name", ENV["STORMPATH_API_KEY_SECRET_PROPERTY_NAME"])
85
+
86
+ o[:api_key] = {
87
+ id: ENV["STORMPATH_API_KEY_ID"],
88
+ secret: ENV["STORMPATH_API_KEY_SECRET"]
89
+ } unless ENV["STORMPATH_API_KEY_ID"].blank? or ENV["STORMPATH_API_KEY_SECRET"].blank?
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def self.set_if_not_empty(object, property, value)
96
+ object[property.to_sym] = value unless value.blank?
68
97
  end
69
98
  end
70
99
  end