Module: Sinatra::DigestAuthorization

Includes:
AbstractAuthorization
Defined in:
lib/amp/server/extension/authorization.rb

Overview

liberally lifted and modified from Rack’s source Code slightly refactored for Amp

Constant Summary collapse

QOP =
'auth'.freeze

Instance Method Summary collapse

Methods included from AbstractAuthorization

#authorized?, #bad_request!, #current_user, #unauthorized!

Instance Method Details

#A1(auth, password) ⇒ Object



183
184
185
# File 'lib/amp/server/extension/authorization.rb', line 183

def A1(auth, password)
  [ auth.username, auth.realm, password ] * ':'
end

#A2(auth) ⇒ Object



187
188
189
# File 'lib/amp/server/extension/authorization.rb', line 187

def A2(auth)
  [ auth.method, auth.uri ] * ':'
end

#auth_params(hash = {}) ⇒ Object



143
144
145
146
147
148
149
150
151
# File 'lib/amp/server/extension/authorization.rb', line 143

def auth_params(hash = {})
  param = Rack::Auth::Digest::Params.new do |param|
    param['realm'] = options.authorization_realm
    param['nonce'] = Rack::Auth::Digest::Nonce.new.to_s
    param['opaque'] = H(opaque)
    param['qop'] = QOP
    hash.each { |k, v| param[k] = v }
  end
end

#challenge(hash = {}) ⇒ Object



153
154
155
# File 'lib/amp/server/extension/authorization.rb', line 153

def challenge(hash = {})
  "Digest #{auth_params(hash)}"
end

#digest(auth, password) ⇒ Object



191
192
193
194
195
196
# File 'lib/amp/server/extension/authorization.rb', line 191

def digest(auth, password)
  # change false to match if we ever store hashed passes
  password_hash = false ? password : H(A1(auth, password))

  KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
end

#KD(secret, data) ⇒ Object



179
180
181
# File 'lib/amp/server/extension/authorization.rb', line 179

def KD(secret, data)
  H([secret, data] * ':')
end

#login_requiredObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/amp/server/extension/authorization.rb', line 99

def 
  auth = Rack::Auth::Digest::Request.new(request.env)
  unauthorized! unless auth.provided?
  bad_request!  if !auth.digest?
  if valid?(auth)
    if auth.nonce.stale?
      return unauthorized!(challenge(:stale => true))
    else
      request.env["REMOTE_USER"] = auth.username
      return true
    end
  end
  unauthorized!
end

#md5(data) ⇒ Object Also known as: H



173
174
175
# File 'lib/amp/server/extension/authorization.rb', line 173

def md5(data)
  ::Digest::MD5.hexdigest(data)
end

#opaqueObject



95
# File 'lib/amp/server/extension/authorization.rb', line 95

def opaque; "DEADBEEF"; end

#valid?(auth) ⇒ Boolean

Returns:



157
158
159
# File 'lib/amp/server/extension/authorization.rb', line 157

def valid?(auth)
  valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
end

#valid_digest?(auth) ⇒ Boolean

This method verifies that the digest provided is accurate. This is the only method involved in the authentication process that requires knowledge of the login system, so it is exposed here, rather than Sinatra::DigestAuthorization.

Parameters:

  • auth (Rack::Request)

    The request being used for authorization

Returns:

  • (Boolean)

    is the user allowed to view the given material?



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/amp/server/extension/authorization.rb', line 121

def valid_digest?(auth)
  repo = self.class.amp_repositories[request.path_info]
  # no repo OR no users added to repo --> Access to anyone
  return true  unless repo && repos[repo]
  
  user = get_user_and_permissions repo, auth.username
  # User not in the system at all? Denied!
  return false unless user
  
  # if we're private
  if repo_is_private?(repo)
    # and the command is read-only, but user cannot read, they get Ben Wallace'd
    return false if command_reads?(params["cmd"]) && !user[:read]
  end
  
  # Command is write-only, but user cannot write --> Denied. Private/non-private doesn't matter.
  return false if command_writes?(params["cmd"]) && !user[:write]
  
  # Can't short-circuit this one. Just run the digest.
  digest(auth, user[:user].password) == auth.response
end

#valid_nonce?(auth) ⇒ Boolean

Returns:



169
170
171
# File 'lib/amp/server/extension/authorization.rb', line 169

def valid_nonce?(auth)
  auth.nonce.valid?
end

#valid_opaque?(auth) ⇒ Boolean

Returns:



165
166
167
# File 'lib/amp/server/extension/authorization.rb', line 165

def valid_opaque?(auth)
  H(opaque) == auth.opaque
end

#valid_qop?(auth) ⇒ Boolean

Returns:



161
162
163
# File 'lib/amp/server/extension/authorization.rb', line 161

def valid_qop?(auth)
  QOP == auth.qop
end