httpauth 0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,16 +1,20 @@
1
- HTTPauth is an HTTP Authentication library for Ruby
2
- Copyright (C) 2006 Fingertips, Manfred Stienstra <m.stienstra@fngtps.com>
1
+ Copyright (C) 2006-2011
2
+ Manfred Stienstra <manfred@fngtps.com>, Fingertips,
3
+ Tim Olsen <tim@brooklynpenguin.com>
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
3
10
 
4
- This program is free software; you can redistribute it and/or modify
5
- it under the terms of the GNU General Public License as published by
6
- the Free Software Foundation; either version 2 of the License, or
7
- (at your option) any later version.
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
8
13
 
9
- This program is distributed in the hope that it will be useful,
10
- but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- GNU General Public License for more details.
13
-
14
- You should have received a copy of the GNU General Public License along
15
- with this program; if not, write to the Free Software Foundation, Inc.,
16
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
@@ -1,4 +1,5 @@
1
- = README
1
+ HTTPauth
2
+ ======
2
3
 
3
4
  HTTPauth is a library supporting the full HTTP Authentication protocol as specified in RFC 2617; both Digest Authentication and Basic Authentication. We aim to make HTTPAuth as compliant as possible.
4
5
 
@@ -6,34 +7,34 @@ HTTPAuth is built to be completely agnostic of the HTTP implementation. If you h
6
7
 
7
8
  This project is currently under development, don't use it in mission critical applications.
8
9
 
9
- == Getting started
10
+ ## Getting started
10
11
 
11
12
  If you want to implement authentication for your application you should probably start by looking at the various examples. In the examples directory is an implementation of an HTTP client and server, you can use these to test your implementation. The examples are basic implementations of the protocol.
12
13
 
13
- == Limitations
14
+ ## Limitations
14
15
 
15
16
  Currently the library doesn't check for consistency of the directives in the various headers, this means that implementations using this library can be vulnerable to request replay attacks. This will obviously be addressed before the final release.
16
17
 
17
- == Plugins
18
+ ## Plugins
18
19
 
19
- === Ruby on Rails
20
+ ### Ruby on Rails
20
21
 
21
22
  A plugin for Ruby on Rails can be found here:
22
23
 
23
24
  https://fngtps.com/svn/rails-plugins/trunk/digest_authentication
24
25
 
25
- == Known client implementation issues
26
+ ## Known client implementation issues
26
27
 
27
- === Safari
28
+ ### Safari
28
29
 
29
- Safari doesn't understand and parse the algorithm and qop directives correctly. For instance: it sends qop=auth as qop="auth" and when multiple qop values are suggested by the server, no authentication is triggered. See http://bugzilla.opendarwin.org/show_bug.cgi?id=10727.
30
+ Safari doesn't understand and parse the algorithm and qop directives correctly. For instance: it sends qop=auth as qop="auth" and when multiple qop values are suggested by the server, no authentication is triggered.
30
31
 
31
- == Internet Explorer
32
+ ### Internet Explorer
32
33
 
33
34
  The qop and algorithm bug quoting bugs are also present in IE.
34
35
 
35
36
  IE doesn't use the full URI for digest calculation, it chops off the query parameters. So a request on /script?q=a will response with uri='/script'.
36
37
 
37
- == Known server implementation issues
38
+ ## Known server implementation issues
38
39
 
39
40
  Apache 2.0 sends Authorization-Info headers without a nextnonce directive.
@@ -106,7 +106,7 @@ module HTTPAuth
106
106
  # RewriteRule ^admin/ - [E=X-HTTP-AUTHORIZATION:%{HTTP:Authorization}]
107
107
  def get_credentials(env)
108
108
  d = HTTPAuth::CREDENTIAL_HEADERS.inject(false) { |d,h| env[h] || d }
109
- return unpack_authorization(d) if d
109
+ return unpack_authorization(d) unless !d or d.nil? or d.empty?
110
110
  [nil, nil]
111
111
  end
112
112
  end
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # For more information see RFC 2617 (http://www.ietf.org/rfc/rfc2617.txt)
5
5
  module HTTPAuth
6
- VERSION = '0.1'
6
+ VERSION = '0.2'
7
7
 
8
8
  CREDENTIAL_HEADERS = %w{REDIRECT_X_HTTP_AUTHORIZATION X-HTTP-AUTHORIZATION X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION}
9
9
  SUPPORTED_SCHEMES = { :basic => 'Basic', :digest => 'Digest' }
@@ -54,12 +54,11 @@ module HTTPAuth
54
54
  # * <tt>variant</tt>: Specifies whether the directives are for an Authorize header (:credentials),
55
55
  # for a WWW-Authenticate header (:challenge) or for a Authentication-Info header (:auth_info).
56
56
  def encode_directives(h, variant)
57
- encode = {:domain => :join, :algorithm => false, :stale => :str_to_bool, :nc => :int_to_hex,
58
- :nextnonce => :int_to_hex}
57
+ encode = {:domain => :list_to_space_quoted_string, :algorithm => false, :stale => :bool_to_str, :nc => :int_to_hex}
59
58
  if [:credentials, :auth].include? variant
60
59
  encode.merge! :qop => false
61
60
  elsif variant == :challenge
62
- encode.merge! :qop => :list_to_quoted_string
61
+ encode.merge! :qop => :list_to_comma_quoted_string
63
62
  else
64
63
  raise ArgumentError.new("#{variant} is not a valid value for `variant' use :auth, :credentials or :challenge")
65
64
  end
@@ -89,12 +88,11 @@ module HTTPAuth
89
88
  # for a WWW-Authenticate header (:challenge) or for a Authentication-Info header (:auth_info).
90
89
  def decode_directives(directives, variant)
91
90
  raise HTTPAuth::UnwellformedHeader.new("Can't decode directives which are nil") if directives.nil?
92
- decode = {:domain => :split, :algorithm => false, :stale => :bool_to_str, :nc => :hex_to_int,
93
- :nextnonce => :hex_to_int}
91
+ decode = {:domain => :space_quoted_string_to_list, :algorithm => false, :stale => :str_to_bool, :nc => :hex_to_int}
94
92
  if [:credentials, :auth].include? variant
95
93
  decode.merge! :qop => false
96
94
  elsif variant == :challenge
97
- decode.merge! :qop => :quoted_string_to_list
95
+ decode.merge! :qop => :comma_quoted_string_to_list
98
96
  else
99
97
  raise ArgumentError.new("#{variant} is not a valid value for `variant' use :auth, :credentials or :challenge")
100
98
  end
@@ -230,7 +228,7 @@ module HTTPAuth
230
228
  )
231
229
  ).gsub("\n", '')[0..-3]
232
230
  end
233
-
231
+
234
232
  # Create a 32 character long opaque string with a 'random' value
235
233
  def create_opaque
236
234
  s = []; 16.times { s << rand(127).chr }
@@ -275,8 +273,10 @@ module HTTPAuth
275
273
  #
276
274
  # See the Digest module for examples
277
275
  class Credentials < AbstractHeader
276
+ # Holds an explanation why <tt>validate</tt> returned false.
277
+ attr_reader :reason
278
278
 
279
- # Parses the information from a Authorize header and create a new Credentials instance with the information.
279
+ # Parses the information from an Authorize header and creates a new Credentials instance with the information.
280
280
  # The options hash allows you to specify additional information.
281
281
  #
282
282
  # * <tt>authorization</tt>: The contents of the Authorize header
@@ -294,6 +294,14 @@ module HTTPAuth
294
294
  credentials.update_from_challenge! options
295
295
  credentials
296
296
  end
297
+
298
+ def self.load(filename, options={})
299
+ h = nil
300
+ File.open(filename, 'r') do |f|
301
+ h = Marshal.load f
302
+ end
303
+ new h, options
304
+ end
297
305
 
298
306
  # Create a new instance.
299
307
  #
@@ -334,7 +342,7 @@ module HTTPAuth
334
342
  # * <tt>:method</tt>: The HTTP Verb in uppercase, ie. GET or POST.
335
343
  # * <tt>:password</tt>: The password for the sent username and realm, either a password or digest should be
336
344
  # provided.
337
- # * <tt>:digest</tt>: The digest for the specified username and realm, either a digest or password should ne
345
+ # * <tt>:digest</tt>: The digest for the specified username and realm, either a digest or password should be
338
346
  # provided.
339
347
  def validate(options)
340
348
  ho = @h.merge(options)
@@ -351,13 +359,8 @@ module HTTPAuth
351
359
  false
352
360
  end
353
361
 
354
- # Returns a string with the reason <tt>validate</tt> returned false.
355
- def reason
356
- @reason
357
- end
358
-
359
362
  # Encodeds directives and returns a string that can be used in the Authorize header
360
- def to_header
363
+ def to_header
361
364
  Utils.encode_directives Utils.filter_h_on(@h,
362
365
  [:username, :realm, :nonce, :uri, :response, :algorithm, :cnonce, :opaque, :qop, :nc]), :credentials
363
366
  end
@@ -390,6 +393,13 @@ module HTTPAuth
390
393
  end
391
394
  @h[:response] = Utils.calculate_digest(@h, @s, :request)
392
395
  end
396
+
397
+ def dump_sans_creds(filename)
398
+ File.open(filename, 'w') do |f|
399
+ Marshal.dump(Utils.filter_h_on(@h, [:username, :realm, :nonce, :algorithm, :cnonce, :opaque, :qop, :nc]), f)
400
+ end
401
+ end
402
+
393
403
  end
394
404
 
395
405
  # The Challenge class handlers the WWW-Authenticate header. The WWW-Authenticate header is sent by a server when
@@ -469,6 +479,7 @@ module HTTPAuth
469
479
  # * <tt>h</tt>: A Hash with directives, normally this is filled with the directives coming from a
470
480
  # Credentials instance.
471
481
  # * <tt>options</tt>: Used to set or override data from the Authentication-Info header
482
+ # * <tt>:digest</tt>: The digest for the specified username and realm.
472
483
  # * <tt>:response_body</tt> The body of the response that's going to be sent to the client. This is a
473
484
  # compulsory option if the qop directive is 'auth-int'.
474
485
  def initialize(h, options={})
@@ -485,9 +496,25 @@ module HTTPAuth
485
496
  # Updates @h from options, generally called after an instance was created with <tt>from_credentials</tt>.
486
497
  def update_from_credentials!(options)
487
498
  # TODO: update @h after nonce invalidation
499
+ [:digest, :username, :realm, :password].each do |k|
500
+ @h[k] = options[k] if options.include? k
501
+ end
488
502
  @h[:response_body] = options[:response_body]
489
- @h[:nextnonce] = @h[:nc] + 1
503
+ @h[:nextnonce] = Utils.create_nonce @h[:salt]
504
+ @h[:rspauth] = Utils.calculate_digest(@h, nil, :response)
490
505
  end
506
+
507
+ # Validates rspauth. Returns <tt>true</tt> or <tt>false</tt>
508
+ #
509
+ # * <tt>options</tt>: The extra options needed to validate rspauth.
510
+ # * <tt>:digest</tt>: The H(a1) digest
511
+ # * <tt>:uri</tt>: request uri
512
+ # * <tt>:nonce</tt>:nonce
513
+ def validate(options)
514
+ ho = @h.merge(options)
515
+ return @h[:rspauth] == Utils.calculate_digest(ho, @s, :response)
516
+ end
517
+
491
518
  end
492
519
 
493
520
  # Conversion for a number of internal data structures to and from directives in the headers. Implementations
@@ -497,7 +524,7 @@ module HTTPAuth
497
524
 
498
525
  # Adds quotes around the string
499
526
  def quote_string(str)
500
- "\"#{str.gsub('"', '')}\""
527
+ "\"#{str.gsub(/\"/, '')}\""
501
528
  end
502
529
 
503
530
  # Removes quotes from around a string
@@ -526,14 +553,23 @@ module HTTPAuth
526
553
  end
527
554
 
528
555
  # Creates a quoted string with space separated items from a list
529
- def list_to_quoted_string(list)
556
+ def list_to_space_quoted_string(list)
530
557
  quote_string list.join(' ')
531
558
  end
532
559
 
533
560
  # Creates a list from a quoted space separated string of items
534
- def quoted_string_to_list(string)
561
+ def space_quoted_string_to_list(string)
535
562
  unquote_string(string).split ' '
536
563
  end
564
+
565
+ # Creates a quoted string with comma separated items from a list
566
+ def list_to_comma_quoted_string(list)
567
+ quote_string list.join(',')
568
+ end
569
+ # Create a list from a quoted comma separated string of items
570
+ def comma_quoted_string_to_list(string)
571
+ unquote_string(string).split ','
572
+ end
537
573
  end
538
574
  end
539
575
 
@@ -3,4 +3,6 @@ module HTTPAuth
3
3
  class UnwellformedHeader < ArgumentError; end
4
4
  # Raised when the library finds data that is not strictly forbidden but doesn't know how to handle.
5
5
  class UnsupportedError < ArgumentError; end
6
+ # Raise when validation on the request failed, most of the times this means that someone is trying to do replay attacks.
7
+ class ValidationError < ArgumentError; end
6
8
  end
metadata CHANGED
@@ -1,66 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.10
3
- specification_version: 1
4
2
  name: httpauth
5
3
  version: !ruby/object:Gem::Version
6
- version: "0.1"
7
- date: 2006-09-04
8
- summary: Library for the HTTP Authentication protocol (RFC 2617)
9
- require_paths:
10
- - lib
11
- email: manfred@fngtps.com
12
- homepage: http://httpauth.rubyforge.org
13
- rubyforge_project:
14
- description: HTTPauth is a library supporting the full HTTP Authentication protocol as specified in RFC 2617; both Digest Authentication and Basic Authentication.
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.8.0
24
- version:
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
25
11
  platform: ruby
26
12
  authors:
27
13
  - Manfred Stienstra
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-09-25 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Library for the HTTP Authentication protocol (RFC 2617)
22
+ email: manfred@fngtpspec.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.md
29
+ - LICENSE
28
30
  files:
29
- - README
31
+ - README.md
30
32
  - LICENSE
31
- - Rakefile
32
- - lib/httpauth
33
- - lib/httpauth.rb
34
33
  - lib/httpauth/basic.rb
35
34
  - lib/httpauth/constants.rb
36
35
  - lib/httpauth/digest.rb
37
36
  - lib/httpauth/exceptions.rb
38
- - examples/client_digest_secure
39
- - examples/server_digest_secure
40
- test_files: []
37
+ - lib/httpauth.rb
38
+ homepage: https://github.com/Manfred/HTTPauth
39
+ licenses: []
41
40
 
41
+ post_install_message:
42
42
  rdoc_options:
43
- - --quiet
44
- - --title
45
- - HTTPAuth - A Ruby library for creating, parsing and validating HTTP authentication headers
46
- - --opname
47
- - index.html
48
- - --line-numbers
49
- - --main
50
- - README
51
- - --charset
52
- - utf-8
53
- - --inline-source
54
- - --exclude
55
- - ^(examples|test)\/
56
- extra_rdoc_files:
57
- - README
58
- - LICENSE
59
- executables: []
60
-
61
- extensions: []
62
-
43
+ - --charset=utf-8
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
63
64
  requirements: []
64
65
 
65
- dependencies: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.18
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: HTTPauth is a library supporting the full HTTP Authentication protocol as specified in RFC 2617; both Digest Authentication and Basic Authentication.
71
+ test_files: []
66
72
 
data/Rakefile DELETED
@@ -1,76 +0,0 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/testtask'
4
- require 'rake/gempackagetask'
5
- require 'rake/rdoctask'
6
-
7
- NAME = 'httpauth'
8
- VERSIE = '0.1'
9
- RDOC_OPTS = ['--quiet', '--title', "HTTPAuth - A Ruby library for creating, parsing and validating HTTP authentication headers",
10
- "--opname", "index.html",
11
- "--line-numbers",
12
- "--main", "README",
13
- "--charset", "utf-8",
14
- "--inline-source"]
15
- CLEAN.include ['pkg', 'doc', '*.gem']
16
-
17
- desc 'Default: run tests'
18
- task :default => [:test]
19
- task :package => [:clean]
20
-
21
- desc 'Run tests'
22
- Rake::TestTask.new(:test) do |t|
23
- t.pattern = 'test/**/*_test.rb'
24
- t.verbose = true
25
- t.warning = true
26
- end
27
-
28
- desc 'Create documentation'
29
- Rake::RDocTask.new("doc") do |rdoc|
30
- rdoc.rdoc_dir = 'doc'
31
- rdoc.options += RDOC_OPTS
32
- rdoc.main = "README"
33
- rdoc.rdoc_files.include('README')
34
- rdoc.rdoc_files.include('lib/**/*.rb')
35
- end
36
-
37
- desc 'Upload rdoc documentation to Rubyforge'
38
- task :upload_doc => :doc do
39
- `scp -r #{File.dirname(__FILE__)}/doc/* mst@rubyforge.org:/var/www/gforge-projects/httpauth/`
40
- end
41
-
42
- spec =
43
- Gem::Specification.new do |s|
44
- s.name = NAME
45
- s.version = VERSIE
46
- s.platform = Gem::Platform::RUBY
47
- s.has_rdoc = true
48
- s.extra_rdoc_files = ["README", "LICENSE"]
49
- s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|test)\/']
50
- s.summary = "Library for the HTTP Authentication protocol (RFC 2617)"
51
- s.description = "HTTPauth is a library supporting the full HTTP Authentication protocol as specified in RFC 2617; both Digest Authentication and Basic Authentication."
52
- s.author = "Manfred Stienstra"
53
- s.email = 'manfred@fngtps.com'
54
- s.homepage = 'http://httpauth.rubyforge.org'
55
- s.required_ruby_version = '>= 1.8.0'
56
-
57
- s.files = %w(README LICENSE Rakefile) +
58
- Dir.glob("lib/**/*") +
59
- Dir.glob("examples/**/*")
60
-
61
- s.require_path = "lib"
62
- end
63
-
64
- Rake::GemPackageTask.new(spec) do |p|
65
- p.need_tar = true
66
- p.gem_spec = spec
67
- end
68
-
69
- task :install do
70
- sh %{rake package}
71
- sh %{sudo gem install pkg/#{NAME}-#{VERSIE}}
72
- end
73
-
74
- task :uninstall => [:clean] do
75
- sh %{sudo gem uninstall #{NAME}}
76
- end
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
-
5
- require 'rubygems' rescue LoadError
6
- require 'uri'
7
- require 'rfuzz/client'
8
- require 'httpauth/digest'
9
-
10
- SALT = 'My very very secret salt'
11
-
12
- class AuthenticationCache
13
-
14
- def initialize
15
- @uri = nil
16
- @credentials = nil
17
- end
18
-
19
- def set_credentials_for(uri, credentials)
20
- @uri = get_new_uri(@uri, uri)
21
- @credentials = credentials
22
- end
23
-
24
- def get_credentials
25
- @credentials
26
- end
27
-
28
- def update_usage_for(uri, nextnonce=nil)
29
- if nextnonce
30
- @credentials.nc = nextnonce
31
- else
32
- @credentials.nc += 1
33
- end
34
- end
35
-
36
- protected
37
-
38
- # Is uri1 more general than uri2
39
- def more_general_uri?(uri1, uri2)
40
- ua1 = uri1.nil? ? [] : uri1.split('/')
41
- ua2 = uri2.nil? ? [] : uri2.split('/')
42
- ua1.each_with_index do |p, i|
43
- return false unless ua2[i] == p
44
- end
45
- true
46
- end
47
-
48
- def get_new_uri(uri1, uri2)
49
- if more_general_uri?(uri1, uri2)
50
- uri1
51
- else
52
- uri2
53
- end
54
- end
55
- end
56
-
57
- class AuthenticatedClient
58
- include HTTPAuth::Digest
59
-
60
- def initialize(host, port)
61
- @client = RFuzz::HttpClient.new host, port
62
- @cache = AuthenticationCache.new
63
- @username = nil
64
- @password = nil
65
- end
66
-
67
- def get_credentials_from_user
68
- if @username.nil?
69
- print 'Username: '
70
- @username = $stdin.gets.strip
71
- end
72
- if @password.nil?
73
- print 'Password: '
74
- @password = $stdin.gets.strip
75
- end
76
- [@username, @password]
77
- end
78
-
79
- # Get a resource from the server
80
- def get(resource)
81
- uri = URI.parse resource
82
-
83
- # If credentials were stored, use them. Otherwise do a normal get
84
- credentials = @cache.get_credentials
85
- unless credentials.nil?
86
- puts "sending credentials: #{credentials.to_header}"
87
- response = @client.get resource, :head => {"Authorization" => credentials.to_header}
88
- else
89
- response = @client.get resource
90
- end
91
- # If response was 401, retry with authentication
92
- if response.http_status == '401' and !response['WWW_AUTHENTICATE'].nil?
93
- puts "got challenge: #{response['WWW_AUTHENTICATE']}"
94
- challenge = Challenge.from_header(response['WWW_AUTHENTICATE'])
95
- (stale = challenge.stale) rescue NoMethodError
96
- unless stale
97
- username, password = get_credentials_from_user
98
- else
99
- username = credentials.username
100
- password = credentials.password
101
- end
102
- credentials = Credentials.from_challenge(challenge,
103
- {:uri => resource, :username => username, :password => password, :method => 'GET'}
104
- )
105
- puts "sending credentials: #{credentials.to_header}"
106
- @cache.set_credentials_for uri.path, credentials
107
- response = @client.get resource, :head => {"Authorization" => credentials.to_header}
108
- end
109
- # If the server sends authentication info use the information for the next request
110
- if response['AUTHENTICATION_INFO']
111
- puts "got authentication-info: #{response['AUTHENTICATION_INFO']}"
112
- auth_info = AuthenticationInfo.from_header(response['AUTHENTICATION_INFO'])
113
- @cache.update_usage_for uri.path, auth_info.h[:nextnonce]
114
- else
115
- @cache.update_usage_for uri.path
116
- end
117
- response
118
- end
119
- end
120
-
121
- if $0 == __FILE__
122
- unless ARGV.length == 2
123
- puts <<-EOT
124
- Usage: client_digest_secure get <url>
125
- EOT
126
- exit 0
127
- end
128
- uri = URI.parse ARGV[1]
129
- client = AuthenticatedClient.new uri.host, uri.port
130
- response = client.send ARGV[0].intern, uri.query ? "#{uri.path}&#{uri.query}" : uri.path
131
- puts response.http_body
132
- end
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
-
5
- require 'webrick'
6
- require 'httpauth/digest'
7
- require 'yaml'
8
-
9
- include WEBrick
10
-
11
- s = HTTPServer.new :Port => 2000, :AccessLog => [[File.open('/dev/null', 'w'), AccessLog::COMMON_LOG_FORMAT],
12
- [File.open('/dev/null', 'w'), AccessLog::REFERER_LOG_FORMAT]]
13
-
14
- class AuthenticationServlet < HTTPServlet::AbstractServlet
15
- include HTTPAuth::Digest
16
- def do_GET(request, response)
17
- puts '-'*79
18
- puts "request: Authorization: " + (request['Authorization'] || '')
19
-
20
- credentials = Credentials.from_header(request['Authorization']) unless request['Authorization'].nil?
21
- if !credentials.nil? and credentials.validate :password => 'secret', :method => 'GET'
22
- response.status = 200
23
- auth_info = AuthenticationInfo.from_credentials credentials
24
- response['Authentication-Info'] = auth_info.to_header
25
- response['Content-Type'] = 'text/plain; charset=utf-8'
26
- response.body = 'You are authorized'
27
- puts "response: Authentication-Info: " + response['Authentication-Info']
28
- else
29
- if credentials
30
- puts '[!] FAILED: ' + credentials.reason
31
- else
32
- puts '[!] FAILED: No credentials specified'
33
- end
34
- response.status = 401
35
- challenge = Challenge.new :realm => 'admin@httpauth.example.com', :qop => ['auth']
36
- response['WWW-Authenticate'] = challenge.to_header
37
- response['Content-Type'] = 'text/plain; charset=utf-8'
38
- response.body = 'You are not authorized'
39
- puts "response: WWW-Authenticate: " + response['WWW-Authenticate']
40
- end
41
- end
42
- end
43
-
44
- puts "\n>>> Open http://localhost:2000/ and login with password 'secret', any username should work\n\n"
45
- s.mount '/', AuthenticationServlet
46
- trap('INT') { s.shutdown }
47
- s.start