Class: EventMachine::AblyHttpRequest::Middleware::DigestAuth

Inherits:
Object
  • Object
show all
Includes:
HttpEncoding
Defined in:
lib/em-http/middleware/digest_auth.rb

Constant Summary

Constants included from HttpEncoding

HttpEncoding::FIELD_ENCODING, HttpEncoding::HTTP_REQUEST_HEADER

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HttpEncoding

#bytesize, #encode_auth, #encode_cookie, #encode_field, #encode_headers, #encode_host, #encode_param, #encode_query, #encode_request, #escape, #form_encode_body, #munge_header_keys, #unescape

Constructor Details

#initialize(www_authenticate, opts = {}) ⇒ DigestAuth

Returns a new instance of DigestAuth.



12
13
14
15
16
17
18
19
20
21
# File 'lib/em-http/middleware/digest_auth.rb', line 12

def initialize(www_authenticate, opts = {})
  @nonce_count = -1
  @opts = opts
  @digest_params = {
      algorithm: 'MD5' # MD5 is the default hashing algorithm
  }
  if (@is_digest_auth = www_authenticate =~ /^Digest/)
    get_params(www_authenticate)
  end
end

Instance Attribute Details

#auth_digestObject

Returns the value of attribute auth_digest.



10
11
12
# File 'lib/em-http/middleware/digest_auth.rb', line 10

def auth_digest
  @auth_digest
end

#is_digest_authObject

Returns the value of attribute is_digest_auth.



10
11
12
# File 'lib/em-http/middleware/digest_auth.rb', line 10

def is_digest_auth
  @is_digest_auth
end

Instance Method Details

#build_auth_digest(method, uri, params = nil) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/em-http/middleware/digest_auth.rb', line 41

def build_auth_digest(method, uri, params = nil)
  params = @opts.merge(@digest_params) if !params
  nonce_count = next_nonce

  user = unescape params[:username]
  password = unescape params[:password]

  splitted_algorithm = params[:algorithm].split('-')
  sess = "-sess" if splitted_algorithm[1]
  raw_algorithm = splitted_algorithm[0]
  if %w(MD5 SHA1 SHA2 SHA256 SHA384 SHA512 RMD160).include? raw_algorithm
    algorithm = eval("Digest::#{raw_algorithm}")
  else
    raise "Unknown algorithm: #{raw_algorithm}"
  end
  qop = params[:qop]
  cnonce = make_cnonce if qop or sess
  a1 = if sess
    [
      algorithm.hexdigest("#{params[:username]}:#{params[:realm]}:#{params[:password]}"),
      params[:nonce],
      cnonce,
      ].join ':'
  else
    "#{params[:username]}:#{params[:realm]}:#{params[:password]}"
  end
  ha1 = algorithm.hexdigest a1
  ha2 = algorithm.hexdigest "#{method}:#{uri}"

  request_digest = [ha1, params[:nonce]]
  request_digest.push(('%08x' % @nonce_count), cnonce, qop) if qop
  request_digest << ha2
  request_digest = request_digest.join ':'
  header = [
    "Digest username=\"#{params[:username]}\"",
    "realm=\"#{params[:realm]}\"",
    "algorithm=#{raw_algorithm}#{sess}",
    "uri=\"#{uri}\"",
    "nonce=\"#{params[:nonce]}\"",
    "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"",
  ]
  if params[:qop]
    header << "qop=#{qop}"
    header << "nc=#{'%08x' % @nonce_count}"
    header << "cnonce=\"#{cnonce}\""
  end
  header << "opaque=\"#{params[:opaque]}\"" if params.key? :opaque
  header.join(', ')
end

#get_params(www_authenticate) ⇒ Object

Process the WWW_AUTHENTICATE header to get the authentication parameters



92
93
94
95
96
# File 'lib/em-http/middleware/digest_auth.rb', line 92

def get_params(www_authenticate)
  www_authenticate.scan(/(\w+)="?(.*?)"?(,|\z)/).each do |match|
    @digest_params[match[0].to_sym] = match[1]
  end
end

#make_cnonceObject

Generate a client nonce



99
100
101
102
103
104
105
# File 'lib/em-http/middleware/digest_auth.rb', line 99

def make_cnonce
  Digest::MD5.hexdigest [
    Time.now.to_i,
    $$,
    SecureRandom.random_number(2**32),
  ].join ':'
end

#next_nonceObject

Keep track of the nounce count



108
109
110
# File 'lib/em-http/middleware/digest_auth.rb', line 108

def next_nonce
  @nonce_count += 1
end

#request(client, head, body) ⇒ Object



23
24
25
26
27
28
29
30
31
# File 'lib/em-http/middleware/digest_auth.rb', line 23

def request(client, head, body)
  # Allow HTTP basic auth fallback
  if @is_digest_auth
    head['Authorization'] = build_auth_digest(client.req.method, client.req.uri.path, @opts.merge(@digest_params))
  else
    head['Authorization'] = [@opts[:username], @opts[:password]]
  end
  [head, body]
end

#response(resp) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/em-http/middleware/digest_auth.rb', line 33

def response(resp)
  # If the server responds with the Authentication-Info header, set the nonce to the new value
  if @is_digest_auth && (authentication_info = resp.response_header['Authentication-Info'])
    authentication_info =~ /nextnonce="?(.*?)"?(,|\z)/
    @digest_params[:nonce] = $1
  end
end