devise_oauth2_token_bearer_authenticatable 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format documentation
3
+
@@ -0,0 +1,6 @@
1
+ Ryan Sonnek - Original Author
2
+
3
+
4
+ Complete list of contributors:
5
+ https://github.com/socialcast/devise_oauth2_token_bearer_authenticatable/contributors
6
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in devise_oauth2_token_bearer_authenticatable.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 Socialcast, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
@@ -0,0 +1,20 @@
1
+ # devise_oauth2_token_bearer_authenticatable
2
+
3
+ Support OAuth2 authentication for your API.
4
+
5
+ http://tools.ietf.org/html/draft-ietf-oauth-v2-15
6
+
7
+ ## Contributing
8
+
9
+ * Fork the project
10
+ * Fix the issue
11
+ * Add unit tests
12
+ * Submit pull request on github
13
+
14
+ See CONTRIBUTORS.txt for list of project contributors
15
+
16
+ ## Copyright
17
+
18
+ Copyright (c) 2011 Socialcast, Inc.
19
+ See LICENSE.txt for further details.
20
+
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
6
+ task :default => :spec
7
+
@@ -0,0 +1,52 @@
1
+ class Oauth2::AuthorizationsController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
5
+ @error = e
6
+ render :error, :status => e.status
7
+ end
8
+
9
+ def new
10
+ respond *authorize_endpoint.call(request.env)
11
+ end
12
+
13
+ def create
14
+ respond *authorize_endpoint(:allow_approval).call(request.env)
15
+ end
16
+
17
+ private
18
+
19
+ def respond(status, header, response)
20
+ ["WWW-Authenticate"].each do |key|
21
+ headers[key] = header[key] if header[key].present?
22
+ end
23
+ if response.redirect?
24
+ redirect_to header['Location']
25
+ else
26
+ render :new
27
+ end
28
+ end
29
+
30
+ def authorize_endpoint(allow_approval = false)
31
+ Rack::OAuth2::Server::Authorize.new do |req, res|
32
+ @client = Client.find_by_identifier(req.client_id) || req.bad_request!
33
+ res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.redirect_uri)
34
+ if allow_approval
35
+ if params[:approve].present?
36
+ case req.response_type
37
+ when :code
38
+ authorization_code = current_user.authorization_codes.create(:client_id => @client, :redirect_uri => @redirect_uri)
39
+ res.code = authorization_code.token
40
+ when :token
41
+ res.access_token = current_user.access_tokens.create(:client_id => @client).to_bearer_token
42
+ end
43
+ res.approve!
44
+ else
45
+ req.access_denied!
46
+ end
47
+ else
48
+ @response_type = req.response_type
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ require 'oauth2_token'
2
+
3
+ class AccessToken < ActiveRecord::Base
4
+ include Oauth2Token
5
+ self.default_lifetime = 15.minutes
6
+ belongs_to :refresh_token
7
+
8
+ def to_bearer_token(with_refresh_token = false)
9
+ bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
10
+ :access_token => self.token,
11
+ :expires_in => self.expires_in
12
+ )
13
+ if with_refresh_token
14
+ bearer_token.refresh_token = self.create_refresh_token(
15
+ :user => self.user,
16
+ :client => self.client
17
+ ).token
18
+ end
19
+ p bearer_token.token_response
20
+ bearer_token
21
+ end
22
+
23
+ private
24
+
25
+ def setup
26
+ super
27
+ if refresh_token
28
+ self.user = refresh_token.user
29
+ self.client = refresh_token.client
30
+ self.expires_at = [self.expires_at, refresh_token.expires_at].min
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ require 'oauth2_token'
2
+
3
+ class AuthorizationCode < ActiveRecord::Base
4
+ include Oauth2Token
5
+
6
+ def access_token
7
+ @access_token ||= expired! && user.access_tokens.create(:client => client)
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ class Client < ActiveRecord::Base
2
+ has_many :access_tokens
3
+ has_many :refresh_tokens
4
+
5
+ before_validation :setup, :on => :create
6
+ validates :name, :website, :redirect_uri, :secret, :presence => true
7
+ validates :identifier, :presence => true, :uniqueness => true
8
+
9
+ private
10
+
11
+ def setup
12
+ self.identifier = ActiveSupport::SecureRandom.base64(16)
13
+ self.secret = ActiveSupport::SecureRandom.base64
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ require 'oauth2_token'
2
+
3
+ class RefreshToken < ActiveRecord::Base
4
+ include Oauth2Token
5
+ self.default_lifetime = 1.month
6
+ has_many :access_tokens
7
+ end
@@ -0,0 +1,7 @@
1
+ <%= form_tag oauth2_authorizations_path, :class => action do %>
2
+ <%= hidden_field_tag :client_id, client.identifier %>
3
+ <%= hidden_field_tag :response_type, response_type %>
4
+ <%= hidden_field_tag :redirect_uri, redirect_uri %>
5
+ <%= submit_tag action.to_s.capitalize %>
6
+ <%= hidden_field_tag action, true %>
7
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <h2>Invalid Authorization Request</h2>
2
+ <h3><%= @error.error %></h3>
3
+ <p><%= @error.description %></p>
4
+
@@ -0,0 +1,5 @@
1
+ <h2><%= link_to @client.name, @client.website %> is permission to access your resources.</h2>
2
+
3
+ <%= render 'oauth2/authorizations/form', :client => @client, :response_type => @response_type, :redirect_uri => @redirect_uri, :action => :approve %>
4
+ <%= render 'oauth2/authorizations/form', :client => @client, :response_type => @response_type, :redirect_uri => @redirect_uri, :action => :deny %>
5
+
@@ -0,0 +1,8 @@
1
+ require 'token_endpoint'
2
+ Rails.application.routes.draw do |map|
3
+ namespace 'oauth2' do
4
+ resources :authorizations, :only => :create
5
+ end
6
+ match 'oauth2/authorize', :to => 'oauth2/authorizations#new'
7
+ post 'oauth2/token', :to => proc { |env| TokenEndpoint.new.call(env) }
8
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "devise_oauth2_token_bearer_authenticatable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "devise_oauth2_token_bearer_authenticatable"
7
+ s.version = DeviseOauth2TokenBearerAuthenticatable::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ryan Sonnek"]
10
+ s.email = ["ryan@socialcast.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{OAuth2 Provider for Rails3 applications}
13
+ s.description = %q{add OAuth2 authentication to rails3 application}
14
+
15
+ s.rubyforge_project = "devise_oauth2_token_bearer_authenticatable"
16
+
17
+ s.add_runtime_dependency(%q<rails>, ["~> 3.0.7"])
18
+ s.add_runtime_dependency(%q<devise>, ["~> 1.3.3"])
19
+ s.add_runtime_dependency(%q<rack-oauth2>, ["~> 0.6.3"])
20
+ s.add_development_dependency(%q<rspec>, ['>= 2.5.0'])
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,18 @@
1
+ require 'devise'
2
+ require 'rack/oauth2'
3
+ require 'devise_oauth2_token_bearer_authenticatable/strategy'
4
+ require 'devise_oauth2_token_bearer_authenticatable/model'
5
+ require 'devise_oauth2_token_bearer_authenticatable/schema'
6
+ require 'devise_oauth2_token_bearer_authenticatable/engine'
7
+
8
+ module Devise
9
+ module Oauth2TokenBearerAuthenticatable
10
+ # Your code goes here...
11
+
12
+ end
13
+ end
14
+
15
+ Devise.add_module(:oauth2_token_bearer_authenticatable,
16
+ :strategy => true,
17
+ :model => 'devise_oauth2_token_bearer_authenticatable/model')
18
+
@@ -0,0 +1,12 @@
1
+ module Devise
2
+ module Oauth2TokenBearerAuthenticatable
3
+ class Engine < Rails::Engine
4
+ initializer "devise_oauth2_token_bearer_authenticatable.initialize_application" do |app|
5
+ app.middleware.use Rack::OAuth2::Server::Resource::Bearer, 'OAuth2 Bearer Token Resources' do |req|
6
+ AccessToken.valid.find_by_token(req.access_token) || req.invalid_token!
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,13 @@
1
+ require 'devise/models'
2
+
3
+ module Devise
4
+ module Models
5
+ module Oauth2TokenBearerAuthenticatable
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ has_many :access_tokens
9
+ has_many :authorization_codes
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ require 'devise/schema'
2
+
3
+ module Devise
4
+ module Oauth2TokenBearerAuthenticatable
5
+ module Schema
6
+ def self.up(migration)
7
+ migration.create_table :clients do |t|
8
+ t.string :name
9
+ t.string :redirect_uri
10
+ t.string :website
11
+ t.string :identifier
12
+ t.string :secret
13
+ t.timestamps
14
+ end
15
+ migration.add_index :clients, :identifier
16
+
17
+ migration.create_table :access_tokens do |t|
18
+ t.belongs_to :user, :client
19
+ t.string :token
20
+ t.datetime :expires_at
21
+ t.timestamps
22
+ end
23
+ migration.add_index :access_tokens, :token
24
+ migration.add_index :access_tokens, :expires_at
25
+
26
+ migration.create_table :refresh_tokens do |t|
27
+ t.belongs_to :user, :client
28
+ t.string :token
29
+ t.datetime :expires_at
30
+ t.timestamps
31
+ end
32
+ migration.add_index :refresh_tokens, :token
33
+ migration.add_index :refresh_tokens, :expires_at
34
+
35
+ migration.create_table :authorization_codes do |t|
36
+ t.belongs_to :user, :client
37
+ t.string :token
38
+ t.datetime :expires_at
39
+ t.string :redirect_uri
40
+ t.timestamps
41
+ end
42
+ migration.add_index :authorization_codes, :token
43
+ migration.add_index :authorization_codes, :expires_at
44
+ end
45
+
46
+ def self.down(migration)
47
+ migration.drop_table :refresh_tokens
48
+ migration.drop_table :access_tokens
49
+ migration.drop_table :clients
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,19 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2TokenBearerAuthenticatable < Base
6
+ def valid?
7
+ env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN].present?
8
+ end
9
+ def authenticate!
10
+ token = AccessToken.valid.find_by_token env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
11
+ raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized unless token
12
+ raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:invalid_token, 'User token is required') unless token.user
13
+ success! token.user
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Warden::Strategies.add(:oauth2_token_bearer_authenticatable, Devise::Strategies::Oauth2TokenBearerAuthenticatable)
@@ -0,0 +1,3 @@
1
+ module DeviseOauth2TokenBearerAuthenticatable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,37 @@
1
+ module Oauth2Token
2
+ def self.included(klass)
3
+ klass.class_eval do
4
+ cattr_accessor :default_lifetime
5
+ self.default_lifetime = 1.minute
6
+
7
+ belongs_to :user
8
+ belongs_to :client
9
+
10
+ before_validation :setup, :on => :create
11
+ validates :client, :expires_at, :presence => true
12
+ validates :token, :presence => true, :uniqueness => true
13
+
14
+ # TODO: this should be a default scope once rails default_scope supports lambda's
15
+ scope :valid, lambda {
16
+ where(self.arel_table[:expires_at].gteq(Time.now.utc))
17
+ }
18
+ end
19
+ end
20
+
21
+ def expires_in
22
+ (expires_at - Time.now.utc).to_i
23
+ end
24
+
25
+ def expired!
26
+ self.expires_at = Time.now.utc
27
+ self.save!
28
+ end
29
+
30
+ private
31
+
32
+ def setup
33
+ self.token = ActiveSupport::SecureRandom.base64(16)
34
+ self.expires_at ||= self.default_lifetime.from_now
35
+ end
36
+ end
37
+
@@ -0,0 +1,37 @@
1
+ class TokenEndpoint
2
+
3
+ def call(env)
4
+ authenticator.call(env)
5
+ end
6
+
7
+ private
8
+
9
+ def authenticator
10
+ Rack::OAuth2::Server::Token.new do |req, res|
11
+ client = Client.find_by_identifier(req.client_id) || req.invalid_client!
12
+ client.secret == req.client_secret || req.invalid_client!
13
+ case req.grant_type
14
+ when :authorization_code
15
+ code = AuthorizationCode.valid.find_by_token(req.code)
16
+ req.invalid_grant! if code.blank? || code.redirect_uri != req.redirect_uri
17
+ res.access_token = code.access_token.to_bearer_token(:with_refresh_token)
18
+ when :password
19
+ user = User.find_by_email(req.username) || req.invalid_grant!
20
+ req.invalid_grant! unless user.valid_password?(req.password)
21
+ res.access_token = user.access_tokens.create(:client => client).to_bearer_token(:with_refresh_token)
22
+ when :client_credentials
23
+ # NOTE: client is already authenticated here.
24
+ res.access_token = client.access_tokens.create.to_bearer_token
25
+ when :refresh_token
26
+ refresh_token = client.refresh_tokens.valid.find_by_token(req.refresh_token)
27
+ req.invalid_grant! unless refresh_token
28
+ res.access_token = refresh_token.access_tokens.create.to_bearer_token
29
+ else
30
+ # NOTE: extended assertion grant_types are not supported yet.
31
+ req.unsupported_grant_type!
32
+ end
33
+ end
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Devise::Oauth2TokenBearerAuthenticatable do
4
+ it 'should be defined' do
5
+ # success
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'devise_oauth2_token_bearer_authenticatable'
5
+
6
+ # Requires supporting ruby files with custom matchers and macros, etc,
7
+ # in spec/support/ and its subdirectories.
8
+ # Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
9
+
10
+ # include Devise::TestHelpers
11
+
12
+ RSpec.configure do |config|
13
+ # == Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+ config.mock_with :rspec
21
+
22
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
23
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
24
+
25
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
26
+ # examples within a transaction, remove the following line or assign false
27
+ # instead of true.
28
+ # config.use_transactional_fixtures = true
29
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_oauth2_token_bearer_authenticatable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Sonnek
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-25 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 9
29
+ segments:
30
+ - 3
31
+ - 0
32
+ - 7
33
+ version: 3.0.7
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: devise
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 29
45
+ segments:
46
+ - 1
47
+ - 3
48
+ - 3
49
+ version: 1.3.3
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rack-oauth2
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 1
61
+ segments:
62
+ - 0
63
+ - 6
64
+ - 3
65
+ version: 0.6.3
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 27
77
+ segments:
78
+ - 2
79
+ - 5
80
+ - 0
81
+ version: 2.5.0
82
+ type: :development
83
+ version_requirements: *id004
84
+ description: add OAuth2 authentication to rails3 application
85
+ email:
86
+ - ryan@socialcast.com
87
+ executables: []
88
+
89
+ extensions: []
90
+
91
+ extra_rdoc_files: []
92
+
93
+ files:
94
+ - .gitignore
95
+ - .rspec
96
+ - CONTRIBUTORS.txt
97
+ - Gemfile
98
+ - LICENSE.txt
99
+ - README.md
100
+ - Rakefile
101
+ - app/controllers/oauth2/authorizations_controller.rb
102
+ - app/models/access_token.rb
103
+ - app/models/authorization_code.rb
104
+ - app/models/client.rb
105
+ - app/models/refresh_token.rb
106
+ - app/views/oauth2/authorizations/_form.html.erb
107
+ - app/views/oauth2/authorizations/error.html.erb
108
+ - app/views/oauth2/authorizations/new.html.erb
109
+ - config/routes.rb
110
+ - devise_oauth2_token_bearer_authenticatable.gemspec
111
+ - lib/devise_oauth2_token_bearer_authenticatable.rb
112
+ - lib/devise_oauth2_token_bearer_authenticatable/engine.rb
113
+ - lib/devise_oauth2_token_bearer_authenticatable/model.rb
114
+ - lib/devise_oauth2_token_bearer_authenticatable/schema.rb
115
+ - lib/devise_oauth2_token_bearer_authenticatable/strategy.rb
116
+ - lib/devise_oauth2_token_bearer_authenticatable/version.rb
117
+ - lib/oauth2_token.rb
118
+ - lib/token_endpoint.rb
119
+ - spec/devise_oauth2_token_bearer_authenticatable_spec.rb
120
+ - spec/spec_helper.rb
121
+ homepage: ""
122
+ licenses: []
123
+
124
+ post_install_message:
125
+ rdoc_options: []
126
+
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ hash: 3
135
+ segments:
136
+ - 0
137
+ version: "0"
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ requirements: []
148
+
149
+ rubyforge_project: devise_oauth2_token_bearer_authenticatable
150
+ rubygems_version: 1.7.2
151
+ signing_key:
152
+ specification_version: 3
153
+ summary: OAuth2 Provider for Rails3 applications
154
+ test_files:
155
+ - spec/devise_oauth2_token_bearer_authenticatable_spec.rb
156
+ - spec/spec_helper.rb