devise_oauth 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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Yury Korolev
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Devise::Oauth
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Devise::Oauth'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
@@ -0,0 +1,183 @@
1
+ class Devise::Oauth::AccessTokensController < ApplicationController
2
+
3
+ include Devise::Oauth::Helpers
4
+
5
+ # create access_token flows
6
+ cattr_accessor :flows
7
+ @@flows = {
8
+ ## section 4.1.3 (authorization code flow)
9
+ authorization_code: [
10
+ :find_auth_by_code,
11
+ :normalize_scope,
12
+ :access_blocked?,
13
+ :create_token_from_auth
14
+ ],
15
+
16
+ ## section 4.3.2 (Resource Owner Password Credentials flow)
17
+ password: [
18
+ :authenticate_resource_owner,
19
+ :normalize_scope,
20
+ :access_blocked?,
21
+ :create_token
22
+ ],
23
+ # section 6.0 (refresh token)
24
+ refresh_token: [
25
+ :find_refresh_token,
26
+ :normalize_scope,
27
+ :access_blocked?,
28
+ :create_token_from_refresh
29
+ ]
30
+ }
31
+
32
+ ## common flow
33
+ before_filter :find_client, only: :create
34
+ before_filter :client_blocked?, only: :create
35
+ before_filter :find_grant_type, only: :create
36
+ before_filter :execute_flow, only: :create
37
+
38
+ def create
39
+ render json: @token_response
40
+ @authorization.used! if @authorization
41
+ end
42
+
43
+ def destroy
44
+ end
45
+
46
+ private
47
+
48
+ def find_client
49
+ client_id, client_secret = request.authorization ?
50
+ decode_credentials : [params[:client_id], params[:client_secret]]
51
+
52
+ if client_id.blank? || client_secret.blank?
53
+ return invalid_request
54
+ end
55
+
56
+ @client = Devise::Oauth::Client.where(identifier: client_id).first
57
+
58
+ return client_not_found if @client.blank? || @client.secret != client_secret
59
+ end
60
+
61
+
62
+ def find_grant_type
63
+ @grant_type = case params[:grant_type]
64
+ when "authorization_code"
65
+ :authorization_code
66
+ when "password"
67
+ :password
68
+ when "refresh_token"
69
+ :refresh_token
70
+ when "client_credentials"
71
+ :client_credentials
72
+ else
73
+ :unsupported
74
+ end
75
+
76
+ return invalid_grant_type(params[:grant_type]) if !Devise::Oauth.supported_grant_types.include?(@grant_type)
77
+ end
78
+
79
+ def execute_flow
80
+ flow = self.class.flows[@grant_type]
81
+ flow.each do |method|
82
+ break if response_body
83
+ send(method)
84
+ end
85
+ end
86
+
87
+ def resource_owner_credentials_flow?
88
+ @grant_type == :password
89
+ end
90
+
91
+ # tokens responses
92
+
93
+ def create_token_from_auth
94
+ @token_response = @authorization.create_access_token.token_response
95
+ end
96
+
97
+ def create_token_from_refresh
98
+ @token_response = @refresh_token.refresh!
99
+ end
100
+
101
+ def create_token
102
+ @token_response = Devise::Oauth::AccessToken.create(client: @client, resource_owner: @resource_owner, scope: @scope).token_response
103
+ end
104
+
105
+ def find_auth_by_code
106
+ code = params[:code]
107
+
108
+ @authorization = @client.authorizations.where(code: code).first
109
+ return auth_not_found if @authorization.blank?
110
+ return access_denied if @authorization.used?
111
+ return invalid_request if !@authorization.valid_redirect_uri?(params[:redirect_uri])
112
+ return auth_expired if @authorization.expired?
113
+ @resource_owner = @authorization.resource_owner
114
+ end
115
+
116
+ def find_refresh_token
117
+ refresh_token = params[:refresh_token]
118
+
119
+ return invalid_request if refresh_token.blank?
120
+
121
+ @refresh_token = @client.access_tokens.where(refresh_token: params[:refresh_token]).first
122
+
123
+ return invalid_request if @refresh_token.blank?
124
+ @resource_owner = @refresh_token.resource_owner
125
+ end
126
+
127
+ def authenticate_resource_owner
128
+ owner_class = Devise::Oauth.resource_owner.constantize
129
+ owner = owner_class.find_for_authentication(owner_class.authentication_keys.first => params[:username])
130
+ if owner && owner.valid_password?(params[:password])
131
+ @resource_owner = owner
132
+ else
133
+ invalid_request
134
+ end
135
+ end
136
+
137
+
138
+
139
+ # errors
140
+
141
+ def auth_not_found
142
+ render_error :unprocessable_entity, error: "invalid_request", error_description: "Authorization not found"
143
+ end
144
+
145
+ def auth_expired
146
+ render_error :unprocessable_entity, error: "invalid_request", error_description: "Authorization expired"
147
+ end
148
+
149
+ def client_not_found
150
+ render_error :unprocessable_entity, error: "invalid_request", error_description: "Client not found"
151
+ end
152
+
153
+ def access_denied
154
+ render_error :unauthorized, error: "invalid_request"
155
+ end
156
+
157
+ def invalid_request
158
+ render_error :bad_request, error: "invalid_request"
159
+ end
160
+
161
+ def invalid_client
162
+ render_error :unauthorized, error: "invalid_client"
163
+ ## TODO: check authorization
164
+ end
165
+
166
+ def blocked_client
167
+ render_error :unprocessable_entity, error: "invalid_request", error_description: "Client Blocked"
168
+ end
169
+
170
+ def blocked_token
171
+ render_error :unprocessable_entity, error: "invalid_request", error_description: "Client blocked from the user"
172
+ end
173
+
174
+ def invalid_grant
175
+ render_error :bad_request, error: "invalid_grant"
176
+ end
177
+
178
+ def render_error status, info
179
+ render json: info, status: status
180
+ end
181
+
182
+
183
+ end
@@ -0,0 +1,7 @@
1
+ class AccessesController < ApplicationController
2
+ def index
3
+ end
4
+
5
+ def show
6
+ end
7
+ end
@@ -0,0 +1,84 @@
1
+ class Devise::Oauth::AuthorizationsController < ApplicationController
2
+ include Devise::Oauth::Helpers
3
+
4
+ before_filter :authenticate_user! # TODO: use devise scope here
5
+ before_filter :find_client
6
+ before_filter :find_resource_owner
7
+ before_filter :normalize_scope
8
+ # before_filter :check_scope # check if the access is authorized
9
+ before_filter :client_blocked? # check if the client is blocked
10
+ before_filter :access_blocked? # check if user has blocked the client
11
+
12
+ # before_filter :token_blocked?, only: :show # check for an existing token
13
+ # before_filter :refresh_token, only: :show # create a new token
14
+
15
+ def show
16
+ end
17
+
18
+ def create
19
+ @client.granted!
20
+
21
+ # section 4.1.1 - authorization code flow
22
+ if params[:response_type] == "code"
23
+ @authorization = Devise::Oauth::Authorization.create(client: @client, resource_owner: @resource_owner, scope: @scope)
24
+ redirect_to authorization_redirect_uri(@client, @authorization, params[:state])
25
+ end
26
+
27
+ # section 4.2.1 - implicit grant flow
28
+ if params[:response_type] == "token"
29
+ @token = Devise::Oauth::AccessToken.create(client: @client, resource_owner: @resource_owner, scope: scope)
30
+ redirect_to implicit_redirect_uri(@client, @token, params[:state])
31
+ end
32
+ end
33
+
34
+ def destroy
35
+ @client.revoked!
36
+ redirect_to deny_redirect_uri(params[:response_type], params[:state])
37
+ end
38
+
39
+ private
40
+
41
+ def authorization_redirect_uri(client, authorization, state)
42
+ uri = client.redirect_uris.first
43
+ uri += "?code=" + authorization.code
44
+ uri += "&state=" + state if state
45
+ uri
46
+ end
47
+
48
+ def implicit_redirect_uri(client, token, state)
49
+ uri = client.redirect_uris.first
50
+ uri += "#token=" + token.token
51
+ uri += "&expires_in=" + Oauth.settings["token_expires_in"]
52
+ uri += "&state=" + state if state
53
+ return uri
54
+ end
55
+
56
+ def deny_redirect_uri(response_type, state)
57
+ uri = @client.redirect_uris.first
58
+ uri += (response_type == "code") ? "?" : "#"
59
+ uri += "error=access_denied"
60
+ uri += "&state=" + state if state
61
+ return uri
62
+ end
63
+
64
+ def find_resource_owner
65
+ @resource_owner = current_user
66
+ end
67
+
68
+ def find_client
69
+ client_id = params[:client_id]
70
+
71
+ @client = Devise::Oauth::Client.where(identifier: client_id).first
72
+
73
+ client_not_found if @client.blank?
74
+ end
75
+
76
+ def invalid_request
77
+ raise "sd"
78
+ end
79
+
80
+ def client_not_found
81
+ rails "bla"
82
+ end
83
+
84
+ end
@@ -0,0 +1,24 @@
1
+ class Devise::Oauth::ClientsController < ApplicationController
2
+ load_and_authorize_resource if respond_to? :load_and_authorize_resource
3
+
4
+ def index
5
+ end
6
+
7
+ def show
8
+ end
9
+
10
+ def update
11
+ end
12
+
13
+ def edit
14
+ end
15
+
16
+ def new
17
+ end
18
+
19
+ def create
20
+ end
21
+
22
+ def destroy
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Devise::Oauth::Helpers
2
+
3
+ def normalize_scope
4
+ scope = (params[:scope] || "").split(" ")
5
+ scope_mask = Devise::Oauth::AccessToken.scope_to_mask(scope)
6
+ @requested_scope = Devise::Oauth::AccessToken.mask_to_scope(scope_mask)
7
+
8
+ scope_mask = @client.scope_mask & scope_mask
9
+ scope_mask = @authorization.scope_mask & scope_mask if @authorization
10
+ scope_mask = @refresh_token.scope_mask & scope_mask if @refresh_token
11
+
12
+ @scope = Devise::Oauth::AccessToken.mask_to_scope(scope_mask)
13
+ end
14
+
15
+ def client_blocked?
16
+ blocked_client if @client.blocked?
17
+ end
18
+
19
+ def access_blocked?
20
+ @access = Devise::Oauth::Access.find_or_create_by_client_id_and_resource_owner_id(@client.id, @resource_owner.id)
21
+ blocked_token if @access.blocked?
22
+ end
23
+
24
+ end
@@ -0,0 +1,19 @@
1
+ class Devise::Oauth::Access < ActiveRecord::Base
2
+ belongs_to :client, class_name: "Devise::Oauth::Client"
3
+ belongs_to :resource_owner, class_name: Devise::Oauth.resource_owner
4
+
5
+ validates :client_id, presence: true
6
+ validates :resource_owner_id, presence: true
7
+
8
+ include Devise::Oauth::Blockable
9
+
10
+ def block!
11
+ super
12
+ Devise::Oauth::AccessToken.block_access!(client_id, resource_owner_id)
13
+ Devise::Oauth::Authorization.block_access!(client_id, resource_owner_id)
14
+ end
15
+
16
+ def accessed!
17
+ self.class.update_counters(id, accessed_times: 1)
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ class Devise::Oauth::AccessToken < ActiveRecord::Base
2
+ belongs_to :client, class_name: "Devise::Oauth::Client"
3
+ belongs_to :resource_owner, class_name: Devise::Oauth.resource_owner
4
+
5
+ validates :client_id, presence: true
6
+ validates :resource_owner_id, presence: true
7
+
8
+ attr_accessible :client, :resource_owner, :scope
9
+
10
+ before_create :generate_refresh_token if Devise::Oauth.generate_refresh_token
11
+
12
+ before_create :generate_value
13
+ before_create :setup_expiration
14
+
15
+ include Devise::Oauth::Scopable
16
+ include Devise::Oauth::Blockable
17
+
18
+ def expired?(at = Time.now)
19
+ self.expires_at < at
20
+ end
21
+
22
+ def refresh!
23
+ generate_refresh_token if Devise::Oauth.regenerate_refresh_token
24
+
25
+ generate_value
26
+ setup_expiration
27
+
28
+ save
29
+ token_response(Devise::Oauth.regenerate_refresh_token)
30
+ end
31
+
32
+ def refresh_token_expired?
33
+ self.refresh_token_expires_at < Time.now
34
+ end
35
+
36
+ def token_response(generated_refresh_token=true)
37
+ res = {
38
+ access_token: value,
39
+ token_type: 'bearer'
40
+ }
41
+ res[:scope] = scope_to_response if scope.present?
42
+ res[:expires_in] = Devise::Oauth.access_token_expires_in if Devise::Oauth.access_token_expires_in
43
+ res[:refresh_token] = refresh_token if generated_refresh_token
44
+ res
45
+ end
46
+
47
+ private
48
+
49
+ def generate_value
50
+ self.value = Devise.friendly_token
51
+ end
52
+
53
+ def setup_expiration
54
+ self.expires_at = Time.now + Devise::Oauth.access_token_expires_in
55
+ end
56
+
57
+ def generate_refresh_token
58
+ self.refresh_token = Devise::Oauth.friendly_token
59
+ end
60
+
61
+ end
@@ -0,0 +1,58 @@
1
+ class Devise::Oauth::Authorization < ActiveRecord::Base
2
+ belongs_to :client, class_name: "Devise::Oauth::Client"
3
+ belongs_to :resource_owner, class_name: Devise::Oauth.resource_owner
4
+
5
+ validates :client_id, presence: true
6
+ validates :resource_owner_id, presence: true
7
+
8
+ before_create :generate_code
9
+ before_create :create_expiration
10
+
11
+ include Devise::Oauth::Scopable
12
+ include Devise::Oauth::Blockable
13
+
14
+ attr_accessible :client, :resource_owner, :scope
15
+
16
+ def expired?(at = Time.now)
17
+ self.expires_at < at
18
+ end
19
+
20
+ def expire!(at = Time.now)
21
+ self.expires_at = at
22
+ save
23
+ end
24
+
25
+ def used!(at = Time.now)
26
+ self.used_at = at
27
+ save
28
+ # TODO: May be we should destroy it instead?
29
+ end
30
+
31
+ def used?
32
+ !!self.used_at
33
+ end
34
+
35
+ def valid_redirect_uri? uri
36
+ if redirect_uri.blank?
37
+ client.redirect_uris.include? uri
38
+ else
39
+ self.redirect_uri = uri
40
+ end
41
+ end
42
+
43
+ def create_access_token
44
+ Devise::Oauth::AccessToken.create client: client, resource_owner: resource_owner, scope: scope
45
+ end
46
+
47
+ private
48
+
49
+ def generate_code
50
+ self.code = Devise::Oauth.friendly_token
51
+ end
52
+
53
+ def create_expiration
54
+ self.expires_at = Time.now + Devise::Oauth.authorization_code_expires_in
55
+ end
56
+
57
+
58
+ end
@@ -0,0 +1,49 @@
1
+ module Devise::Oauth
2
+ class Client < ActiveRecord::Base
3
+ def self.client_ownable?
4
+ Devise::Oauth.client_owner.constantize.devise_modules.include? :client_ownable
5
+ end
6
+
7
+ belongs_to :owner, class_name: Devise::Oauth.client_owner if self.client_ownable?
8
+
9
+ has_many :access_tokens, class_name: "Devise::Oauth::AccessToken", dependent: :destroy
10
+ has_many :authorizations, class_name: "Devise::Oauth::Authorization", dependent: :destroy
11
+ has_many :accesses, class_name: "Devise::Oauth::Access", dependent: :destroy
12
+
13
+ validates :name, presence: true
14
+ validates :owner_id, presence: true
15
+ validates :site_uri, presence: true
16
+
17
+ serialize :redirect_uris, Array
18
+
19
+ include Devise::Oauth::Scopable
20
+ include Devise::Oauth::Blockable
21
+
22
+ def block!
23
+ super
24
+ AccessToken.block_client! id
25
+ Authorization.block_client! id
26
+ end
27
+
28
+ before_create :generate_identifier
29
+ before_create :generate_secret
30
+
31
+ def granted!
32
+ self.class.update_counters(id, granted_times: 1)
33
+ end
34
+
35
+ def revoked!
36
+ self.class.update_counters(id, revoked_times: 1)
37
+ end
38
+
39
+ private
40
+
41
+ def generate_identifier
42
+ self.identifier = Devise::Oauth.friendly_token
43
+ end
44
+
45
+ def generate_secret
46
+ self.secret = Devise::Oauth.friendly_token
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ <% unless flash.alert %>
2
+ <h2>Authorization request</h2>
3
+ <div>
4
+ <b>The application <em><%=@client.name%></em> would like to access your resources</b>
5
+ <div>You are giving access to <%= @scope.join(", ") %></div>
6
+ </div>
7
+
8
+ <div>
9
+ <form method="POST" action="/oauth/authorization">
10
+ <input type="hidden" name="response_type" value="<%=params[:response_type]%>">
11
+ <input type="hidden" name="client_id" value="<%=params[:client_id]%>">
12
+ <input type="hidden" name="redirect_uri" value="<%=params[:redirect_uri]%>">
13
+ <input type="hidden" name="scope" value="<%=@scope.join(" ")%>">
14
+ <% if params[:state] %>
15
+ <input type="hidden" name="state" value="<%=params[:state]%>">
16
+ <% end %>
17
+ <button>Grant Access</button>
18
+ </form>
19
+ </div>
20
+
21
+ <div>
22
+ <form method="POST" action="/oauth/authorization">
23
+ <input type="hidden" name="_method" value="delete">
24
+ <input type="hidden" name="response_type" value="<%=params[:response_type]%>">
25
+ <input type="hidden" name="client_id" value="<%=params[:client_id]%>">
26
+ <input type="hidden" name="redirect_uri" value="<%=params[:redirect_uri]%>">
27
+ <input type="hidden" name="scope" value="<%=@scope.join(" ")%>">
28
+ <% if params[:state] %>
29
+ <input type="hidden"name="state" value="<%=params[:state]%>">
30
+ <% end %>
31
+ <button>Deny Access</button>
32
+ </form>
33
+ </div>
34
+ <% end %>
data/config/routes.rb ADDED
@@ -0,0 +1,14 @@
1
+ Devise::Oauth::Engine.routes.draw do
2
+ resource :authorization, path: :authorize, only: [:create, :show, :destroy], defaults: {format: :html}
3
+ resource :access_token, path: :token, only: [:create, :destroy], defaults: {format: :json}
4
+
5
+ resources :clients do
6
+ put :block, on: :member
7
+ put :unblock, on: :member
8
+ end
9
+
10
+ resources :access, only: [:index, :show] do
11
+ put :block, on: :member
12
+ put :unblock, on: :member
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ class DeviseCreateOauth < ActiveRecord::Migration
2
+ def change
3
+ create_table :oauth_clients do |t|
4
+ # client_ownable devise strategy
5
+ t.integer :owner_id
6
+
7
+ t.string :identifier, null: false
8
+ t.string :name, null: false
9
+ t.string :secret, null: false
10
+ t.string :site_uri, null: false
11
+ t.text :redirect_uris
12
+ t.text :info
13
+ t.integer :scope_mask, null: false, default: 0
14
+
15
+ t.integer :granted_times, null: false, default: 0
16
+ t.integer :revoked_times, null: false, default: 0
17
+
18
+ t.datetime :blocked_at
19
+ t.timestamps
20
+ end
21
+
22
+ add_index :oauth_clients, :identifier, unique: true
23
+ add_index :oauth_clients, :secret, unique: true
24
+ add_index :oauth_clients, :owner_id
25
+
26
+ create_table :oauth_authorizations do |t|
27
+ t.integer :client_id, null: false
28
+ t.integer :resource_owner_id, null: false
29
+ t.integer :scope_mask, null: false, default: 0
30
+ t.string :redirect_uri
31
+ t.string :code, null: false
32
+ t.datetime :expires_at, null: false
33
+
34
+ t.datetime :used_at
35
+
36
+ t.datetime :blocked_at
37
+ t.timestamps
38
+ end
39
+
40
+ add_index :oauth_authorizations, :client_id
41
+ add_index :oauth_authorizations, :resource_owner_id
42
+ add_index :oauth_authorizations, :code, unique: true
43
+
44
+ # for authorization and access tokens
45
+ create_table :oauth_access_tokens do |t|
46
+ t.integer :client_id, null: false
47
+ t.integer :resource_owner_id, null: false
48
+ t.integer :scope_mask, null: false, default: 0
49
+ t.string :value, null: false
50
+ t.datetime :expires_at, null: false
51
+
52
+ t.string :refresh_token
53
+
54
+ t.datetime :blocked_at
55
+ t.timestamps
56
+ end
57
+
58
+ add_index :oauth_access_tokens, :client_id
59
+ add_index :oauth_access_tokens, :resource_owner_id
60
+ add_index :oauth_access_tokens, :value, unique: true
61
+ add_index :oauth_access_tokens, :refresh_token, unique: true
62
+
63
+ create_table :oauth_accesses do |t|
64
+ t.integer :client_id, null: false
65
+ t.integer :resource_owner_id, null: false
66
+
67
+ t.integer :accessed_times, null: false, default: 0
68
+
69
+ t.datetime :blocked_at
70
+ t.timestamps
71
+ end
72
+
73
+ add_index :oauth_accesses, :client_id
74
+ add_index :oauth_accesses, :resource_owner_id
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ module Devise
2
+ module Models
3
+ module AccessTokenAuthenticatable
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module Devise
2
+ module Models
3
+ module ClientOwnable
4
+ extend ActiveSupport::Concern
5
+ included do
6
+
7
+ has_many :oauth_clients,
8
+ class_name: "Devise::Oauth::Client",
9
+ foreign_key: "owner_id",
10
+ dependent: :destroy
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ module Devise
2
+ module Models
3
+ module ResourceOwnable
4
+ extend ActiveSupport::Concern
5
+ included do
6
+
7
+ has_many :oauth_access_tokens,
8
+ class_name: "Devise::Oauth::AccessToken",
9
+ foreign_key: "resource_owner_id",
10
+ dependent: :destroy
11
+
12
+ has_many :oauth_authorizations,
13
+ class_name: "Devise::Oauth::Authorization",
14
+ foreign_key: "resource_owner_id",
15
+ dependent: :destroy
16
+
17
+ has_many :oauth_accesses,
18
+ class_name: "Devise::Oauth::Access",
19
+ foreign_key: "resource_owner_id",
20
+ dependent: :destroy
21
+
22
+ attr_accessor :oauth_token
23
+ end
24
+
25
+ def oauth_token?
26
+ oauth_token.present?
27
+ end
28
+
29
+ def oauth_scope? *scope
30
+ return false if oauth_token.nil?
31
+
32
+ oauth_token.has_scope? scope
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ module Devise::Oauth::Blockable
2
+ extend ActiveSupport::Concern
3
+
4
+ def block!(at = Time.now)
5
+ self.blocked_at = at
6
+ save
7
+ end
8
+
9
+ def blocked?
10
+ blocked_at.present?
11
+ end
12
+
13
+ def unblock!
14
+ self.blocked_at = nil
15
+ save
16
+ end
17
+
18
+ module ClassMethods
19
+ def block_access!(client_id, resource_owner_id)
20
+ update_all({ blocked_at: Time.now }, { client_id: client_id, resource_owner_id: resource_owner_id })
21
+ end
22
+
23
+ def block_client!(client_id)
24
+ update_all({ blocked_at: Time.now }, { client_id: client_id })
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Devise::Oauth
2
+ class Engine < ::Rails::Engine
3
+ def table_name_prefix
4
+ "oauth"
5
+ end
6
+
7
+ def self.generate_railtie_name(mod)
8
+ "oauth"
9
+ end
10
+
11
+ isolate_namespace Devise::Oauth
12
+
13
+ initializer "devise_oauth.initialize_application", before: :load_config_initializers do |app|
14
+ app.config.filter_parameters << :client_secret
15
+ app.config.filter_parameters << :refresh_token
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,43 @@
1
+ module Devise::Oauth::Scopable
2
+ extend ActiveSupport::Concern
3
+
4
+ def scope=(scope)
5
+ self.scope_mask = self.class.scope_to_mask(scope)
6
+ end
7
+
8
+ def scope
9
+ self.class.mask_to_scope(scope_mask)
10
+ end
11
+
12
+ def has_scope?(scope)
13
+ self.scope_mask & self.class.scope_to_mask(scope) > 0
14
+ end
15
+
16
+ def scope_to_response
17
+ scope.join(" ")
18
+ end
19
+
20
+ module ClassMethods
21
+ def scopes
22
+ @@scopes ||= Devise::Oauth.scopes.map {|s| s.to_s}
23
+ end
24
+
25
+ def scope_to_mask(scope=[])
26
+ return 0 if scope.blank?
27
+ (scope.map(&:to_s) & scopes).map { |r| 2**scopes.index(r) }.sum
28
+ end
29
+
30
+ def mask_to_scope(mask)
31
+ return [] if mask == 0
32
+ scopes.reject {|r| (mask & 2**scopes.index(r)).zero? }
33
+ end
34
+
35
+ def where_scope(scope=[])
36
+ if scope.blank?
37
+ where "scope_mask = 0"
38
+ else
39
+ where "scope_mask & ? > 0", scope_to_mask(scope)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module Oauth
3
+ VERSION = "2.0.0"
4
+ end
5
+ end
@@ -0,0 +1,69 @@
1
+ require 'devise/strategies/base'
2
+ module Devise
3
+ module Strategies
4
+ class AccessTokenAuthenticatable < Authenticatable
5
+ def store?
6
+ false # no no for session here
7
+ end
8
+
9
+ def valid?
10
+ @access_tokens = [access_token_in_header, access_token_in_payload].compact
11
+ @access_tokens.present?
12
+ end
13
+
14
+ def authenticate!
15
+ return oauth_error! if @access_tokens.length > 1
16
+
17
+ access_token = Devise::Oauth::AccessToken.where(value: @access_tokens.first).first
18
+
19
+ return oauth_error!(403, :access_denied) unless access_token
20
+ return oauth_error!(403, :access_denied) if access_token.expired?
21
+
22
+ resource = access_token.resource_owner
23
+ if validate(resource)
24
+ env["devise.oauth.access_token"] = access_token
25
+ resource.oauth_token = access_token
26
+ success!(resource)
27
+ else
28
+ oauth_error!
29
+ end
30
+ end
31
+
32
+ private
33
+ def oauth_error!(status = 400, error_code = :invalid_request, description = nil)
34
+ body = {error: error_code}
35
+ body[:error_description] = description if description
36
+
37
+ headers = {"Content-Type" => "application/json; charset=utf-8"}
38
+
39
+ custom! [status, headers, [body.to_json]]
40
+ end
41
+
42
+ # Access Token Authenticatable can be authenticated with params in any controller and any verb.
43
+ def valid_params_request?
44
+ true
45
+ end
46
+
47
+ # Do not use remember_me behavior with token.
48
+ def remember_me?
49
+ false
50
+ end
51
+
52
+ def access_token_in_payload
53
+ params['access_token']
54
+ end
55
+
56
+ def access_token_in_header
57
+ auth_header = ::Rack::Auth::AbstractRequest.new(env)
58
+ if auth_header.provided? && auth_header.scheme == :bearer
59
+ auth_header.params
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+
69
+ Warden::Strategies.add(:access_token_authenticatable, Devise::Strategies::AccessTokenAuthenticatable)
@@ -0,0 +1,52 @@
1
+ require 'active_support/core_ext'
2
+ require 'devise'
3
+
4
+ module Devise
5
+ module Oauth
6
+ mattr_accessor :resource_owner
7
+ @@resource_owner = "User"
8
+
9
+ mattr_accessor :client_owner
10
+ @@client_owner = self.resource_owner
11
+
12
+ mattr_accessor :scopes
13
+ @@scopes = []
14
+
15
+ mattr_accessor :access_token_expires_in
16
+ @@access_token_expires_in = 1.hour
17
+
18
+ mattr_accessor :authorization_code_expires_in
19
+ @@authorization_code_expires_in = 1.minute
20
+
21
+ mattr_accessor :generate_refresh_token
22
+ @@generate_refresh_token = true
23
+
24
+ mattr_accessor :regenerate_refresh_token
25
+ @@regenerate_refresh_token = true
26
+
27
+ mattr_accessor :supported_grant_types
28
+ @@supported_grant_types = [:authorization_code, :password, :refresh_token]
29
+
30
+ def self.friendly_token(length = 20)
31
+ SecureRandom.base64(length).tr('+/=lIO0', 'pqrsxyz')
32
+ end
33
+ end
34
+ end
35
+
36
+ require "devise/oauth/scopable"
37
+ require "devise/oauth/blockable"
38
+
39
+ require "devise/models/client_ownable"
40
+ require "devise/models/resource_ownable"
41
+
42
+ require "devise/strategies/access_token_authenticatable"
43
+ require "devise/models/access_token_authenticatable"
44
+
45
+
46
+ require "devise/oauth/engine"
47
+
48
+ Devise.add_module(
49
+ :access_token_authenticatable,
50
+ :strategy => true,
51
+ :model => 'devise/models/access_token_authenticatable'
52
+ )
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :devise_oauth do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_oauth
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yury Korolev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &70245897777140 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70245897777140
25
+ - !ruby/object:Gem::Dependency
26
+ name: devise
27
+ requirement: &70245897776200 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '2.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70245897776200
36
+ - !ruby/object:Gem::Dependency
37
+ name: sqlite3
38
+ requirement: &70245897775620 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70245897775620
47
+ - !ruby/object:Gem::Dependency
48
+ name: factory_girl_rails
49
+ requirement: &70245897774900 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70245897774900
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec-rails
60
+ requirement: &70245897773960 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '2.0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70245897773960
69
+ - !ruby/object:Gem::Dependency
70
+ name: database_cleaner
71
+ requirement: &70245897773500 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70245897773500
80
+ - !ruby/object:Gem::Dependency
81
+ name: shoulda-matchers
82
+ requirement: &70245897772840 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70245897772840
91
+ description: The OAuth 2.0 Authorization Framework draft-ietf-oauth-v2-28 implementation
92
+ on top of devise.
93
+ email:
94
+ - yury.korolev@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - app/controllers/oauth/access_tokens_controller.rb
100
+ - app/controllers/oauth/accesses_controller.rb
101
+ - app/controllers/oauth/authorizations_controller.rb
102
+ - app/controllers/oauth/clients_controller.rb
103
+ - app/helpers/devise/oauth/helpers.rb
104
+ - app/models/oauth/access.rb
105
+ - app/models/oauth/access_token.rb
106
+ - app/models/oauth/authorization.rb
107
+ - app/models/oauth/client.rb
108
+ - app/views/devise/oauth/authorizations/show.html.erb
109
+ - config/routes.rb
110
+ - db/migrate/20120622164619_devise_create_oauth.rb
111
+ - lib/devise/models/access_token_authenticatable.rb
112
+ - lib/devise/models/client_ownable.rb
113
+ - lib/devise/models/resource_ownable.rb
114
+ - lib/devise/oauth/blockable.rb
115
+ - lib/devise/oauth/engine.rb
116
+ - lib/devise/oauth/scopable.rb
117
+ - lib/devise/oauth/version.rb
118
+ - lib/devise/strategies/access_token_authenticatable.rb
119
+ - lib/devise_oauth.rb
120
+ - lib/tasks/devise_oauth_tasks.rake
121
+ - MIT-LICENSE
122
+ - Rakefile
123
+ - README.md
124
+ homepage: https://github.com/anjlab/devise_oauth
125
+ licenses: []
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ segments:
137
+ - 0
138
+ hash: -2188440318074512588
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ segments:
146
+ - 0
147
+ hash: -2188440318074512588
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 1.8.17
151
+ signing_key:
152
+ specification_version: 3
153
+ summary: Oauth 2.0 provider implementation on top of devise.
154
+ test_files: []