aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve
diff options
context:
space:
mode:
authorPatrick J Cherry <patrick@bytemark.co.uk>2012-04-21 13:37:12 +0100
committerPatrick J Cherry <patrick@bytemark.co.uk>2012-04-21 13:37:12 +0100
commit84b1abf30fe79032209cb0fcd0bfa9d6aaf37721 (patch)
tree403433b040d2b51b5d40c56b10a530e7fcf2aef4 /lib/mauve
parent392a87cfa181a762bf4b3244aa3c6d065ef15253 (diff)
Overhaul of authentication.
* Added new configuration options: ** bytemark_calendar_url ** bytemark_auth_url ** remote_https_verify_mode ** remote_http_timeout ** failed_login_delay * Added authentication tests * Removed remote auth tests in from the web interface tests. * If no bytemark_auth_url is set, then no remote auth takes place. * SSL peer cert validation now takes place by default. * Removed old logic tests * Tidied the way tests take place a little.
Diffstat (limited to 'lib/mauve')
-rw-r--r--lib/mauve/authentication.rb71
-rw-r--r--lib/mauve/configuration_builders/server.rb27
-rw-r--r--lib/mauve/server.rb98
3 files changed, 146 insertions, 50 deletions
diff --git a/lib/mauve/authentication.rb b/lib/mauve/authentication.rb
index 0fc6823..c467a1d 100644
--- a/lib/mauve/authentication.rb
+++ b/lib/mauve/authentication.rb
@@ -1,7 +1,6 @@
# encoding: UTF-8
require 'sha1'
require 'xmlrpc/client'
-require 'timeout'
#
# This allows poking of the SSL attributes of the http client.
@@ -28,8 +27,6 @@ module Mauve
raise ArgumentError.new("Password must be a string, not a #{password.class}") if String != password.class
raise ArgumentError.new("Login or/and password is/are empty.") if login.empty? || password.empty?
- return false unless Mauve::Configuration.current.people.has_key?(login)
-
false
end
@@ -73,7 +70,7 @@ module Mauve
unless true == result
logger.info "Authentication for #{login} failed"
# Rate limit
- sleep 5
+ sleep Server.instance.failed_login_delay
end
result
@@ -88,45 +85,6 @@ module Mauve
Mauve::Authentication::ORDER << self
- # Set up the Bytemark authenticator
- #
- # @todo allow configuration of where the server is.
- #
- # @param [String] srv Authentication server name
- # @param [String] port Port overwhich authentication should take place
- #
- # @return [Mauve::AuthBytemark]
- #
- def initialize (srv='auth.bytemark.co.uk', port=443)
- raise ArgumentError.new("Server must be a String, not a #{srv.class}") if String != srv.class
- raise ArgumentError.new("Port must be a Fixnum, not a #{port.class}") if Fixnum != port.class
- @srv = srv
- @port = port
- @timeout = 7
-
- self
- end
-
- # Tests to see if a server is alive, alive-o.
- #
- # @deprecated Not really needed.
- #
- # @return [Boolean]
- def ping
- begin
- Timeout.timeout(@timeout) do
- s = TCPSocket.open(@srv, @port)
- s.close()
- return true
- end
- rescue Timeout::Error => ex
- return false
- rescue => ex
- return false
- end
- return false
- end
-
# Authenticate against the Bytemark server
#
# @param [String] login
@@ -136,14 +94,27 @@ module Mauve
def authenticate(login, password)
super
- client = XMLRPC::Client.new(@srv,"/",@port,nil,nil,nil,nil,true,@timeout)
+ #
+ # Don't bother checking if no auth_url has been set.
+ #
+ return false unless Server.instance.bytemark_auth_url.is_a?(URI)
+
+ #
+ # Don't bother checking if the person doesn't exist.
+ #
+ return false unless Mauve::Configuration.current.people.has_key?(login)
+
+ uri = Server.instance.bytemark_auth_url
+ timeout = Server.instance.remote_http_timeout
+ # host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil)
+ client = XMLRPC::Client.new(uri.host, uri.path, uri.port, nil, nil, uri.user, uri.password, uri.scheme == "https", timeout)
#
# Make sure we verify our peer before attempting login.
#
if client.http.use_ssl?
client.http.ca_path = "/etc/ssl/certs/"
- client.http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ client.http.verify_mode = Server.instance.remote_https_verify_mode
end
begin
@@ -179,6 +150,16 @@ module Mauve
# @return [Boolean]
def authenticate(login,password)
super
+ #
+ # Don't bother checking if the person doesn't exist.
+ #
+ return false unless Mauve::Configuration.current.people.has_key?(login)
+
+ #
+ # Don't bother checking if no password has been set.
+ #
+ return false if Mauve::Configuration.current.people[login].password.nil?
+
if ( Digest::SHA1.hexdigest(password) == Mauve::Configuration.current.people[login].password )
return true
else
diff --git a/lib/mauve/configuration_builders/server.rb b/lib/mauve/configuration_builders/server.rb
index feb75b8..d22ed87 100644
--- a/lib/mauve/configuration_builders/server.rb
+++ b/lib/mauve/configuration_builders/server.rb
@@ -170,7 +170,32 @@ module Mauve
#
is_attribute "use_packet_buffer"
is_attribute "use_notification_buffer"
-
+
+ #
+ # This is where the calendar is located. The request paths are hard-coded.
+ #
+ is_attribute "bytemark_calendar_url"
+
+ #
+ # This is where the Bytemark authentication server is located.
+ #
+ is_attribute "bytemark_auth_url"
+
+ #
+ # This is the level of SSL verification used when making external HTTPS connections.
+ #
+ is_attribute "remote_https_verify_mode"
+
+ #
+ # This is the default timeout when making remote HTTP requests
+ #
+ is_attribute "remote_http_timeout"
+
+ #
+ # This is the default sleep time after an authentication attempt has failed.
+ #
+ is_attribute "failed_login_delay"
+
def builder_setup
@result = Mauve::Server.instance
end
diff --git a/lib/mauve/server.rb b/lib/mauve/server.rb
index db5fda6..2b0e101 100644
--- a/lib/mauve/server.rb
+++ b/lib/mauve/server.rb
@@ -27,6 +27,7 @@ module Mauve
attr_reader :hostname, :database, :initial_sleep
attr_reader :packet_buffer, :notification_buffer, :started_at
+ attr_reader :bytemark_auth_url, :bytemark_calendar_url, :remote_http_timeout, :remote_https_verify_mode, :failed_login_delay
include Singleton
@@ -49,6 +50,23 @@ module Mauve
@notification_buffer = []
#
+ # Set the auth/calendar URLs
+ #
+ @bytemark_auth_url = nil
+ @bytemark_calendar_url = nil
+
+ #
+ # Set a couple of params for remote HTTP requests.
+ #
+ @remote_http_timeout = 5
+ @remote_https_verify_mode = OpenSSL::SSL::VERIFY_PEER
+
+ #
+ # Rate limit login attempts to limit the success of brute-forcing.
+ #
+ @failed_login_delay = 1
+
+ #
# Set up a blank config.
#
Configuration.current = Configuration.new if Mauve::Configuration.current.nil?
@@ -70,14 +88,12 @@ module Mauve
@database = d
end
- #
# Sets up the packet buffer (or not). The argument can be "false" or "no"
# or a FalseClass object for no. Anything else makes no change.
#
# @param [String] arg
# @return [Array or nil]
def use_packet_buffer=(arg)
- logger.debug(arg)
if arg.is_a?(FalseClass) or arg =~ /^(n(o)?|f(alse)?)$/i
@packet_buffer = nil
end
@@ -85,14 +101,12 @@ module Mauve
@packet_buffer
end
- #
# Sets up the notification buffer (or not). The argument can be "false" or
# "no" or a FalseClass object for no. Anything else makes no change.
#
# @param [String] arg
# @return [Array or nil]
def use_notification_buffer=(arg)
- logger.debug(arg)
if arg.is_a?(FalseClass) or arg =~ /^(n(o)?|f(alse)?)$/i
@notification_buffer = nil
end
@@ -100,6 +114,82 @@ module Mauve
@notification_buffer
end
+ # Set the calendar URL.
+ #
+ # @param [String] arg
+ # @return [URI]
+ def bytemark_calendar_url=(arg)
+ raise ArgumentError, "bytemark_calendar_url must be a string" unless arg.is_a?(String)
+
+ @bytemark_calendar_url = URI.parse(arg)
+
+ #
+ # Make sure we get an HTTP URL.
+ #
+ raise ArgumentError, "bytemark_calendar_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_calendar_url.scheme)
+
+ #
+ # Set a default request path, if none was given
+ #
+ @bytemark_calendar_url.path="/" if @bytemark_calendar_url.path.empty?
+
+ @bytemark_calendar_url
+ end
+
+ # Set the Bytemark Authentication URL
+ #
+ # @param [String] arg
+ # @return [URI]
+ def bytemark_auth_url=(arg)
+ raise ArgumentError, "bytemark_auth_url must be a string" unless arg.is_a?(String)
+
+ @bytemark_auth_url = URI.parse(arg)
+ #
+ # Make sure we get an HTTP URL.
+ #
+ raise ArgumentError, "bytemark_auth_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_auth_url.scheme)
+
+ #
+ # Set a default request path, if none was given
+ #
+ @bytemark_auth_url.path="/" if @bytemark_auth_url.path.empty?
+
+ @bytemark_auth_url
+ end
+
+ # Sets the timeout when making remote HTTP requests
+ #
+ # @param [Integer] arg
+ # @return [Integer]
+ def remote_http_timeout=(arg)
+ raise ArgumentError, "initial_sleep must be an integer" unless s.is_a?(Integer)
+ @remote_http_timeout = arg
+ end
+
+ # Sets the SSL verification mode when makeing remote HTTPS requests
+ #
+ # @param [String] arg must be one of "none" or "peer"
+ # @return [Constant]
+ def remote_https_verify_mode=(arg)
+ @remote_https_verify_mode = case arg
+ when "peer"
+ OpenSSL::SSL::VERIFY_PEER
+ when "none"
+ OpenSSL::SSL::VERIFY_NONE
+ else
+ raise ArgumentError, "remote_https_verify_mode must be either 'peer' or 'none'"
+ end
+ end
+
+ # Set the delay added following a failed login attempt.
+ #
+ # @param [Numeric] arg Number of seconds to delay following a failed login attempt
+ # @return [Numeric]
+ #
+ def failed_login_delay=(arg)
+ raise ArgumentError, "initial_sleep must be numeric" unless arg.is_a?(Numeric)
+ @failed_login_delay = arg
+ end
# Set the sleep period during which notifications about old alerts are
# suppressed.