oo_auth 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.
- checksums.yaml +7 -0
- data/CHANGELOG +3 -0
- data/LICENSE +20 -0
- data/README.md +95 -0
- data/lib/oo_auth/configuration_error.rb +3 -0
- data/lib/oo_auth/constants.rb +19 -0
- data/lib/oo_auth/credentials.rb +22 -0
- data/lib/oo_auth/nonce/abstract_store.rb +13 -0
- data/lib/oo_auth/nonce/redis_store.rb +28 -0
- data/lib/oo_auth/nonce.rb +48 -0
- data/lib/oo_auth/request_proxy.rb +135 -0
- data/lib/oo_auth/signature.rb +55 -0
- data/lib/oo_auth/version.rb +3 -0
- data/lib/oo_auth.rb +94 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e5200d37778ac2220a1003d8551caf8c12d69fbd
|
4
|
+
data.tar.gz: 5a10c0b125e737c49ca54ae444f9205bb06671e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d4f0c1423e3e41f26ff2bce7acdb83cb42a7b623732385d7259a0cb88f722eb8b8779b2481aded7f454c197e2f47c94d4b00ef88fa39b83ade09323e1399a6ea
|
7
|
+
data.tar.gz: 32d8a1dc341e408ca95fcb50fec6fa58a7621309ea7c95de0286c9a64013b08e5b0315ac5f4f236e6e007e9567fbf6b7e941d93867d306932070dd85d6fd9444
|
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Matthias Grosser
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
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, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
[](http://badge.fury.io/rb/oo_auth) [](https://codeclimate.com/github/mtgrosser/oo_auth)
|
2
|
+
|
3
|
+
# oo_auth
|
4
|
+
|
5
|
+
OAuth Out Of Band - Sign, verify and authorize OAuth requests
|
6
|
+
|
7
|
+
OoAuth is a stripped-down implementation of the OAuth 1.0a protocol.
|
8
|
+
|
9
|
+
It only cares for signing and verifying OAuth requests, supporting both
|
10
|
+
```Net::HTTP``` and ```ActionDispatch::Request```.
|
11
|
+
|
12
|
+
OoAuth does not include any models or controllers dealing with token and
|
13
|
+
secret exchange, storage or lookup. Instead, it offers a simplistic API
|
14
|
+
where you can hook your own implementations as desired.
|
15
|
+
|
16
|
+
OoAuth comes with optional Redis support for short-time high performance storage
|
17
|
+
of OAuth nonces.
|
18
|
+
|
19
|
+
It can be used for implementing OAuth consumers as well as providers.
|
20
|
+
|
21
|
+
## Install
|
22
|
+
|
23
|
+
In your Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'oo_auth'
|
27
|
+
```
|
28
|
+
|
29
|
+
## Prerequisites
|
30
|
+
|
31
|
+
OoAuth requires your application to provide stores for authorization tokens
|
32
|
+
and OAuth nonces.
|
33
|
+
|
34
|
+
OoAuth stores can be simple lambdas or regular ruby objects.
|
35
|
+
|
36
|
+
### Authorization store
|
37
|
+
|
38
|
+
The authorization store should return an instance of ```OoAuth::Credentials```.
|
39
|
+
It can either be a lambda or an object implementing the `authorization` method.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# your own implementation in SomeClass model
|
43
|
+
OoAuth.authorization_store = lambda { |consumer_key, token| SomeClass.find_by_tokens(consumer_key, token) }
|
44
|
+
```
|
45
|
+
```ruby
|
46
|
+
# direct lookup
|
47
|
+
OoAuth.authorization_store = User
|
48
|
+
```
|
49
|
+
### Nonce store
|
50
|
+
```ruby
|
51
|
+
require 'oo_auth/nonce/redis_store'
|
52
|
+
|
53
|
+
OoAuth.nonce_store = OoAuth::Nonce::RedisStore.new(namespace: 'foobar')
|
54
|
+
```
|
55
|
+
## Use
|
56
|
+
|
57
|
+
### OAuth consumer
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
http = Net::HTTP.new('photos.example.net', Net::HTTP.http_default_port)
|
61
|
+
request = Net::HTTP::Get.new('/photos?file=vacation.jpg&size=original')
|
62
|
+
|
63
|
+
credentials = OoAuth::Credentials.new('consumer_key',
|
64
|
+
'consumer_secret',
|
65
|
+
'access_token',
|
66
|
+
'access_token_secret')
|
67
|
+
|
68
|
+
OoAuth.sign!(http, request, credentials)
|
69
|
+
|
70
|
+
request['Authorization']
|
71
|
+
=> "OAuth oauth_version=\"1.0\", oauth_nonce=\"ly9V24IvFMhEGSlGW1tPniUVnVzQkWvn4W6Bwtmc4\", oauth_timestamp=\"1384116351\", oauth_signature_method=\"HMAC-SHA1\", oauth_consumer_key=\"consumer_key\", oauth_token=\"access_token\", oauth_signature=\"5G1ktyWhicZGnSu2AKkjok9%2BMPo%3D\""
|
72
|
+
```
|
73
|
+
|
74
|
+
### OAuth provider
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
class FoobarController < ApplicationController
|
78
|
+
|
79
|
+
before_filter :oauth_required
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def oauth_required
|
84
|
+
if authorization = OoAuth.authorize!(request)
|
85
|
+
self.current_user = authorization.user
|
86
|
+
else
|
87
|
+
render nothing: true, status: 401
|
88
|
+
end
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
## TODO
|
94
|
+
|
95
|
+
* Support POST body signing
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OoAuth
|
2
|
+
|
3
|
+
# request tokens are passed between the consumer and the provider out of
|
4
|
+
# band (i.e. callbacks cannot be used), per section 6.1.1
|
5
|
+
OUT_OF_BAND = 'oob'
|
6
|
+
|
7
|
+
# FIXME: ordering
|
8
|
+
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
9
|
+
PARAMETERS = %w(oauth_callback oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier oauth_version oauth_signature oauth_body_hash)
|
10
|
+
|
11
|
+
# reserved character regexp, per section 5.1
|
12
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
|
13
|
+
|
14
|
+
# OoAuth only supports HMAC-SHA1
|
15
|
+
SIGNATURE_METHOD = 'HMAC-SHA1'
|
16
|
+
|
17
|
+
MAX_TIMESTAMP_DEVIATION = 5 * 60
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module OoAuth
|
2
|
+
class Credentials
|
3
|
+
AUTH_ATTRIBUTES = [:consumer_key, :consumer_secret, :token, :token_secret]
|
4
|
+
|
5
|
+
attr_reader *AUTH_ATTRIBUTES
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def generate
|
9
|
+
new(*4.times.collect { OoAuth.generate_key })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(consumer_key, consumer_secret, token, token_secret)
|
14
|
+
@consumer_key, @consumer_secret, @token, @token_secret = consumer_key, consumer_secret, token, token_secret
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes
|
18
|
+
AUTH_ATTRIBUTES.inject({}) { |hsh, attr| hsh.update(attr => send(attr)) }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OoAuth
|
2
|
+
class Nonce
|
3
|
+
class RedisStore < AbstractStore
|
4
|
+
attr_reader :redis, :namespace, :ttl
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
options.symbolize_keys!
|
8
|
+
@namespace = options.delete(:namespace)
|
9
|
+
@ttl = options.delete(:ttl) || 15.minutes
|
10
|
+
@redis = Redis.new(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(nonce)
|
14
|
+
return nonce if @redis.set(key(nonce), '1', { nx: true, ex: ttl })
|
15
|
+
false
|
16
|
+
rescue Errno::ECONNREFUSED
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def key(nonce)
|
23
|
+
"#{@namespace}:oo_auth_nonce:#{nonce.timestamp}:#{nonce.value}"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module OoAuth
|
2
|
+
class Nonce
|
3
|
+
MAX_LENGTH = 255
|
4
|
+
|
5
|
+
attr_reader :value, :timestamp, :errors
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def store
|
9
|
+
OoAuth.nonce_store || fail(ConfigurationError, 'no nonce store set')
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(nonce)
|
13
|
+
if store.respond_to?(:call)
|
14
|
+
store.call(nonce)
|
15
|
+
elsif store.respond_to?(:create)
|
16
|
+
store.create(nonce)
|
17
|
+
else
|
18
|
+
fail ConfigurationError, 'nonce store not callable'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def remember(value, timestamp)
|
23
|
+
new(value, timestamp).save
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate
|
27
|
+
new(OoAuth.generate_nonce, Time.now.utc.to_i)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(value, timestamp)
|
32
|
+
@value, @timestamp = value, timestamp.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid?
|
36
|
+
@errors = []
|
37
|
+
@errors << 'nonce value cannot be blank' if value.to_s == ''
|
38
|
+
@errors << 'nonce value too big' if value.size > MAX_LENGTH
|
39
|
+
@errors << 'illegal nonce timestamp' if timestamp <= 0
|
40
|
+
@errors.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
!!(valid? && self.class.create(self))
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module OoAuth
|
2
|
+
class RequestProxy
|
3
|
+
|
4
|
+
attr_reader :port, :ssl, :host, :path, :headers, :method, :body
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
|
9
|
+
# Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and
|
10
|
+
# removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a
|
11
|
+
# valid hash. Does not validate the keys or values.
|
12
|
+
#
|
13
|
+
# hash = parse(headers['Authorization'] || headers['WWW-Authenticate'])
|
14
|
+
# hash['oauth_timestamp']
|
15
|
+
# #=>"1234567890"
|
16
|
+
#
|
17
|
+
def parse(header)
|
18
|
+
header = header.to_s
|
19
|
+
return unless header.start_with?('OAuth ')
|
20
|
+
# decompose
|
21
|
+
params = header[6, header.length].split(',').inject({}) do |hsh, str|
|
22
|
+
key, value = str.split('=').map { |s| OoAuth.unescape(s.strip) }
|
23
|
+
if PARAMETERS.include?(key)
|
24
|
+
hsh[key] = value.sub(/^\"(.*)\"$/, '\1')
|
25
|
+
end
|
26
|
+
hsh
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
case args.size
|
33
|
+
when 1 # ActionDispatch request
|
34
|
+
request = args[0]
|
35
|
+
@port = request.port
|
36
|
+
@ssl = request.ssl?
|
37
|
+
@path = request.fullpath
|
38
|
+
@host = request.host
|
39
|
+
@headers = request.headers
|
40
|
+
when 2 # Net:HTTP request
|
41
|
+
http, request = args[0], args[1]
|
42
|
+
@port = http.port
|
43
|
+
@ssl = http.use_ssl?
|
44
|
+
@path = request.path
|
45
|
+
@host = http.address
|
46
|
+
@headers = request
|
47
|
+
else
|
48
|
+
raise ArgumentError, 'wrong number of arguments'
|
49
|
+
end
|
50
|
+
@method = request.method
|
51
|
+
@body = request.body
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalized_request_uri
|
55
|
+
if self.port == Net::HTTP.default_port
|
56
|
+
scheme, port = :http, nil
|
57
|
+
elsif self.port == Net::HTTP.https_default_port
|
58
|
+
scheme, port = :https, nil
|
59
|
+
elsif ssl
|
60
|
+
scheme, port = :https, self.port
|
61
|
+
else
|
62
|
+
scheme, port = :http, self.port
|
63
|
+
end
|
64
|
+
|
65
|
+
uri = "#{scheme}://#{host.downcase}"
|
66
|
+
uri += ":#{port}" if port
|
67
|
+
uri += path.split('?').first
|
68
|
+
uri
|
69
|
+
end
|
70
|
+
|
71
|
+
def oauth_params
|
72
|
+
self.class.parse(authorization)
|
73
|
+
end
|
74
|
+
|
75
|
+
def oauth_params_without_signature
|
76
|
+
params = oauth_params
|
77
|
+
params.delete('oauth_signature')
|
78
|
+
params
|
79
|
+
end
|
80
|
+
|
81
|
+
def authorization
|
82
|
+
headers['Authorization']
|
83
|
+
end
|
84
|
+
|
85
|
+
def authorization=(header)
|
86
|
+
headers['Authorization'] = header
|
87
|
+
end
|
88
|
+
|
89
|
+
PARAMETERS.each do |parameter|
|
90
|
+
define_method "#{parameter[6..-1]}" do
|
91
|
+
oauth_params[parameter]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def post?
|
96
|
+
'POST' == method
|
97
|
+
end
|
98
|
+
|
99
|
+
def signature_base_string(params = {})
|
100
|
+
encoded_params = params_encode(params_array(self) + params_array(params))
|
101
|
+
OoAuth.encode(method, normalized_request_uri, encoded_params)
|
102
|
+
end
|
103
|
+
|
104
|
+
# FIXME: cf nested params implementation in oauth gem
|
105
|
+
# TODO: support oauth body signature for non-formencoded content types
|
106
|
+
def params_array(object)
|
107
|
+
case object
|
108
|
+
when Array then object
|
109
|
+
when Hash then object.to_a
|
110
|
+
when RequestProxy
|
111
|
+
tmp = object.path.split('?')
|
112
|
+
params = tmp[1] ? params_decode(tmp[1]) : []
|
113
|
+
if object.post? && object.headers['Content-Type'].to_s.start_with?('application/x-www-form-urlencoded')
|
114
|
+
params.concat params_decode(object.body)
|
115
|
+
end
|
116
|
+
params
|
117
|
+
else
|
118
|
+
raise "error: cannot convert #{object.class} object to params array"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def params_decode(string)
|
123
|
+
string.split('&').each_with_object([]) do |param, array|
|
124
|
+
k, v = *param.split('=')
|
125
|
+
array << [OoAuth.unescape(k), v && OoAuth.unescape(v)]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# cf. http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
|
130
|
+
def params_encode(params)
|
131
|
+
params.map { |k, v| [OoAuth.escape(k), OoAuth.escape(v)] }.sort.map { |k, v| "#{k}=#{v}" }.join('&')
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module OoAuth
|
2
|
+
module Signature
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def hmac_sha1_signature(base_string, consumer_secret, token_secret)
|
6
|
+
Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, OoAuth.encode(consumer_secret, token_secret), base_string))
|
7
|
+
end
|
8
|
+
|
9
|
+
def calculate_signature(proxy, credentials, params)
|
10
|
+
hmac_sha1_signature(proxy.signature_base_string(params), credentials.consumer_secret, credentials.token_secret)
|
11
|
+
end
|
12
|
+
|
13
|
+
def sign!(proxy, credentials)
|
14
|
+
params = {
|
15
|
+
oauth_version: '1.0',
|
16
|
+
oauth_nonce: OoAuth.generate_nonce,
|
17
|
+
oauth_timestamp: OoAuth.timestamp,
|
18
|
+
oauth_signature_method: SIGNATURE_METHOD,
|
19
|
+
oauth_consumer_key: credentials.consumer_key,
|
20
|
+
oauth_token: credentials.token
|
21
|
+
}
|
22
|
+
|
23
|
+
params[:oauth_signature] = calculate_signature(proxy, credentials, params)
|
24
|
+
|
25
|
+
proxy.authorization = authorization_header(params)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Check signature validity without remembering nonce - DO NOT use to authorize actual requests
|
29
|
+
def valid?(proxy, credentials)
|
30
|
+
verify_timestamp!(proxy) &&
|
31
|
+
calculate_signature(proxy, credentials, proxy.oauth_params_without_signature) == proxy.signature
|
32
|
+
end
|
33
|
+
|
34
|
+
# Verify signature and remember nonce - use this to authorize actual requests
|
35
|
+
def verify!(proxy, credentials)
|
36
|
+
valid?(proxy, credentials) && remember_nonce!(proxy)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def verify_timestamp!(proxy)
|
42
|
+
(OoAuth.timestamp - proxy.timestamp.to_i).abs < MAX_TIMESTAMP_DEVIATION
|
43
|
+
end
|
44
|
+
|
45
|
+
def remember_nonce!(proxy)
|
46
|
+
Nonce.remember(proxy.nonce, proxy.timestamp)
|
47
|
+
end
|
48
|
+
|
49
|
+
def authorization_header(params)
|
50
|
+
'OAuth ' + params.map { |k, v| "#{OoAuth.escape(k)}=\"#{OoAuth.escape(v)}\"" }.join(', ')
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/oo_auth.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
require 'oo_auth/version'
|
7
|
+
require 'oo_auth/constants'
|
8
|
+
require 'oo_auth/configuration_error'
|
9
|
+
require 'oo_auth/nonce'
|
10
|
+
require 'oo_auth/nonce/abstract_store'
|
11
|
+
require 'oo_auth/request_proxy'
|
12
|
+
require 'oo_auth/credentials'
|
13
|
+
require 'oo_auth/signature'
|
14
|
+
|
15
|
+
module OoAuth
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Initialize with instance of store
|
19
|
+
# OoAuth.nonce_store = OoAuth::Nonce::RedisStore.new(namespace: 'foo')
|
20
|
+
attr_accessor :nonce_store
|
21
|
+
|
22
|
+
|
23
|
+
# Define a lookup method for access token verification
|
24
|
+
# It should be callable (proc) or provide an +authorization+ method,
|
25
|
+
# with the argument being the consumer key and token.
|
26
|
+
# The proc or method call should return
|
27
|
+
# - if the consumer key/token combination exists:
|
28
|
+
# an object which responding to +credentials+ with an
|
29
|
+
# initialized instance of
|
30
|
+
# OoAuth::Credentials
|
31
|
+
# - nil otherwise.
|
32
|
+
attr_accessor :authorization_store
|
33
|
+
|
34
|
+
# Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
|
35
|
+
# characters removed.
|
36
|
+
def generate_key(size = 32)
|
37
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :generate_nonce, :generate_key
|
41
|
+
|
42
|
+
# Escape +value+ by URL encoding all non-reserved character.
|
43
|
+
#
|
44
|
+
# See Also: {OAuth core spec version 1.0, section 5.1}[http://oauth.net/core/1.0#rfc.section.5.1]
|
45
|
+
def escape(value)
|
46
|
+
URI.escape(value.to_s, RESERVED_CHARACTERS)
|
47
|
+
rescue ArgumentError
|
48
|
+
URI.escape(value.to_s.force_encoding(Encoding::UTF_8), RESERVED_CHARACTERS)
|
49
|
+
end
|
50
|
+
|
51
|
+
def unescape(value)
|
52
|
+
URI.unescape(value.gsub('+', '%2B'))
|
53
|
+
end
|
54
|
+
|
55
|
+
# cf. http://tools.ietf.org/html/rfc5849#section-3.4.1.1
|
56
|
+
# cf. http://tools.ietf.org/html/rfc5849#section-3.4.4
|
57
|
+
def encode(*components)
|
58
|
+
components.map { |component| OoAuth.escape(component) }.join('&')
|
59
|
+
end
|
60
|
+
|
61
|
+
# Current UTC timestamp
|
62
|
+
def timestamp
|
63
|
+
Time.now.utc.to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def authorization(consumer_key, token)
|
67
|
+
if authorization_store.respond_to?(:call)
|
68
|
+
authorization_store.call(consumer_key, token)
|
69
|
+
elsif authorization_store.respond_to?(:authorization)
|
70
|
+
authorization_store.authorization(consumer_key, token)
|
71
|
+
else
|
72
|
+
fail ConfigurationError, 'authorization store not callable'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Use this to sign Net::HTTP or ActionDispatch requests
|
77
|
+
def sign!(*args)
|
78
|
+
credentials = args.pop
|
79
|
+
proxy = RequestProxy.new(*args)
|
80
|
+
Signature.sign!(proxy, credentials)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Use this in your controllers to verify the OAuth signature
|
84
|
+
# of a request.
|
85
|
+
def authorize!(*args)
|
86
|
+
proxy = RequestProxy.new(*args)
|
87
|
+
return unless authorization = self.authorization(proxy.consumer_key, proxy.token)
|
88
|
+
return unless Signature.verify!(proxy, authorization.credentials)
|
89
|
+
authorization
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oo_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthias Grosser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: byebug
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simplecov
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.7
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: timecop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.6.3
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.6.3
|
83
|
+
description: Out Of Band OAuth
|
84
|
+
email: mtgrosser@gmx.net
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- lib/oo_auth/configuration_error.rb
|
90
|
+
- lib/oo_auth/constants.rb
|
91
|
+
- lib/oo_auth/credentials.rb
|
92
|
+
- lib/oo_auth/nonce/abstract_store.rb
|
93
|
+
- lib/oo_auth/nonce/redis_store.rb
|
94
|
+
- lib/oo_auth/nonce.rb
|
95
|
+
- lib/oo_auth/request_proxy.rb
|
96
|
+
- lib/oo_auth/signature.rb
|
97
|
+
- lib/oo_auth/version.rb
|
98
|
+
- lib/oo_auth.rb
|
99
|
+
- LICENSE
|
100
|
+
- README.md
|
101
|
+
- CHANGELOG
|
102
|
+
homepage: http://github.com/mtgrosser/oo_auth
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.0.3
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: OAuth without the callbacks
|
126
|
+
test_files: []
|