aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick J Cherry <patrick@bytemark.co.uk>2012-03-22 17:40:38 +0000
committerPatrick J Cherry <patrick@bytemark.co.uk>2012-03-22 17:40:38 +0000
commitdc443284c4b5f59a4447797f88730d9fe1bc0b45 (patch)
tree1f82d0e9754c3239cc4ac65220ef4f54a4a5e44e
parent2622cd5d2cb322b78229d345d82076a582925ae2 (diff)
Tidied up login authentication + tests (woo!)
-rw-r--r--lib/mauve/authentication.rb9
-rw-r--r--lib/mauve/web_interface.rb17
-rw-r--r--test/tc_mauve_web_interface.rb175
-rw-r--r--test/test_mauve.rb1
-rw-r--r--views/login.haml2
5 files changed, 196 insertions, 8 deletions
diff --git a/lib/mauve/authentication.rb b/lib/mauve/authentication.rb
index d0d4596..54743f1 100644
--- a/lib/mauve/authentication.rb
+++ b/lib/mauve/authentication.rb
@@ -139,7 +139,7 @@ module Mauve
client.login(login, response)
return true
rescue XMLRPC::FaultException => fault
- logger.warn "Authentication for #{login} failed: #{fault.faultCode}: #{fault.faultString}"
+ logger.warn "#{self.class} for #{login} failed: #{fault.faultCode}: #{fault.faultString}"
return false
rescue IOError => ex
logger.warn "#{ex.class} during auth for #{login} (#{ex.to_s})"
@@ -164,7 +164,12 @@ module Mauve
# @return [Boolean]
def authenticate(login,password)
super
- Digest::SHA1.hexdigest(password) == Mauve::Configuration.current.people[login].password
+ if ( Digest::SHA1.hexdigest(password) == Mauve::Configuration.current.people[login].password )
+ return true
+ else
+ logger.warn "#{self.class} for #{login} failed"
+ return false
+ end
end
end
diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb
index b998ad8..225cc33 100644
--- a/lib/mauve/web_interface.rb
+++ b/lib/mauve/web_interface.rb
@@ -4,6 +4,7 @@ require 'redcloth'
require 'json'
require 'mauve/authentication'
+require 'mauve/http_server'
tilt_lib = "tilt"
begin
@@ -120,7 +121,6 @@ EOF
unless ok_urls.include?(request.path_info)
flash['error'] = "You must be logged in to access that page."
- status 403
redirect "/login?next_page=#{request.path_info}" unless no_redirect_urls.any?{|u| /^#{u}/ =~ request.path_info }
end
end
@@ -146,7 +146,9 @@ EOF
if @person
redirect '/'
else
+ @username = nil
@next_page = params[:next_page] || '/'
+ status 403 if flash['error']
haml :login
end
end
@@ -154,7 +156,7 @@ EOF
post '/login' do
usr = params['username'].to_s
pwd = params['password'].to_s
- next_page = params['next_page'].to_s
+ next_page = params['next_page'] || "/"
#
# Make sure we don't magically logout automatically :)
@@ -165,14 +167,19 @@ EOF
session['username'] = usr
redirect next_page
else
- flash['error'] = "You must be logged in to access that page."
- redirect "/login?next_page=#{next_page}"
+ flash['error'] = "Authentication failed."
+ status 401
+# redirect "/login?next_page=#{next_page}"
+ @title += " Login"
+ @username = usr
+ @next_page = next_page
+ haml :login
end
end
get '/logout' do
session.delete('username')
- flash['error'] = "You have logged out!"
+ flash['info'] = "You have logged out!"
redirect '/login'
end
diff --git a/test/tc_mauve_web_interface.rb b/test/tc_mauve_web_interface.rb
new file mode 100644
index 0000000..a120c37
--- /dev/null
+++ b/test/tc_mauve_web_interface.rb
@@ -0,0 +1,175 @@
+$:.unshift "../lib"
+
+require 'th_mauve'
+require 'th_mauve_resolv'
+
+require 'mauve/alert'
+require 'mauve/proto'
+require 'mauve/server'
+require 'mauve/configuration'
+require 'mauve/configuration_builder'
+require 'mauve/configuration_builders'
+
+require 'rack/test'
+
+ENV['RACK_ENV'] = 'test'
+
+class WebInterfaceTest < Mauve::UnitTest
+ include Rack::Test::Methods
+ include Mauve
+
+ SESSION_KEY="mauvealert"
+
+ class SessionData
+ def initialize(cookies)
+ @cookies = cookies
+ @data = cookies[WebInterfaceTest::SESSION_KEY]
+ if @data
+ @data = @data.unpack("m*").first
+ @data = Marshal.load(@data)
+ else
+ @data = {}
+ end
+ end
+
+ def [](key)
+ @data[key]
+ end
+
+ def []=(key, value)
+ @data[key] = value
+ session_data = Marshal.dump(@data)
+ session_data = [session_data].pack("m*")
+ @cookies.merge("#{WebInterfaceTest::SESSION_KEY}=#{Rack::Utils.escape(session_data)}", URI.parse("//example.org//"))
+ raise "session variable not set" unless @cookies[WebInterfaceTest::SESSION_KEY] == session_data
+ end
+ end
+
+ def session
+ SessionData.new(rack_test_session.instance_variable_get(:@rack_mock_session).cookie_jar)
+ end
+
+ def setup
+ super
+ setup_database
+
+ #
+ # BytemarkAuth test users are:
+ #
+ # test1: ummVRu7qF
+ # test2: POKvBqLT7
+ #
+ config =<<EOF
+server {
+ hostname "localhost"
+ database "sqlite::memory:"
+ initial_sleep 0
+
+ web_interface {
+ document_root "#{File.expand_path(File.join(File.dirname(__FILE__),".."))}"
+ }
+}
+
+person ("test0") {
+ password "#{Digest::SHA1.new.hexdigest("password")}"
+ all { true }
+}
+
+person ("test1") {
+ password "#{Digest::SHA1.new.hexdigest("ummVRu7qF")}"
+ all { true }
+}
+
+source_list "example_hosts", %w(test-1.example.com test-2.example.com www.example.com www2.example.com)
+
+alert_group("test") {
+ includes{ in_source_list?("example_hosts") }
+
+ level LOW
+
+ notify("test1") {
+ every 10.minutes
+ }
+
+}
+
+alert_group("default") {
+ level URGENT
+
+ notify("test1") {
+ every 10.minutes
+ }
+}
+EOF
+
+ Configuration.current = ConfigurationBuilder.parse(config)
+ Server.instance.setup
+ end
+
+ def teardown
+ teardown_database
+ super
+ end
+
+ def app
+ Rack::Session::Cookie.new(WebInterface.new, :key => WebInterfaceTest::SESSION_KEY, :secret => "testing-1234")
+ end
+
+ def test_log_in
+ # Check we get the login page when going to "/" before logging in.
+ get '/'
+ follow_redirect! while last_response.redirect?
+ assert last_response.ok?
+ assert last_response.body.include?("Mauve: Login")
+ assert session['__FLASH__'].empty?
+
+ # Check we can access this page before logging in.
+ get '/alerts'
+ assert(session['__FLASH__'].has_key?(:error),"The flash error wasn't set following forbidden access")
+ follow_redirect! while last_response.redirect?
+ assert_equal(403, last_response.status, "The HTTP status wasn't 403")
+ assert last_response.body.include?("Mauve: Login")
+ assert session['__FLASH__'].empty?
+
+ #
+ # Try to falsify our login.
+ #
+ session['username'] = "test1"
+ get '/alerts'
+ assert(session['__FLASH__'].has_key?(:error),"The flash error wasn't set following forbidden access")
+ follow_redirect! while last_response.redirect?
+ assert_equal(403, last_response.status, "The HTTP status wasn't 403")
+ assert last_response.body.include?("Mauve: Login")
+ assert session['__FLASH__'].empty?
+
+ #
+ # OK login with a bad password
+ #
+ post '/login', :username => 'test1', :password => 'badpassword'
+ assert_equal(401, last_response.status, "A bad login did not produce a 401 response")
+ assert(last_response.body.include?("Mauve: Login"))
+ assert(session['__FLASH__'].has_key?(:error),"The flash error wasn't set")
+
+ post '/login', :username => 'test1', :password => 'ummVRu7qF'
+ follow_redirect! while last_response.redirect?
+ assert last_response.body.include?('Mauve: ')
+
+ get '/logout'
+ follow_redirect! while last_response.redirect?
+ assert last_response.ok?
+ end
+
+ def test_alerts_show_subject
+ post '/login', :username => 'test1', :password => 'ummVRu7qF'
+ follow_redirect! while last_response.redirect?
+ assert last_response.body.include?('Mauve: ')
+
+ a = Alert.new(:source => "www.example.com", :alert_id => "test_raise!")
+ a.raise!
+
+ get '/alerts/raised/subject'
+ end
+
+end
+
+
diff --git a/test/test_mauve.rb b/test/test_mauve.rb
index bdce3aa..ce83c6c 100644
--- a/test/test_mauve.rb
+++ b/test/test_mauve.rb
@@ -24,6 +24,7 @@ tc_mauve_people_list.rb
tc_mauve_person.rb
tc_mauve_source_list.rb
tc_mauve_time.rb
+tc_mauve_web_interface.rb
).each do |s|
require s
end
diff --git a/views/login.haml b/views/login.haml
index 3deee76..d1e9484 100644
--- a/views/login.haml
+++ b/views/login.haml
@@ -2,7 +2,7 @@
%fieldset
%legend Please log in
%label{:for => "username"} Username
- %input{:name => 'username', :type => 'text', :autocorrect => "off", :autocapitalize => "off"}/
+ %input{:name => 'username', :type => 'text', :autocorrect => "off", :autocapitalize => "off", :value => @username}/
%br
%label{:for => "password", :title => "This is either your Single Sign On password or a PIN."} Password / PIN
%input{:name => 'password', :type => 'password'}/