1#--
2# httpauth/authenticator.rb -- Authenticator mix-in module.
3#
4# Author: IPR -- Internet Programming with Ruby -- writers
5# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
6# reserved.
7#
8# $IPR: authenticator.rb,v 1.3 2003/02/20 07:15:47 gotoyuzo Exp $
9
10module WEBrick
11  module HTTPAuth
12
13    ##
14    # Module providing generic support for both Digest and Basic
15    # authentication schemes.
16
17    module Authenticator
18
19      RequestField      = "Authorization" # :nodoc:
20      ResponseField     = "WWW-Authenticate" # :nodoc:
21      ResponseInfoField = "Authentication-Info" # :nodoc:
22      AuthException     = HTTPStatus::Unauthorized # :nodoc:
23
24      ##
25      # Method of authentication, must be overridden by the including class
26
27      AuthScheme        = nil
28
29      ##
30      # The realm this authenticator covers
31
32      attr_reader :realm
33
34      ##
35      # The user database for this authenticator
36
37      attr_reader :userdb
38
39      ##
40      # The logger for this authenticator
41
42      attr_reader :logger
43
44      private
45
46      # :stopdoc:
47
48      ##
49      # Initializes the authenticator from +config+
50
51      def check_init(config)
52        [:UserDB, :Realm].each{|sym|
53          unless config[sym]
54            raise ArgumentError, "Argument #{sym.inspect} missing."
55          end
56        }
57        @realm     = config[:Realm]
58        @userdb    = config[:UserDB]
59        @logger    = config[:Logger] || Log::new($stderr)
60        @reload_db = config[:AutoReloadUserDB]
61        @request_field   = self::class::RequestField
62        @response_field  = self::class::ResponseField
63        @resp_info_field = self::class::ResponseInfoField
64        @auth_exception  = self::class::AuthException
65        @auth_scheme     = self::class::AuthScheme
66      end
67
68      ##
69      # Ensures +req+ has credentials that can be authenticated.
70
71      def check_scheme(req)
72        unless credentials = req[@request_field]
73          error("no credentials in the request.")
74          return nil
75        end
76        unless match = /^#{@auth_scheme}\s+/i.match(credentials)
77          error("invalid scheme in %s.", credentials)
78          info("%s: %s", @request_field, credentials) if $DEBUG
79          return nil
80        end
81        return match.post_match
82      end
83
84      def log(meth, fmt, *args)
85        msg = format("%s %s: ", @auth_scheme, @realm)
86        msg << fmt % args
87        @logger.send(meth, msg)
88      end
89
90      def error(fmt, *args)
91        if @logger.error?
92          log(:error, fmt, *args)
93        end
94      end
95
96      def info(fmt, *args)
97        if @logger.info?
98          log(:info, fmt, *args)
99        end
100      end
101
102      # :startdoc:
103    end
104
105    ##
106    # Module providing generic support for both Digest and Basic
107    # authentication schemes for proxies.
108
109    module ProxyAuthenticator
110      RequestField  = "Proxy-Authorization" # :nodoc:
111      ResponseField = "Proxy-Authenticate" # :nodoc:
112      InfoField     = "Proxy-Authentication-Info" # :nodoc:
113      AuthException = HTTPStatus::ProxyAuthenticationRequired # :nodoc:
114    end
115  end
116end
117