oauth3 1.0.3 → 1.1.2
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.
- checksums.yaml +4 -4
- data/lib/oauth3.rb +114 -19
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b450936d14db6f539be592a4352d6874c0837eb9
|
4
|
+
data.tar.gz: 2ccf0d609255eb79501b39d27e4d7880d9976a00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8377043e6978b8eea92c1ef387d5c0708d7dc49ba9bb854fa53d11862668760e0b81936f53b5bc89852736f10899acbb07ae2c144dd48a92ea6bef0a9a62ef62
|
7
|
+
data.tar.gz: f0bc11d2dc4f342660b3226e6c621be42ceb11877b645b44615dce74bb5ead9108d3a8e1ced022802a54df6d9fc949254a867f961e082c0a2b3f2c272a4512b5
|
data/lib/oauth3.rb
CHANGED
@@ -6,6 +6,14 @@ class Oauth3
|
|
6
6
|
#attr_reader :client
|
7
7
|
#attr_accessor :options
|
8
8
|
|
9
|
+
OAuth2::Response.register_parser(:text, 'text/plain') do |body|
|
10
|
+
if '{' == body[0] or '[' == body[0]
|
11
|
+
MultiJson.load(body) rescue body
|
12
|
+
else
|
13
|
+
Rack::Utils.parse_query(body)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
def initialize(registrar, options={})
|
10
18
|
# make sure all options for the OAuth module and faraday
|
11
19
|
# pass all the way down
|
@@ -25,14 +33,25 @@ class Oauth3
|
|
25
33
|
return @providers[provider_uri][:directive]
|
26
34
|
end
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
registration = @registrar.get(provider_uri)
|
37
|
+
dynamic = true
|
38
|
+
|
39
|
+
if registration and registration['directives']
|
40
|
+
directives = registration['directives']
|
41
|
+
dynamic = false
|
42
|
+
else
|
43
|
+
# TODO if there's no prefix (https://), add it first
|
44
|
+
# TODO if the directive is stale, refresh it
|
45
|
+
http = HTTPClient.new()
|
46
|
+
response = http.get_content("#{provider_uri}/oauth3.json")
|
47
|
+
directives = JSON.parse(response)
|
48
|
+
end
|
49
|
+
|
32
50
|
@providers[provider_uri] = {
|
33
51
|
provider_uri: provider_uri,
|
34
|
-
directive:
|
35
|
-
timestamp: Time.now
|
52
|
+
directive: directives,
|
53
|
+
timestamp: Time.now,
|
54
|
+
dynamic: dynamic
|
36
55
|
}
|
37
56
|
@providers[provider_uri][:directive]
|
38
57
|
end
|
@@ -47,6 +66,8 @@ class Oauth3
|
|
47
66
|
client_options[:site] = ""
|
48
67
|
client_options[:authorize_url] = get_directive(provider_uri)['authorization_dialog']['url']
|
49
68
|
client_options[:token_url] = get_directive(provider_uri)['access_token']['url']
|
69
|
+
token_method = (get_directive(provider_uri)['access_token']['method'] || 'POST').downcase.to_sym
|
70
|
+
client_options[:token_method] = token_method
|
50
71
|
|
51
72
|
@clients[provider_uri] = OAuth2::Client.new(
|
52
73
|
@registrar.get(provider_uri)['id'],
|
@@ -60,19 +81,91 @@ class Oauth3
|
|
60
81
|
(0...50).map { ('a'..'z').to_a[rand(26)] }.join
|
61
82
|
end
|
62
83
|
|
63
|
-
def authorize_url(provider_uri)
|
64
|
-
|
84
|
+
def authorize_url(provider_uri, params)
|
85
|
+
provider_uri = @@oauth3.normalize_provider_uri(provider_uri)
|
86
|
+
authorization_code_callback_uri = @options[:authorization_code_callback_uri] || @options[:redirect_uri]
|
65
87
|
rnd = random_string()
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
88
|
+
|
89
|
+
@states[rnd] = {
|
90
|
+
created_at: Time.now,
|
91
|
+
provider_uri: provider_uri,
|
92
|
+
params: params
|
93
|
+
}
|
94
|
+
|
95
|
+
get_oauth2_client(provider_uri).auth_code.authorize_url({
|
96
|
+
# Note that no parameters can be passed tothis redirect
|
97
|
+
# It is required to be verbatim for Facebook and probably many other providers
|
98
|
+
redirect_uri: authorization_code_callback_uri,
|
99
|
+
scope: params[:scope],
|
100
|
+
state: rnd
|
101
|
+
})
|
102
|
+
end
|
103
|
+
|
104
|
+
def authorization_code_callback(params)
|
105
|
+
# TODO needs error handling function to make this DRY
|
106
|
+
|
107
|
+
server_state = params[:state] or params[:server_state]
|
108
|
+
if not server_state
|
109
|
+
if params[:error]
|
110
|
+
return params
|
111
|
+
else
|
112
|
+
return { error: "E_NO_STATE", error_description: "provider_did_not_return_state" }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
meta_state = @@oauth3.get_state(server_state)
|
117
|
+
if not meta_state
|
118
|
+
return { error: "E_INVALID_SERVER_STATE", error_description: "server_state_missing_or_expired" }
|
119
|
+
end
|
120
|
+
|
121
|
+
# TODO provider_uri should not be necessary because we have state
|
122
|
+
# (but I don't think oauth3.html implements that completely yet)
|
123
|
+
# meta_state = { created_at, provider_uri, params }
|
124
|
+
browser_params = meta_state[:params].merge({ provider_uri: meta_state[:provider_uri] })
|
125
|
+
if not browser_params
|
126
|
+
browser_params = { error: "E_SANITY_FAIL", error_description: "sanity fail: server_state missing browser_params" }
|
127
|
+
params.delete(:state)
|
128
|
+
return params.merge(browser_params)
|
129
|
+
end
|
130
|
+
|
131
|
+
browser_state = browser_params[:state] or browser_params[:browser_state]
|
132
|
+
if not browser_state
|
133
|
+
browser_params[:error] = "E_INVALID_BROWSER_STATE"
|
134
|
+
browser_params[:error_description] = "server_state missing or expired"
|
135
|
+
return browser_params
|
136
|
+
end
|
137
|
+
|
138
|
+
# TODO decide on one or the other. Favor explicit to avoid confusion?
|
139
|
+
result_params = { browser_state: browser_state, state: browser_state }
|
140
|
+
if params[:error]
|
141
|
+
params.delete(:state)
|
142
|
+
return params.merge(result_params)
|
143
|
+
end
|
144
|
+
|
145
|
+
code = params[:code]
|
146
|
+
|
147
|
+
if not code
|
148
|
+
result_params[:error] = "E_INVALID_BROWSER_STATE"
|
149
|
+
result_params[:error_description] = "state_missing_or_expired"
|
150
|
+
params.delete(:state)
|
151
|
+
return params.merge(result_params)
|
152
|
+
end
|
153
|
+
|
154
|
+
provider_uri = browser_params[:provider_uri]
|
155
|
+
if token = @@oauth3.get_token(provider_uri, code).token
|
156
|
+
result_params[:access_token] = token
|
157
|
+
end
|
158
|
+
|
159
|
+
# Note in the future the server will send back
|
160
|
+
# granted_scopes=foo,bar,baz,etc
|
161
|
+
# expires_at=2015-04-01T12:30:00.000Z
|
162
|
+
# app_scoped_id=<<default-account-app-scoped-id>>
|
163
|
+
params.delete(:state)
|
164
|
+
params.merge(result_params)
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_state(state)
|
168
|
+
@states.delete(state)
|
76
169
|
end
|
77
170
|
|
78
171
|
def validate_state(provider_uri, state)
|
@@ -81,7 +174,9 @@ class Oauth3
|
|
81
174
|
end
|
82
175
|
|
83
176
|
def get_token(provider_uri, code)
|
84
|
-
get_oauth2_client(provider_uri).auth_code.get_token(code
|
177
|
+
get_oauth2_client(provider_uri).auth_code.get_token(code, {
|
178
|
+
redirect_uri: @options[:authorization_code_callback_uri]
|
179
|
+
})
|
85
180
|
end
|
86
181
|
|
87
182
|
def get_profile(provider_uri, token)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oauth3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AJ ONeal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oauth2
|
@@ -52,7 +52,8 @@ dependencies:
|
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.8.2
|
55
|
-
description:
|
55
|
+
description: OAuth3 (backwards compatible with OAuth2) authentication strategy for
|
56
|
+
connecting to any OAuth2 / OAuth3 provider in Ruby / Sinatra / etc
|
56
57
|
email: coolaj86@gmail.com
|
57
58
|
executables: []
|
58
59
|
extensions: []
|