opro 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/README.md +29 -6
- data/VERSION +1 -1
- data/lib/opro.rb +12 -0
- data/lib/opro/controllers/application_controller_helper.rb +1 -1
- data/opro.gemspec +2 -2
- data/test/integration/action_dispatch/oauth_flow_test.rb +10 -0
- metadata +29 -29
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ A production ready Rails Engine that turns your app into an [Oauth2](http://oaut
|
|
9
9
|
|
10
10
|
Lets say you've built a Rails app, awesome. Now you want to build a mobile app on say, the iPhone... cool. You start throwing around `#to_json` like nobody's business, but then you realize you need to authenticate users somehow. "Basic Auth!!", you exclaim, but then you realize that's not the most secure solution. You also realize that some users already signed up with Facebook & Twitter so they don't have a username/password combo. What ever shall you do?
|
11
11
|
|
12
|
-
Wouldn't it be great if we could have a token exchange where the user goes to a mobile web view and grants permission, and then we return back an auth token just like the big boys (Facebook, Twitter, *cough* Foursquare *cough*). With Opro, we can add this functionality pretty easily. We'll use your existing authentication strategy and provide some end
|
12
|
+
Wouldn't it be great if we could have a token exchange where the user goes to a mobile web view and grants permission, and then we return back an auth token just like the big boys (Facebook, Twitter, *cough* Foursquare *cough*). With Opro, we can add this functionality pretty easily. We'll use your existing authentication strategy and provide some integration end points for your clients to use out of the box.
|
13
13
|
|
14
14
|
|
15
15
|
## Install
|
@@ -91,13 +91,12 @@ Opro is simple by default, but easily configurable for a number of common use ca
|
|
91
91
|
|
92
92
|
If you're not using devise you can manually configure your own auth strategy. In the future I plan on adding more auth strategies, ping me or submit a pull request for your desired authentication scheme.
|
93
93
|
|
94
|
-
|
94
|
+
|
95
95
|
Opro.setup do |config|
|
96
96
|
config.login_method { |controller, current_user| controller.sign_in(current_user, :bypass => true) }
|
97
97
|
config.logout_method { |controller, current_user| controller.sign_out(current_user) }
|
98
98
|
config.authenticate_user_method { |controller| controller.authenticate_user! }
|
99
99
|
end
|
100
|
-
```
|
101
100
|
|
102
101
|
## Permissions
|
103
102
|
|
@@ -129,14 +128,15 @@ The result is expected to be true or false.
|
|
129
128
|
|
130
129
|
## Refresh Tokens
|
131
130
|
|
132
|
-
For added security you can require access_tokens be refreshed by client applications. This will help to mitigate risk of a leaked access_token, and enable an all around more secure system. This security comes at a price however, since
|
133
|
-
|
134
|
-
By default refresh tokens are disabled, you can enable them in your application and set the timeout period of the tokens by adding this line to your configuration.
|
131
|
+
For added security you can require access_tokens be refreshed by client applications. This will help to mitigate risk of a leaked access_token, and enable an all around more secure system. This security comes at a price however, since implementing the `refresh_token` functionality in a client can be more difficult.
|
135
132
|
|
133
|
+
By default refresh tokens are enabled, you can disable them in your application and set the timeout period of the tokens by adding this line to your configuration.
|
136
134
|
|
137
135
|
config.require_refresh_within = 1.month
|
138
136
|
|
139
137
|
|
138
|
+
|
139
|
+
|
140
140
|
## Password Token Exchange
|
141
141
|
|
142
142
|
If a client application has a user's password and username/email they can exchange these for a token. This is much safer than storing username and password on a local device, but does not offer the traditional OAuth "Flow". Because of this all available permissions will be granted to the client application. If you want to disable this feature you can set the configuration below to false:
|
@@ -185,6 +185,29 @@ Then to let our server know if a given client has reached add this method, the o
|
|
185
185
|
Rate limited clients will receive an "unsuccessful" response to any query with a message letting them know they've been rate limited. Using redis with a rotating key generator based on (hour, daty, etc.) is one very common way to count rate, and implement the rate limits. Since there are so many different ways to implement this, we decided to give you a blank slate and implement it however you like. The default is that apps are not rate limited, and in general unlimited API access is the way to go, but if you do find abusive behavior you can always easily add in a rate limit.
|
186
186
|
|
187
187
|
|
188
|
+
## Configurable Authorization Header
|
189
|
+
|
190
|
+
By default oPRO allows clients to send their authorization token in a header. For example someone using an auth token of `9693accessTokena7ca570bbaf` could set the `Authorization` header in a request like this:
|
191
|
+
|
192
|
+
$ curl -H "Authorization: Bearer 9693accessTokena7ca570bbaf" "http://localhost:3000/oauth_test/show_me_the_money"
|
193
|
+
|
194
|
+
By default oPRO will accept `Bearer` and `token` in the authorization header, but if your client needs to send a custom auth header, you can add a custom extra regular expression to parse parse and return the token. For example if a client was setting the auth header like this:
|
195
|
+
|
196
|
+
$ curl -H "Authorization: cUsTomAuthHeader 9693accessTokena7ca570bbaf" "http://localhost:3000/oauth_test/show_me_the_money"
|
197
|
+
|
198
|
+
You could pull out the auth token using this regular expression `/cUsTomAuthHeader\s(.*)/`. If you're not great with regular expressions I highly recommend using [Rubular](http://rubular.com) to test regex matches. It is very important that we are "capturing" data with in between the `()` characters. The data returned inside of the parens are expected to be the auth token with no spaces or special characters such as new lines or quotes. To set parse this auth header in oPRO, you can specify the `header_auth_regex` in an initializer like this:
|
199
|
+
|
200
|
+
|
201
|
+
Opro.setup do |config|
|
202
|
+
config.auth_strategy = :devise
|
203
|
+
|
204
|
+
config.header_auth_regex = /cUsTomAuthHeader\s(.*)/
|
205
|
+
end
|
206
|
+
|
207
|
+
Now when a client sends your custom auth header it will be parsed correctly. Custom authorization headers should not be used for security through obscurity. They may be exposed in the docs or tests in a later iteration of oPRO, if you have strong feelings against this, then please open a pull request or send me a message stating your case.
|
208
|
+
|
209
|
+
|
210
|
+
|
188
211
|
## Assumptions
|
189
212
|
|
190
213
|
* You have a user model and that is what your authenticating
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/opro.rb
CHANGED
@@ -121,6 +121,18 @@ module Opro
|
|
121
121
|
end
|
122
122
|
|
123
123
|
|
124
|
+
# default to no match
|
125
|
+
def self.header_auth_regex
|
126
|
+
@header_auth_regex || /$^/
|
127
|
+
end
|
128
|
+
|
129
|
+
# Allows a user to set define a custom authorization regular expression
|
130
|
+
def self.header_auth_regex=(regexstring)
|
131
|
+
raise "not a regex" unless regexstring.is_a? Regexp
|
132
|
+
@header_auth_regex = regexstring
|
133
|
+
end
|
134
|
+
|
135
|
+
|
124
136
|
# Grossssss, don't use, needed to support `return` from the blocks provided to `find_user_for_auth`
|
125
137
|
def self.convert_to_lambda &block
|
126
138
|
obj = Object.new
|
@@ -66,7 +66,7 @@ module Opro
|
|
66
66
|
# grabs access_token from header if one is present
|
67
67
|
def oauth_access_token_from_header
|
68
68
|
auth_header = request.env["HTTP_AUTHORIZATION"]||""
|
69
|
-
match = auth_header.match(
|
69
|
+
match = auth_header.match(/token\W*([^\W]*)/) || auth_header.match(/^Bearer\s(.*)/) || auth_header.match(Opro.header_auth_regex)
|
70
70
|
return match[1] if match.present?
|
71
71
|
false
|
72
72
|
end
|
data/opro.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "opro"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["schneems"]
|
12
|
-
s.date = "2012-08-
|
12
|
+
s.date = "2012-08-09"
|
13
13
|
s.description = " Enable OAuth clients (iphone, android, web sites, etc.) to access and use your Rails application, what you do with it is up to you"
|
14
14
|
s.email = "richard.schneeman@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -47,6 +47,16 @@ class OauthTokenTest < ActionDispatch::IntegrationTest
|
|
47
47
|
post oauth_tests_path, {}, headers
|
48
48
|
|
49
49
|
assert_equal 200, status
|
50
|
+
|
51
|
+
headers = {"HTTP_AUTHORIZATION" => "token=\"#{access_token}\""}
|
52
|
+
post oauth_tests_path, {}, headers
|
53
|
+
|
54
|
+
Opro.setup {|config| config.header_auth_regex = /Zoro\s(.*)/ }
|
55
|
+
|
56
|
+
headers = {"HTTP_AUTHORIZATION" => "Zoro #{access_token}"}
|
57
|
+
post oauth_tests_path, {}, headers
|
58
|
+
|
59
|
+
assert_equal 200, status
|
50
60
|
end
|
51
61
|
|
52
62
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70236452285760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70236452285760
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rails
|
27
|
-
requirement: &
|
27
|
+
requirement: &70236452291300 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.1.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70236452291300
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bluecloth
|
38
|
-
requirement: &
|
38
|
+
requirement: &70236452293960 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70236452293960
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
|
-
requirement: &
|
49
|
+
requirement: &70236452295480 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70236452295480
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: timecop
|
60
|
-
requirement: &
|
60
|
+
requirement: &70236452297460 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70236452297460
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: jeweler
|
71
|
-
requirement: &
|
71
|
+
requirement: &70236456034720 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 1.6.4
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70236456034720
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: bundler
|
82
|
-
requirement: &
|
82
|
+
requirement: &70236456033900 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 1.1.3
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70236456033900
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: capybara
|
93
|
-
requirement: &
|
93
|
+
requirement: &70236456033180 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: 0.4.0
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70236456033180
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: sqlite3
|
104
|
-
requirement: &
|
104
|
+
requirement: &70236456032180 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70236456032180
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: launchy
|
115
|
-
requirement: &
|
115
|
+
requirement: &70236456031660 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70236456031660
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: devise
|
126
|
-
requirement: &
|
126
|
+
requirement: &70236456030960 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70236456030960
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: rcov
|
137
|
-
requirement: &
|
137
|
+
requirement: &70236456030160 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *70236456030160
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: simplecov
|
148
|
-
requirement: &
|
148
|
+
requirement: &70236456029360 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,7 +153,7 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :development
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *70236456029360
|
157
157
|
description: ! ' Enable OAuth clients (iphone, android, web sites, etc.) to access
|
158
158
|
and use your Rails application, what you do with it is up to you'
|
159
159
|
email: richard.schneeman@gmail.com
|
@@ -280,7 +280,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
280
280
|
version: '0'
|
281
281
|
segments:
|
282
282
|
- 0
|
283
|
-
hash:
|
283
|
+
hash: -2359912822064241279
|
284
284
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
285
285
|
none: false
|
286
286
|
requirements:
|