devise_oauth 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []