oauth2_provider_engine 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.
Files changed (132) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/oauth2_provider/application.js +52 -0
  5. data/app/assets/javascripts/oauth2_provider/highcharts.js +162 -0
  6. data/app/assets/javascripts/oauth2_provider/jquery.tagsinput.js +218 -0
  7. data/app/assets/stylesheets/oauth2_provider/gh-buttons.css +388 -0
  8. data/app/assets/stylesheets/oauth2_provider/gh-icons.png +0 -0
  9. data/app/assets/stylesheets/oauth2_provider/jquery.tagsinput.css +6 -0
  10. data/app/assets/stylesheets/oauth2_provider/reset.css +2 -0
  11. data/app/assets/stylesheets/oauth2_provider/template.css +52 -0
  12. data/app/controllers/oauth2_provider/accesses_controller.rb +39 -0
  13. data/app/controllers/oauth2_provider/application_controller.rb +17 -0
  14. data/app/controllers/oauth2_provider/authorize_controller.rb +141 -0
  15. data/app/controllers/oauth2_provider/clients_controller.rb +85 -0
  16. data/app/controllers/oauth2_provider/scopes_controller.rb +63 -0
  17. data/app/controllers/oauth2_provider/token_controller.rb +187 -0
  18. data/app/helpers/clients_helper.rb +5 -0
  19. data/app/helpers/oauth2_provider/application_helper.rb +4 -0
  20. data/app/models/oauth2_provider/client.rb +129 -0
  21. data/app/models/oauth2_provider/document.rb +15 -0
  22. data/app/models/oauth2_provider/oauth_access.rb +80 -0
  23. data/app/models/oauth2_provider/oauth_authorization.rb +70 -0
  24. data/app/models/oauth2_provider/oauth_daily_request.rb +54 -0
  25. data/app/models/oauth2_provider/oauth_refresh_token.rb +20 -0
  26. data/app/models/oauth2_provider/oauth_token.rb +78 -0
  27. data/app/models/oauth2_provider/scope.rb +39 -0
  28. data/app/views/layouts/oauth2_provider/application.html.erb +62 -0
  29. data/app/views/oauth2_provider/accesses/index.html.erb +25 -0
  30. data/app/views/oauth2_provider/accesses/show.html.erb +35 -0
  31. data/app/views/oauth2_provider/clients/_form.html.erb +50 -0
  32. data/app/views/oauth2_provider/clients/edit.html.erb +9 -0
  33. data/app/views/oauth2_provider/clients/index.html.erb +43 -0
  34. data/app/views/oauth2_provider/clients/new.html.erb +8 -0
  35. data/app/views/oauth2_provider/clients/show.html.erb +49 -0
  36. data/app/views/oauth2_provider/scopes/_form.html.erb +35 -0
  37. data/app/views/oauth2_provider/scopes/edit.html.erb +8 -0
  38. data/app/views/oauth2_provider/scopes/index.html.erb +27 -0
  39. data/app/views/oauth2_provider/scopes/new.html.erb +7 -0
  40. data/app/views/oauth2_provider/scopes/show.html.erb +19 -0
  41. data/app/views/shared/authorize.html.erb +34 -0
  42. data/app/views/shared/token.json.erb +8 -0
  43. data/config/locales/en.yml +31 -0
  44. data/config/oauth.yml +4 -0
  45. data/config/routes.rb +25 -0
  46. data/lib/oauth2_provider.rb +38 -0
  47. data/lib/oauth2_provider/controller_mixin.rb +53 -0
  48. data/lib/oauth2_provider/engine.rb +4 -0
  49. data/lib/oauth2_provider_engine.rb +1 -0
  50. data/lib/oauth2_provider_engine/version.rb +3 -0
  51. data/test/dummy/CHANGELOG.rdoc +67 -0
  52. data/test/dummy/Gemfile +53 -0
  53. data/test/dummy/Gemfile.lock +254 -0
  54. data/test/dummy/README.rdoc +522 -0
  55. data/test/dummy/Rakefile +7 -0
  56. data/test/dummy/VERSION +1 -0
  57. data/test/dummy/app/assets/stylesheets/reset.css +2 -0
  58. data/test/dummy/app/assets/stylesheets/template.css +52 -0
  59. data/test/dummy/app/controllers/application_controller.rb +52 -0
  60. data/test/dummy/app/controllers/pastas_controller.rb +23 -0
  61. data/test/dummy/app/controllers/pizzas_controller.rb +23 -0
  62. data/test/dummy/app/controllers/sessions_controller.rb +26 -0
  63. data/test/dummy/app/controllers/users_controller.rb +59 -0
  64. data/test/dummy/app/models/user.rb +50 -0
  65. data/test/dummy/app/views/layouts/application.html.erb +65 -0
  66. data/test/dummy/app/views/sessions/new.html.erb +25 -0
  67. data/test/dummy/app/views/shared/403.json.erb +4 -0
  68. data/test/dummy/app/views/shared/404.json.erb +6 -0
  69. data/test/dummy/app/views/shared/422.json.erb +5 -0
  70. data/test/dummy/app/views/shared/500.json.erb +4 -0
  71. data/test/dummy/app/views/shared/html/404.html.erb +0 -0
  72. data/test/dummy/app/views/shared/html/422.html.erb +0 -0
  73. data/test/dummy/app/views/users/_form.html.erb +27 -0
  74. data/test/dummy/app/views/users/edit.html.erb +8 -0
  75. data/test/dummy/app/views/users/index.html.erb +20 -0
  76. data/test/dummy/app/views/users/new.html.erb +46 -0
  77. data/test/dummy/app/views/users/show.html.erb +15 -0
  78. data/test/dummy/app/views/users/show.json.erb +6 -0
  79. data/test/dummy/config.ru +4 -0
  80. data/test/dummy/config/application.rb +57 -0
  81. data/test/dummy/config/boot.rb +13 -0
  82. data/test/dummy/config/cucumber.yml +8 -0
  83. data/test/dummy/config/environment.rb +5 -0
  84. data/test/dummy/config/environments/development.rb +32 -0
  85. data/test/dummy/config/environments/production.rb +58 -0
  86. data/test/dummy/config/environments/test.rb +35 -0
  87. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  88. data/test/dummy/config/initializers/inflections.rb +10 -0
  89. data/test/dummy/config/initializers/mime_types.rb +5 -0
  90. data/test/dummy/config/initializers/secret_token.rb +7 -0
  91. data/test/dummy/config/initializers/session_store.rb +8 -0
  92. data/test/dummy/config/initializers/test.rb +3 -0
  93. data/test/dummy/config/locales/en.yml +1 -0
  94. data/test/dummy/config/mongoid.yml +20 -0
  95. data/test/dummy/config/routes.rb +22 -0
  96. data/test/dummy/db/seeds.rb +7 -0
  97. data/test/dummy/doc/README_FOR_APP +2 -0
  98. data/test/dummy/lib/tasks/cucumber.rake +53 -0
  99. data/test/dummy/lib/tasks/watchr.rake +5 -0
  100. data/test/dummy/public/404.html +26 -0
  101. data/test/dummy/public/422.html +26 -0
  102. data/test/dummy/public/500.html +4 -0
  103. data/test/dummy/public/favicon.ico +0 -0
  104. data/test/dummy/public/robots.txt +5 -0
  105. data/test/dummy/script/cucumber +10 -0
  106. data/test/dummy/script/rails +6 -0
  107. data/test/dummy/spec/acceptance/acceptance_helper.rb +5 -0
  108. data/test/dummy/spec/acceptance/accesses_controller_spec.rb +77 -0
  109. data/test/dummy/spec/acceptance/clients_controller_spec.rb +218 -0
  110. data/test/dummy/spec/acceptance/oauth_authorize_controller_spec.rb +241 -0
  111. data/test/dummy/spec/acceptance/oauth_token_controller_spec.rb +196 -0
  112. data/test/dummy/spec/acceptance/resource_controller_spec.rb +143 -0
  113. data/test/dummy/spec/acceptance/scopes_controller_spec.rb +227 -0
  114. data/test/dummy/spec/acceptance/support/helpers.rb +81 -0
  115. data/test/dummy/spec/acceptance/support/paths.rb +9 -0
  116. data/test/dummy/spec/acceptance/support/view_helpers.rb +52 -0
  117. data/test/dummy/spec/acceptance/users_controller_spec.rb +198 -0
  118. data/test/dummy/spec/extras/scope_spec.rb +105 -0
  119. data/test/dummy/spec/factories/oauth.rb +106 -0
  120. data/test/dummy/spec/models/oauth/client_spec.rb +123 -0
  121. data/test/dummy/spec/models/oauth/oauth_access_spec.rb +48 -0
  122. data/test/dummy/spec/models/oauth/oauth_authorization_spec.rb +50 -0
  123. data/test/dummy/spec/models/oauth/oauth_daily_request_spec.rb +14 -0
  124. data/test/dummy/spec/models/oauth/oauth_refresh_token_spec.rb +11 -0
  125. data/test/dummy/spec/models/oauth/oauth_token_spec.rb +55 -0
  126. data/test/dummy/spec/models/scope_spec.rb +17 -0
  127. data/test/dummy/spec/spec_helper.rb +39 -0
  128. data/test/dummy/spec/support/settings_helper.rb +28 -0
  129. data/test/dummy/test/initializers/capybara_headers_hack.rb +23 -0
  130. data/test/oauth2_provider_test.rb +7 -0
  131. data/test/test_helper.rb +15 -0
  132. metadata +387 -0
@@ -0,0 +1,5 @@
1
+ module ClientsHelper
2
+ def authorization_uri(client, scope)
3
+ "/oauth/authorize?response_type=code&scope=#{scope}&client_id=#{client.uri}&redirect_uri=#{client.redirect_uri}"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Oauth2Provider
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,129 @@
1
+ # Application making protected resource requests on behalf of
2
+ # the resource owner and with its authorization
3
+
4
+ module Oauth2Provider
5
+ class Client
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Document::Base
9
+
10
+ field :uri # client identifier (internal)
11
+ field :name # client name
12
+ field :created_from # user who created the client
13
+ field :secret # client secret
14
+ field :site_uri # client website
15
+ field :redirect_uri # page called after authorization
16
+ field :scope, type: Array, default: [] # raw scope with keywords
17
+ field :scope_values, type: Array, default: [] # scope parsed as array of allowed actions
18
+ field :info # client additional info
19
+ field :granted_times, type: Integer, default: 0 # tokens granted in the authorization step
20
+ field :revoked_times, type: Integer, default: 0 # tokens revoked in the authorization step
21
+ field :blocked, type: Time, default: nil # blocks any request from the client
22
+
23
+ attr_accessible :name, :site_uri, :redirect_uri, :info, :scope
24
+
25
+ before_create :random_secret
26
+ before_destroy :clean
27
+
28
+ validates :name, presence: true
29
+ validates :uri, presence: true, url: true
30
+ validates :created_from, presence: true, url: true
31
+ validates :redirect_uri, presence: true, url: true
32
+
33
+
34
+ # Block the client
35
+ def block!
36
+ self.blocked = Time.now
37
+ self.save
38
+ OauthToken.block_client!(self.uri)
39
+ OauthAuthorization.block_client!(self.uri)
40
+ end
41
+
42
+ # Unblock the client
43
+ def unblock!
44
+ self.blocked = nil
45
+ self.save
46
+ end
47
+
48
+ # Check if the status is or is not blocked
49
+ def blocked?
50
+ !self.blocked.nil?
51
+ end
52
+
53
+ # Increase the counter of resource owners granting the access
54
+ # to the client
55
+ def granted!
56
+ self.granted_times += 1
57
+ self.save
58
+ end
59
+
60
+ # Increase the counter of resource owners revoking the access
61
+ # to the client
62
+ def revoked!
63
+ self.revoked_times += 1
64
+ self.save
65
+ end
66
+
67
+ def scope_pretty
68
+ separator = Oauth2Provider.settings["scope_separator"]
69
+ scope.join(separator)
70
+ end
71
+
72
+ def scope_values_pretty
73
+ separator = Oauth2Provider.settings["scope_separator"]
74
+ scope_values.join(separator)
75
+ end
76
+
77
+ class << self
78
+
79
+ # Filter to the client uri (internal identifier) and the
80
+ # redirect uri
81
+ def where_uri(client_uri, redirect_uri)
82
+ where(uri: client_uri, redirect_uri: redirect_uri)
83
+ end
84
+
85
+ # Filter to the client secret and the redirect uri
86
+ def where_secret(secret, client_uri)
87
+ where(secret: secret, uri: client_uri)
88
+ end
89
+
90
+ # Filter to the client scope
91
+ def where_scope(scope)
92
+ all_in(scope_values: scope)
93
+ end
94
+
95
+ # Sync all clients with the correct exploded scope when a
96
+ # scope is modified (changed or removed)
97
+ def sync_clients_with_scope(scope)
98
+ Client.all.each do |client|
99
+ scope_string = client.scope.join(Oauth2Provider.settings["scope_separator"])
100
+ client.scope_values = Oauth2Provider.normalize_scope(scope_string)
101
+ client.save
102
+ end
103
+ end
104
+ end
105
+
106
+
107
+ private
108
+
109
+ # TODO: use atomic updates
110
+ # https://github.com/mongoid/mongoid/commit/aa2c388c71529bf4d987b286acfd861eaac530ce
111
+ def block_tokens!
112
+ OauthToken.where(client_uri: uri).map(&:block!)
113
+ end
114
+
115
+ def block_authorizations!
116
+ OauthAuthorization.where(client_uri: uri).map(&:block!)
117
+ end
118
+
119
+ def random_secret
120
+ self.secret = SecureRandom.hex(Oauth2Provider.settings["random_length"])
121
+ end
122
+
123
+ def clean
124
+ OauthToken.where(client_uri: uri).destroy_all
125
+ OauthAuthorization.where(client_uri: uri).destroy_all
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,15 @@
1
+ module Oauth2Provider
2
+ module Document
3
+ module Base
4
+
5
+ def base_uri(request)
6
+ protocol = request.protocol
7
+ host = request.host_with_port
8
+ name = self.class.name.underscore.pluralize.split('/').last
9
+ id = self.id.as_json
10
+ uri = protocol + host + "/oauth/" + name + "/" + id
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,80 @@
1
+ # Access info related to a resource owner using a specific
2
+ # client (block and statistics)
3
+
4
+ module Oauth2Provider
5
+ class OauthAccess
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ field :client_uri # client identifier (internal)
10
+ field :resource_owner_uri # resource owner identifier
11
+ field :blocked, type: Time, default: nil # authorization block (a user block a single client)
12
+
13
+ embeds_many :oauth_daily_requests, class_name: 'Oauth2Provider::OauthDailyRequest' # daily requests (one record per day)
14
+
15
+ validates :client_uri, presence: true
16
+ validates :resource_owner_uri, presence: true
17
+
18
+
19
+ # Block the resource owner delegation to a specific client
20
+ def block!
21
+ self.blocked = Time.now
22
+ self.save
23
+ OauthToken.block_access!(client_uri, resource_owner_uri)
24
+ OauthAuthorization.block_access!(client_uri, resource_owner_uri)
25
+ end
26
+
27
+ # Unblock the resource owner delegation to a specific client
28
+ def unblock!
29
+ self.blocked = nil
30
+ self.save
31
+ end
32
+
33
+ # Check if the status is or is not blocked
34
+ def blocked?
35
+ !self.blocked.nil?
36
+ end
37
+
38
+ # Increment the daily accesses
39
+ def accessed!
40
+ daily_requests.increment!
41
+ end
42
+
43
+ # A daily requests record (there is one per day)
44
+ #
45
+ # @params [String] time we want to find the requests record
46
+ # @return [OauthDailyRequest] requests record
47
+ def daily_requests(time = Time.now)
48
+ find_or_create_daily_requests(time)
49
+ end
50
+
51
+ # Give back the last days in a friendly format.It is used to
52
+ # generate graph for statistics
53
+ def chart_days
54
+ daily_requests = self.oauth_daily_requests.limit(10)
55
+ days = daily_requests.map(&:created_at)
56
+ days.map { |d| d.strftime("%b %e") }
57
+ end
58
+
59
+ # Give the number of accesses for the last days. It is used
60
+ # to generate graph for statistics
61
+ def chart_times
62
+ access_times = self.oauth_daily_requests.limit(10)
63
+ access_times.map(&:times)
64
+ end
65
+
66
+
67
+ private
68
+
69
+ def find_or_create_daily_requests(time)
70
+ daily_requests = oauth_daily_requests.find_day(time).first
71
+ daily_requests = oauth_daily_requests.create(created_at: time) unless daily_requests
72
+ return daily_requests
73
+ end
74
+
75
+ def daily_id(time)
76
+ time.year + time.month + time.day
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,70 @@
1
+ # Authorization grant which represents the authorization
2
+ # provided by the resource owner
3
+
4
+ module Oauth2Provider
5
+ class OauthAuthorization
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ field :client_uri # client identifier
10
+ field :resource_owner_uri # resource owner identifier
11
+ field :code # authorization code
12
+ field :scope, type: Array # scope accessible with request
13
+ field :expire_at, type: Time # authorization expiration (security reasons)
14
+ field :blocked, type: Time, default: nil # authorization block (if client is blocked)
15
+
16
+ validates :client_uri, presence: true, url: true
17
+ validates :resource_owner_uri, presence: true, url: true
18
+
19
+ before_create :random_code
20
+ before_create :create_expiration
21
+
22
+ # Block the authorization (when resource owner blocks a client)
23
+ def block!
24
+ self.blocked = Time.now
25
+ self.save
26
+ end
27
+
28
+ # Block tokens used from a client
29
+ def self.block_client!(client_uri)
30
+ self.where(client_uri: client_uri).map(&:block!)
31
+ end
32
+
33
+ # Block tokens used from a client in behalf of a resource owner
34
+ def self.block_access!(client_uri, resource_owner_uri)
35
+ self.where(client_uri: client_uri, resource_owner_uri: resource_owner_uri).map(&:block!)
36
+ end
37
+
38
+ # Check if the status is or is not blocked
39
+ def blocked?
40
+ !self.blocked.nil?
41
+ end
42
+
43
+ # Check if the authorization is expired
44
+ def expired?
45
+ self.expire_at < Time.now
46
+ end
47
+
48
+ # Find the authorization based on the client uri and the
49
+ # authorization code
50
+ class << self
51
+ def where_code_and_client_uri(code, client_id)
52
+ where(code: code).where(client_uri: client_id)
53
+ end
54
+ end
55
+
56
+
57
+ private
58
+
59
+ # random authorization code
60
+ def random_code
61
+ self.code = SecureRandom.hex(Oauth2Provider.settings["random_length"])
62
+ end
63
+
64
+ # expiration time
65
+ def create_expiration
66
+ self.expire_at = Chronic.parse("in #{Oauth2Provider.settings["authorization_expires_in"]} seconds")
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,54 @@
1
+ # Daily requests of a Resource Owner on a specific client
2
+
3
+ module Oauth2Provider
4
+ class OauthDailyRequest
5
+
6
+ include Mongoid::Document
7
+
8
+ field :created_at, type: Time # creation time
9
+ field :time_id # unique key for the day
10
+ field :day # request day
11
+ field :month # request month
12
+ field :year # request year
13
+ field :times, type: Integer, default: 0 # daily request times
14
+
15
+ # resource owner's client access
16
+ embedded_in :oauth_access, inverse_of: :oauth_daily_requests
17
+
18
+ after_create :init_times
19
+
20
+ # Increment the times counter that track the number of
21
+ # requests a client have made in behalf of a resource
22
+ # owner in a specific day
23
+ def increment!
24
+ self.times += 1
25
+ self.save
26
+ end
27
+
28
+ class << self
29
+
30
+ # Find a daily requests record
31
+ def find_day(time)
32
+ time_id = time_id(time)
33
+ where(time_id: time_id)
34
+ end
35
+
36
+ # Define an identifier for a specific day
37
+ def time_id(time)
38
+ time.strftime("%Y%m%d")
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # Add statistical informations
45
+ def init_times
46
+ self.day = self.created_at.strftime("%d")
47
+ self.month = self.created_at.strftime("%m")
48
+ self.year = self.created_at.strftime("%Y")
49
+ self.time_id = self.class.time_id(created_at)
50
+ self.save
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ module Oauth2Provider
2
+ class OauthRefreshToken
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ field :refresh_token
7
+ field :access_token
8
+
9
+ validates :access_token, presence: true
10
+
11
+ before_create :random_refresh_token
12
+
13
+ private
14
+
15
+ def random_refresh_token
16
+ self.refresh_token = SecureRandom.hex(Oauth2Provider.settings["random_length"])
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,78 @@
1
+ # Access token used from the client to request resource
2
+ # owner resouces
3
+
4
+ module Oauth2Provider
5
+ class OauthToken
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ field :client_uri # client identifier (internal)
10
+ field :resource_owner_uri # resource owner identifier
11
+ field :token # access token
12
+ field :refresh_token # refresh token
13
+ field :scope, type: Array # scope accessible with token
14
+ field :expire_at, type: Time, default: nil # token expiration
15
+ field :blocked, type: Time, default: nil # access token block (if client is blocked)
16
+
17
+ before_create :random_token
18
+ before_create :random_refresh_token
19
+ before_create :create_expiration
20
+
21
+ validates :client_uri, presence: true, url: true
22
+ validates :resource_owner_uri, presence: true, url: true
23
+
24
+
25
+ # Block the resource owner delegation to a specific client
26
+ def block!
27
+ self.blocked = Time.now
28
+ self.save
29
+ end
30
+
31
+ # Block tokens used from a client
32
+ def self.block_client!(client_uri)
33
+ self.where(client_uri: client_uri).map(&:block!)
34
+ end
35
+
36
+ # Block tokens used from a client in behalf of a resource owner
37
+ def self.block_access!(client_uri, resource_owner_uri)
38
+ self.where(client_uri: client_uri, resource_owner_uri: resource_owner_uri).map(&:block!)
39
+ end
40
+
41
+ def self.exist(client_uri, resource_owner_uri, scope)
42
+ self.where(client_uri: client_uri).
43
+ where(resource_owner_uri: resource_owner_uri).
44
+ all_in(scope: scope)
45
+ end
46
+
47
+ # Check if the status is or is not blocked
48
+ def blocked?
49
+ !self.blocked.nil?
50
+ end
51
+
52
+ # Last time the resource owner have used the token
53
+ def last_access
54
+ self.updated_at
55
+ end
56
+
57
+ # Token is expired or not
58
+ def expired?
59
+ self.expire_at < Time.now
60
+ end
61
+
62
+
63
+ private
64
+
65
+ def random_token
66
+ self.token = SecureRandom.hex(Oauth2Provider.settings["random_length"])
67
+ end
68
+
69
+ def random_refresh_token
70
+ self.refresh_token = SecureRandom.hex(Oauth2Provider.settings["random_length"])
71
+ end
72
+
73
+ def create_expiration
74
+ self.expire_at = Chronic.parse("in #{Oauth2Provider.settings["token_expires_in"]} seconds")
75
+ end
76
+
77
+ end
78
+ end