oauth 0.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oauth might be problematic. Click here for more details.

data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.1 2007-11-26
2
+
3
+ * 1 First release as a GEM
4
+ * Moved all non rails functions into this GEM from the Rails plugin http://code.google.com/p/oauth-plugin/
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Pelle Braendgaard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,35 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/oauth.rb
9
+ lib/oauth/consumer.rb
10
+ lib/oauth/consumer_credentials.rb
11
+ lib/oauth/key.rb
12
+ lib/oauth/oauth_test_helper.rb
13
+ lib/oauth/request.rb
14
+ lib/oauth/server.rb
15
+ lib/oauth/signature.rb
16
+ lib/oauth/token.rb
17
+ lib/oauth/version.rb
18
+ script/destroy
19
+ script/generate
20
+ script/txt2html
21
+ setup.rb
22
+ tasks/deployment.rake
23
+ tasks/environment.rake
24
+ tasks/website.rake
25
+ test/test_consumer.rb
26
+ test/test_helper.rb
27
+ test/test_oauth.rb
28
+ test/test_request.rb
29
+ test/test_server.rb
30
+ test/test_signature.rb
31
+ website/index.html
32
+ website/index.txt
33
+ website/javascripts/rounded_corners_lite.inc.js
34
+ website/stylesheets/screen.css
35
+ website/template.rhtml
data/README.txt ADDED
@@ -0,0 +1 @@
1
+ README
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/config/hoe.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'oauth/version'
2
+
3
+ AUTHOR = 'Pelle Braendgaard' # can also be an array of Authors
4
+ EMAIL = "pelleb@gmail.com"
5
+ DESCRIPTION = "OAuth Core Ruby implementation"
6
+ GEM_NAME = 'oauth' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'oauth' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Oauth::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'oauth documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
62
+ p.extra_deps = [['ruby-hmac','>= 0.3.1'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
+
64
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
+
66
+ end
67
+
68
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
69
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
70
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
71
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'oauth'
data/lib/oauth.rb ADDED
@@ -0,0 +1,14 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'rubygems'
3
+ require 'oauth/key'
4
+ require 'oauth/request'
5
+ require 'oauth/signature'
6
+ require 'oauth/consumer_credentials'
7
+ require 'oauth/consumer'
8
+ require 'oauth/server'
9
+ require 'oauth/token'
10
+ require 'oauth/oauth_test_helper'
11
+
12
+ module OAuth
13
+
14
+ end
@@ -0,0 +1,123 @@
1
+ module OAuth
2
+ class Consumer<ConsumerCredentials
3
+
4
+ @@default_params={
5
+ # Signature method used by server. Defaults to HMAC-SHA1
6
+ :oauth_signature_method=>'HMAC-SHA1',
7
+
8
+ # default paths on site. These are the same as the defaults set up by the generators
9
+ :request_token_path=>'/oauth/request_token',
10
+ :authorize_path=>'/oauth/authorize',
11
+ :access_token_path=>'/oauth/access_token',
12
+
13
+ # How do we send the oauth values to the server see
14
+ # http://oauth.googlecode.com/svn/spec/branches/1.0/drafts/6/spec.html#consumer_req_param for more info
15
+ #
16
+ # Possible values:
17
+ #
18
+ # :authorize - via the Authorize header (Default) ( option 1. in spec)
19
+ # :post - url form encoded in body of POST request ( option 2. in spec)
20
+ # :query - via the query part of the url ( option 3. in spec)
21
+ :auth_method=>:authorize,
22
+
23
+ # Default http method used for OAuth Token Requests (defaults to :post)
24
+ :http_method=>:post,
25
+
26
+ :oauth_version=>"1.0"
27
+ }
28
+
29
+ attr_accessor :site,:params
30
+
31
+ # Create a new consumer instance by passing it a configuration hash:
32
+ #
33
+ # @consumer=OAuth::Consumer.new( {
34
+ # :consumer_key=>"key",
35
+ # :consumer_secret=>"secret",
36
+ # :site=>"http://term.ie",
37
+ # :auth_method=>:authorize,
38
+ # :http_method=>:post,
39
+ # :request_token_path=>"/oauth/example/request_token.php",
40
+ # :access_token_path=>"/oauth/example/access_token.php",
41
+ # :authorize_path=>"/oauth/example/authorize.php"
42
+ # })
43
+ #
44
+ # Start the process by requesting a token
45
+ #
46
+ # @request_token=@consumer.request_token
47
+ # session[:request_token]=@request_token
48
+ # redirect_to @request_token.authorize_url
49
+ #
50
+ # When user returns create an access_token
51
+ #
52
+ # @access_token=@request_token.access_token
53
+ # @photos=@access_token.get('http://test.com/photos.xml')
54
+ #
55
+ #
56
+
57
+ def initialize(params)
58
+ # ensure that keys are symbols
59
+ @params=@@default_params.merge( params.inject({}) do |options, (key, value)|
60
+ options[key.to_sym] = value
61
+ options
62
+ end)
63
+ super @params[:consumer_key],@params[:consumer_secret]
64
+ @site=@params[:site]
65
+ raise ArgumentError, 'Missing site URI' unless @site
66
+ end
67
+
68
+ def http_method
69
+ @http_method||=@params[:http_method]||:post
70
+ end
71
+
72
+ # Get a Request Token
73
+ def get_request_token
74
+ request=create_request(http_method,request_token_path)
75
+ response=request.perform_token_request(self.secret)
76
+ OAuth::RequestToken.new(self,response[:oauth_token],response[:oauth_token_secret])
77
+ end
78
+
79
+ def create_request(http_method,path, oauth_params={},*arguments)
80
+ OAuth::Request.new(http_method,site,path,oauth_params.merge({
81
+ :oauth_consumer_key=>self.key,
82
+ :realm=>authorize_url,
83
+ :oauth_signature_method=>params[:oauth_signature_method],
84
+ :oauth_version=>params[:oauth_version],
85
+ :auth_method=>auth_method
86
+ }),*arguments)
87
+ end
88
+
89
+ def signed_request(http_method, path, oauth_params={},token_secret=nil,*arguments)
90
+ request=create_request(http_method,path,oauth_params,*arguments)
91
+ request.sign(self.secret,token_secret)
92
+ request
93
+ end
94
+
95
+ def auth_method
96
+ @params[:auth_method]
97
+ end
98
+
99
+ def request_token_path
100
+ @params[:request_token_path]
101
+ end
102
+
103
+ def authorize_path
104
+ @params[:authorize_path]
105
+ end
106
+
107
+ def access_token_path
108
+ @params[:access_token_path]
109
+ end
110
+
111
+ def request_token_url
112
+ site+request_token_path
113
+ end
114
+
115
+ def authorize_url
116
+ site+authorize_path
117
+ end
118
+
119
+ def access_token_url
120
+ site+access_token_path
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,12 @@
1
+ module OAuth
2
+ class ConsumerCredentials
3
+ attr_accessor :key, :secret
4
+
5
+ def initialize(key, secret)
6
+ @key = key
7
+ @secret = secret
8
+ raise ArgumentError, 'Missing consumer credentials ("key and/or secret")' unless @key && @secret
9
+ end
10
+ end
11
+
12
+ end
data/lib/oauth/key.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ module OAuth
4
+ module Key
5
+ def generate_key(size=32)
6
+ Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,'')
7
+ end
8
+
9
+ # Based on Blaine's example from the Oauth mailing list
10
+ def escape(value)
11
+ CGI.escape(value.to_s).gsub("%7E", "~").gsub("+", "%20")
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module OAuth
2
+ module OAuthTestHelper
3
+
4
+ def mock_incoming_request_with_query(request)
5
+ incoming=ActionController::TestRequest.new(request.to_hash)
6
+ incoming.request_uri=request.path
7
+ incoming.env["SERVER_PORT"]=request.uri.port
8
+ incoming.host=request.uri.host
9
+ incoming.env['REQUEST_METHOD']=request.http_method
10
+ incoming
11
+ end
12
+
13
+ def mock_incoming_request_with_authorize_header(request)
14
+ incoming=ActionController::TestRequest.new
15
+ incoming.env["HTTP_AUTHORIZATION"]=request.to_auth_string
16
+ incoming.request_uri=request.path
17
+ incoming.env["SERVER_PORT"]=request.uri.port
18
+ incoming.host=request.uri.host
19
+ incoming.env['REQUEST_METHOD']=request.http_method
20
+ incoming
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,258 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'open-uri'
4
+ require 'net/http'
5
+ module OAuth
6
+ # This encapsulates all the request details for OAuth.
7
+ #
8
+ # On the consumer side you shouldn't use this directly but rather Use consumer.get_request_token for the initial token
9
+ # and access token for actual web service calls
10
+ #
11
+ # On the service provider side there are various interesting methods.
12
+ #
13
+ # To find the consumer_key for a request in a rails app do:
14
+ #
15
+ # @consumer_key=OAuth::Request.extract_consumer_key(request)
16
+ #
17
+ # To extract an OAuth::Request for a rails request in a rails app do:
18
+ #
19
+ # @oauth_request=OAuth::Request.incoming(request)
20
+ # @token=AccessToken.find_by_token @oauth_request.token
21
+ # return @oauth_request.verify?(@token.client_application.secret,@token.secret)
22
+ #
23
+ # This example assumes an ActiveRecord Model called AccessToken with a token and a secret column.
24
+ # This is associated with a ActiveRecord Model ClientApplication (the consumer), which has a key and secret column.
25
+ #
26
+ class Request
27
+ include OAuth::Key
28
+
29
+ attr_accessor :oauth_params,:headers,:site,:path,:realm,:body,:auth_method
30
+
31
+ @@default_oauth_params={:oauth_signature_method=>'HMAC-SHA1',:oauth_version=>"1.0",:realm=>''}
32
+
33
+ def initialize(http_method,site,path,oauth_params={},*arguments)
34
+ # ensure that keys are symbols
35
+ @oauth_params=@@default_oauth_params.merge( oauth_params.inject({}) do |options, (key, value)|
36
+ options[key.to_sym] = value
37
+ options
38
+ end)
39
+ self.http_method=http_method
40
+ self.site=site
41
+ self.path=path
42
+ self.realm=@oauth_params.delete(:realm)
43
+ self.auth_method=@oauth_params.delete(:auth_method)||:authorize
44
+ self.body=arguments.shift if ['POST','PUT'].include?(self.http_method)
45
+ self.headers=arguments.shift||{}
46
+ self.headers['Content-Type']||='application/x-www-form-urlencoded' if ['POST','PUT'].include?(self.http_method)
47
+
48
+ self[:oauth_timestamp]=create_timestamp unless self.timestamp
49
+ self[:oauth_nonce]=generate_key(24) unless self.nonce
50
+
51
+ # Default to Authorize header if http method doesn't support the specified auth_method
52
+ if ['GET','HEAD','DELETE'].include?(self.http_method)
53
+ self.auth_method=:authorize unless self.auth_method==:query
54
+ else
55
+ self.auth_method=:authorize unless self.auth_method==:post
56
+ end
57
+
58
+ end
59
+
60
+ # Use to extract the consumer key from a http request object
61
+ # This is intended for use on the server
62
+ def self.extract_consumer_key(http_request)
63
+ auth=http_request.env["HTTP_AUTHORIZATION"]
64
+ if auth && auth[0..5]=="OAuth "&&auth=~/ oauth_consumer_key="([^, ]+)"/
65
+ $1
66
+ else
67
+ http_request.parameters[:oauth_consumer_key]
68
+ end
69
+ end
70
+
71
+ # This takes a rails like Request and returns an OAuth request object
72
+ def self.incoming(http_request)
73
+ auth=http_request.env["HTTP_AUTHORIZATION"]
74
+ if auth && auth[0..5]=="OAuth "
75
+ parameters=auth[6,auth.size].scan(/ ([^= ]+)="([^"]*)",?/).inject({}) do |h,(k,v)|
76
+ h[k.to_sym]=CGI.unescape(v)
77
+ h
78
+ end
79
+ _path=http_request.request_uri
80
+ else
81
+ parameters=http_request.query_parameters#.reject{|k,v| ['controller','action'].include?(k)}
82
+ # non_oauth=to_name_value_pair_array(http_request.query_parameters.reject(){|k,v| k.to_s=~/oauth_/}).join(/&/)
83
+ _path=http_request.request_uri
84
+ # _path=http_request.path+'?'+non_auth
85
+ end
86
+ if http_request.post?||http_request.put?
87
+ Request.new(http_request.method,"http://#{http_request.host_with_port}",_path,parameters,http_request.raw_post,{'Content-Type'=>http_request.content_type})
88
+ else
89
+ Request.new(http_request.method,"http://#{http_request.host_with_port}",_path,parameters)
90
+ end
91
+ end
92
+
93
+ def perform(consumer_secret,token_secret=nil)
94
+ http_klass=(uri.scheme=="https" ? Net::HTTPS : Net::HTTP)
95
+ http_klass.start(uri.host,uri.port) do |http|
96
+ sign(consumer_secret,token_secret)
97
+
98
+ case auth_method
99
+ when :query
100
+ _path="#{uri.path}?#{to_query}"
101
+ when :post
102
+ self.body=to_query
103
+ else
104
+ headers['Authorization']=to_auth_string
105
+ end
106
+ _path||=path
107
+ # TODO if realm is set use auth header
108
+ if (['POST','PUT'].include?(http_method))
109
+ # headers['Content-Length']=body.size.to_s unless body.nil?
110
+ http.send(http_method.downcase.to_sym,_path,body,headers)
111
+ else # any request without a body
112
+ http.send(http_method.downcase.to_sym,_path,headers)
113
+ end
114
+ end
115
+ end
116
+
117
+ def perform_token_request(consumer_secret,token_secret=nil)
118
+ response=perform(consumer_secret,token_secret)
119
+ if response.code=="200"
120
+ CGI.parse(response.body).inject({}){|h,(k,v)| h[k.to_sym]=v.first;h}
121
+ else
122
+ response.error!
123
+ end
124
+ end
125
+
126
+ def http_method=(value)
127
+ @http_method=value.to_s.strip.upcase
128
+ end
129
+
130
+ def http_method
131
+ @http_method
132
+ end
133
+
134
+ def content_type
135
+ @content_type||=headers['Content-Type']
136
+ end
137
+
138
+ def site=(_site)
139
+ @site=_site.downcase
140
+ @uri=nil # invalidate uri
141
+ @site
142
+ end
143
+
144
+ def path=(_path)
145
+ @path=_path
146
+ @uri=nil # invalidate uri
147
+ @path
148
+ end
149
+
150
+ def uri
151
+ @uri||=URI.parse(url)
152
+ end
153
+
154
+ def url
155
+ (site+path)
156
+ end
157
+
158
+ # produces a hash of the query or post parameters depending on http method
159
+ def http_parameters
160
+ @http_params||=parse_url_form_encoded( body||uri.query||'')
161
+ end
162
+
163
+ def parse_url_form_encoded(string)
164
+ CGI.parse(string).inject({}){|h,(k,v)| h[k.to_sym]=v[0];h}
165
+ end
166
+
167
+ def normalized_url
168
+ uri=URI.split(url)
169
+ if uri[3].nil?||(uri[3]=='80'&&uri[0]=='http')||(uri[3]=='443'&&uri[0]=='https')
170
+ port=""
171
+ else
172
+ port=":#{uri[3]}"
173
+ end
174
+ "#{uri[0]}://#{uri[2]}#{port}#{uri[5]}"
175
+ end
176
+
177
+ def [](key)
178
+ oauth_params[key.to_sym]
179
+ end
180
+
181
+ def []=(key,value)
182
+ oauth_params[key.to_sym]=value
183
+ end
184
+
185
+ def timestamp
186
+ self[:oauth_timestamp]
187
+ end
188
+
189
+ def create_timestamp
190
+ Time.now.utc.to_i.to_s
191
+ end
192
+
193
+ def nonce
194
+ self[:oauth_nonce]
195
+ end
196
+
197
+ def token
198
+ self[:oauth_token]
199
+ end
200
+
201
+ def to_name_value_pair_array(hash,with={})
202
+ hash.merge(with).collect{|(key,value)| "#{escape(key.to_s)}=#{escape(value)}"}.sort
203
+ end
204
+
205
+ def to_hash(with={})
206
+ oauth_params.merge(http_parameters).merge(with)
207
+ end
208
+
209
+ def to_query(with={})
210
+ (to_name_value_pair_array(to_hash(with))).sort.join("&")
211
+ end
212
+
213
+ def to_query_without_signature(with={})
214
+ (to_name_value_pair_array(oauth_params_without_signature,with)).sort.join("&")
215
+ end
216
+
217
+ def to_auth_string
218
+ "OAuth realm=\"#{realm}\", "+oauth_params.collect{|(key,value)| "#{escape(key.to_s)}=\"#{escape(value)}\""}.sort.join(", ")
219
+ end
220
+
221
+ def to_base_string(secret)
222
+ to_query({:oauth_secret=>secret})
223
+ end
224
+
225
+ def oauth_params_without_signature
226
+ to_hash.reject{|key,value| key.to_sym==:oauth_signature}
227
+ end
228
+
229
+ def signature
230
+ self[:oauth_signature]
231
+ end
232
+
233
+ def signature=(_signature)
234
+ self[:oauth_signature]=_signature
235
+ end
236
+
237
+ def signature_method
238
+ self[:oauth_signature_method]
239
+ end
240
+
241
+ def signature_method=(_signature_method)
242
+ self[:oauth_signature_method]=_signature_method
243
+ end
244
+
245
+ def signed?
246
+ signature!=nil
247
+ end
248
+
249
+ def sign(consumer_secret,token_secret=nil)
250
+ OAuth::Signature.create(self,consumer_secret,token_secret).sign!
251
+ end
252
+
253
+ def verify?(consumer_secret,token_secret=nil)
254
+ OAuth::Signature.create(self,consumer_secret,token_secret).verify?
255
+ end
256
+
257
+ end
258
+ end