Class: HTTPAuth::Basic

Inherits:
Object
  • Object
show all
Defined in:
lib/httpauth/basic.rb

Overview

Basic

The Basic class provides a number of methods to handle HTTP Basic Authentication. In Basic Authentication the server sends a challenge and the client has to respond to that with the correct credentials. These credentials will have to be sent with every request from that point on.

On the server

On the server you will have to check the headers for the ‘Authorization’ header. When you find one unpack it and check it against your database of credentials. If the credentials are wrong you have to return a 401 status message and a challenge, otherwise proceed as normal. The code is meant as an example, not as runnable code.

def check_authentication(request, response)
  credentials = HTTPAuth::Basic.unpack_authorization(request['Authorization'])
  if ['admin', 'secret'] == credentials
    response.status = 200
    return true
  else
    response.status = 401
    response['WWW-Authenticate'] = HTTPAuth::Basic.pack_challenge('Admin Pages')
    return false
  end
end

On the client

On the client you have to detect the WWW-Authenticate header sent from the server. Once you find one you should send credentials for that resource any resource ‘deeper in the URL space’. You may send the credentials for every request without a WWW-Authenticate challenge. Note that credentials are valid for a realm, a server can use multiple realms for different resources. The code is meant as an example, not as runnable code.

def get_credentials_from_user_for(realm)
  if realm == 'Admin Pages'
   return ['admin', 'secret']
  else
   return [nil, nil]
  end
end

def handle_authentication(response, request)
  unless response['WWW-Authenticate'].nil?
    realm = HTTPAuth::Basic.unpack_challenge(response['WWW-Authenticate])
    @credentials[realm] ||= get_credentials_from_user_for(realm)
    @last_realm = realm
  end
  unless @last_realm.nil?
    request['Authorization'] = HTTPAuth::Basic.pack_authorization(*@credentials[@last_realm])
  end
end

Class Method Summary collapse

Class Method Details

.get_credentials(env) ⇒ Object

Finds and unpacks the authorization credentials in a hash with the CGI enviroment. Returns [nil,nil] if no credentials were found. See HTTPAuth::CREDENTIAL_HEADERS for supported variable names.

_Note for Apache_: normally the Authorization header can be found in the HTTP_AUTHORIZATION env variable, but Apache’s mod_auth removes the variable from the enviroment. You can work around this by renaming the variable in your apache configuration (or .htaccess if allowed). For example: rewrite the variable for every request on /admin/*.

RewriteEngine on
RewriteRule ^admin/ - [E=X-HTTP-AUTHORIZATION:%{HTTP:Authorization}]


106
107
108
109
110
# File 'lib/httpauth/basic.rb', line 106

def get_credentials(env)
  d = HTTPAuth::CREDENTIAL_HEADERS.inject(false) { |a, e| env[e] || a }
  return unpack_authorization(d) unless !d || d.nil? || d.empty?
  [nil, nil]
end

.pack_authorization(username, password) ⇒ Object

Packs HTTP Basic credentials to an ‘Authorization’ header

  • username: A string with the username

  • password: A string with the password



70
71
72
# File 'lib/httpauth/basic.rb', line 70

def pack_authorization(username, password)
  format('Basic %s', Base64.encode64("#{username}:#{password}").gsub("\n", ''))
end

.pack_challenge(realm) ⇒ Object

Returns contents for the WWW-authenticate header

  • realm: A string with a recognizable title for the restricted resource



77
78
79
# File 'lib/httpauth/basic.rb', line 77

def pack_challenge(realm)
  format("Basic realm=\"%s\"", realm.gsub('"', ''))
end

.unpack_authorization(authorization) ⇒ Object

Unpacks the HTTP Basic ‘Authorization’ credential header

  • authorization: The contents of the Authorization header

  • Returns a list with two items: the username and password



60
61
62
63
64
# File 'lib/httpauth/basic.rb', line 60

def unpack_authorization(authorization)
  d = authorization.split ' '
  fail(ArgumentError, 'HTTPAuth::Basic can only unpack Basic Authentication headers') unless d[0] == 'Basic'
  Base64.decode64(d[1]).split(':')[0..1]
end

.unpack_challenge(authenticate) ⇒ Object

Returns the name of the realm in a WWW-Authenticate header

  • authenticate: The contents of the WWW-Authenticate header



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/httpauth/basic.rb', line 84

def unpack_challenge(authenticate)
  if authenticate =~ /Basic\srealm=\"([^\"]*)\"/
    return Regexp.last_match[1]
  else
    if authenticate =~ /^Basic/
      fail(UnwellformedHeader, "Can't parse the WWW-Authenticate header, it's probably not well formed")
    else
      fail(ArgumentError, 'HTTPAuth::Basic can only unpack Basic Authentication headers')
    end
  end
end