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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/oauth3.rb +114 -19
  3. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4151158493b6c0035e630b0e188339a4c7b05c34
4
- data.tar.gz: 59f10fd777ffebec56190c0c180b49e97c301973
3
+ metadata.gz: b450936d14db6f539be592a4352d6874c0837eb9
4
+ data.tar.gz: 2ccf0d609255eb79501b39d27e4d7880d9976a00
5
5
  SHA512:
6
- metadata.gz: 6d64fc1d31adc1ebc771916af940382e152ef9a8e846c9829f07b1171f9cd004196cde2e22eedca277314780ecb5386cf43bf712bbaf8a0ef172e0c584217a1d
7
- data.tar.gz: 44566e908c777ca01c949a35aca115f3dde3ed74253c85efa2ac62c48a8575dd0f65ba8e70de5af36eb25b7209192e01cd3944d4e44c90560e5b34aae534ea07
6
+ metadata.gz: 8377043e6978b8eea92c1ef387d5c0708d7dc49ba9bb854fa53d11862668760e0b81936f53b5bc89852736f10899acbb07ae2c144dd48a92ea6bef0a9a62ef62
7
+ data.tar.gz: f0bc11d2dc4f342660b3226e6c621be42ceb11877b645b44615dce74bb5ead9108d3a8e1ced022802a54df6d9fc949254a867f961e082c0a2b3f2c272a4512b5
@@ -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
- # TODO if there's no prefix (https://), add it first
29
- # TODO if the directive is stale, refresh it
30
- http = HTTPClient.new()
31
- response = http.get_content("#{provider_uri}/oauth3.json")
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: JSON.parse(response),
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
- redirect_uri = @options[:redirect_uri]
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
- @states[rnd] = Time.now
67
-
68
- # TODO state should go in params to the provider, not the redirect directly
69
- # ... but ultimately it has the same effect, so whatever
70
- get_oauth2_client(provider_uri).auth_code.authorize_url(
71
- # TODO (change ? to & if there's already a ?)
72
- redirect_uri: redirect_uri +
73
- "?provider_uri=" + URI.encode_www_form_component(provider_uri) +
74
- "&state=" + rnd
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.0.3
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-01 00:00:00.000000000 Z
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: []