aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/web_interface.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mauve/web_interface.rb')
-rw-r--r--lib/mauve/web_interface.rb220
1 files changed, 155 insertions, 65 deletions
diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb
index 4569cb6..210f88a 100644
--- a/lib/mauve/web_interface.rb
+++ b/lib/mauve/web_interface.rb
@@ -1,7 +1,11 @@
# encoding: UTF-8
+require 'haml'
+require 'redcloth'
+
+require 'sinatra/tilt'
require 'sinatra/base'
require 'sinatra-partials'
-require 'haml'
+
require 'rack'
require 'rack-flash'
@@ -16,15 +20,18 @@ module Mauve
class PleaseAuthenticate < Exception; end
- use Rack::Session::Cookie, :expire_after => 604800 # 7 days in seconds
+ use Rack::CommonLogger
+ use Rack::Chunked
+ use Rack::ContentLength
+ use Rack::Flash
- enable :sessions
+# Tilt.register :textile, RedClothTemplate
- use Rack::Flash
-
- set :root, "/usr/share/mauve"
- set :views, "#{root}/views"
- set :public, "#{root}/static"
+
+ # Ugh.. hacky way to dynamically configure the document root.
+ set :root, Proc.new{ HTTPServer.instance.document_root }
+ set :views, Proc.new{ root && File.join(root, 'views') }
+ set :public, Proc.new{ root && File.join(root, 'static') }
set :static, true
set :show_exceptions, true
@@ -39,12 +46,43 @@ module Mauve
########################################################################
before do
- @person = Configuration.current.people[session['username']]
@title = "Mauve alert panel"
+ @person = nil
+ #
+ # Make sure we're authenticated.
+ #
+
+ if session.has_key?('username') and Configuration.current.people.has_key?(session['username'].to_s)
+ #
+ # Phew, we're authenticated
+ #
+ @person = Configuration.current.people[session['username']]
+
+ #
+ # A bit wasteful maybe..?
+ #
+ @alerts_raised = Alert.all_raised
+ @alerts_cleared = Alert.all_cleared
+ @alerts_ackd = Alert.all_acknowledged
+ @group_by = "subject"
+ else
+ # Uh-oh.. Intruder alert!
+ #
+ ok_urls = %w(/ /login /logout)
+
+ unless ok_urls.include?(request.path_info)
+ flash['error'] = "You must be logged in to access that page."
+ redirect "/login?next_page=#{request.path_info}"
+ end
+ end
end
get '/' do
- redirect '/alerts'
+ if @person.nil?
+ redirect '/login'
+ else
+ redirect '/alerts'
+ end
end
########################################################################
@@ -53,36 +91,69 @@ module Mauve
#
# The password can be either the SSO or a local one defined
# in the configuration file.
- #
+
+ get '/login' do
+ if @person
+ redirect '/'
+ else
+ @next_page = params[:next_page] || '/'
+ haml :login
+ end
+ end
+
post '/login' do
usr = params['username']
pwd = params['password']
- ret_sso = helper_auth_SSO(usr, pwd)
- ret_loc = helper_auth_local(usr, pwd)
- if "success" == ret_sso or "success" == ret_loc
+ next_page = params['next_page']
+ #
+ # Make sure we don't magically logout automatically :)
+ #
+ next_page = '/' if next_page == '/logout'
+
+ if auth_helper(usr, pwd)
session['username'] = usr
+ redirect next_page
else
- flash['error'] =<<__MSG
-<hr /> <img src="/images/error.png" /> <br />
-ACCESS DENIED <br />
-#{ret_sso} <br />
-#{ret_loc} <hr />
-__MSG
+ flash['error'] = "Access denied."
end
- redirect '/alerts'
end
get '/logout' do
session.delete('username')
- redirect '/alerts'
+ redirect '/login'
end
get '/alerts' do
- #now = MauveTime.now.to_f
- please_authenticate()
- find_active_alerts()
- #pp MauveTime.now.to_f - now
- haml(:alerts2)
+ redirect '/alerts/raised'
+ end
+
+ get '/alerts/:alert_type' do
+ redirect "/alerts/#{params[:alert_type]}/subject"
+ end
+
+ get '/alerts/:alert_type/:group_by' do
+ if %w(raised cleared acknowledged).include?(params[:alert_type])
+ @alert_type = params[:alert_type]
+ else
+ @alert_type = "raised"
+ end
+
+ if %w(subject source summary id alert_id level).include?(params[:group_by])
+ @group_by = params[:group_by]
+ else
+ @group_by = "subject"
+ end
+
+ case @alert_type
+ when "raised"
+ @grouped_alerts = group_by(@alerts_raised, @group_by)
+ when "cleared"
+ @grouped_alerts = group_by(@alerts_cleared, @group_by)
+ when "acknowledged"
+ @grouped_alerts = group_by(@alerts_ackd, @group_by)
+ end
+
+ haml(:alerts)
end
get '/_alert_summary' do
@@ -98,22 +169,20 @@ __MSG
partial("head")
end
- get '/alert/:id/detail' do
- please_authenticate
-
- content_type("text/html") # I think
- Alert.get(params[:id]).detail
+ get '/alert/:id/_detail' do
+ content_type "text/html"
+ alert = Alert.get(params[:id])
+
+ haml :_detail, :locals => { :alert => alert } unless alert.nil?
end
get '/alert/:id' do
- please_authenticate
find_active_alerts
@alert = Alert.get(params['id'])
haml :alert
end
post '/alert/:id/acknowledge' do
- please_authenticate
alert = Alert.get(params[:id])
if alert.acknowledged?
@@ -128,7 +197,6 @@ __MSG
# Note that :until must be in seconds.
post '/alert/acknowledge/:id/:until' do
#now = MauveTime.now.to_f
- please_authenticate
alert = Alert.get(params[:id])
alert.acknowledge!(@person, params[:until].to_i())
@@ -140,7 +208,6 @@ __MSG
post '/alert/:id/raise' do
#now = MauveTime.now.to_f
- please_authenticate
alert = Alert.get(params[:id])
alert.raise!
@@ -150,7 +217,6 @@ __MSG
end
post '/alert/:id/clear' do
- please_authenticate
alert = Alert.get(params[:id])
alert.clear!
@@ -159,7 +225,6 @@ __MSG
end
post '/alert/:id/toggleDetailView' do
- please_authenticate
alert = Alert.get(params[:id])
if nil != alert
@@ -171,8 +236,6 @@ __MSG
end
post '/alert/fold/:subject' do
- please_authenticate
-
session[:display_folding][params[:subject]] = (true == session[:display_folding][params[:subject]])? false : true
content_type("application/json")
'all is good'.to_json
@@ -181,7 +244,6 @@ __MSG
########################################################################
get '/preferences' do
- please_authenticate
find_active_alerts
haml :preferences
end
@@ -189,7 +251,6 @@ __MSG
########################################################################
get '/events' do
- please_authenticate
find_active_alerts
find_recent_alerts
haml :events
@@ -199,11 +260,21 @@ __MSG
helpers do
include Sinatra::Partials
-
- def please_authenticate
- raise PleaseAuthenticate.new unless @person
+
+ def group_by(things, meth)
+ return {} if things.empty?
+
+ raise ArgumentError.new "#{things.first.class} does not respond to #{meth}" unless things.first.respond_to?(meth)
+
+ results = Hash.new{|h,k| h[k] = Array.new}
+
+ things.each do |thing|
+ results[thing.__send__(meth)] << thing
+ end
+
+ results
end
-
+
def find_active_alerts
# FIXME: make sure alerts only appear once some better way
@@ -287,25 +358,45 @@ __MSG
## Test for authentication with SSO.
#
- def helper_auth_SSO (usr, pwd)
- auth = AuthSourceBytemark.new()
- begin
- return "success" if true == auth.authenticate(usr,pwd)
- return "SSO did not regcognise your login/password combination."
- rescue ArgumentError => ex
- return "SSO argument error: #{ex.message}"
- rescue => ex
- return "SSO generic error: #{ex.message}"
+ def auth_helper (usr, pwd)
+ # First try Bytemark
+ #
+ auth = AuthBytemark.new()
+ result = begin
+ auth.authenticate(usr,pwd)
+ rescue Exception => ex
+ @logger.debug "Caught exception during Bytemark auth for #{usr} (#{ex.to_s})"
+ false
end
- end
- ## Test for authentication with configuration file parameter.
- #
- def helper_auth_local (usr, pwd)
- person = Configuration.current.people[params['username']]
- return "I did not recognise your local login details." if !person
- return "I did not recognise your local password." if Digest::SHA1.hexdigest(params['password']) != person.password
- return "success"
+ if true == result
+ return true
+ else
+ @logger.debug "Bytemark authentication failed for #{usr}"
+ end
+
+ #
+ # OK now try local auth
+ #
+ result = begin
+ if Configuration.current.people.has_key?(usr)
+ Digest::SHA1.hexdigest(params['password']) == Configuration.current.people[usr].password
+ end
+ rescue Exception => ex
+ @logger.debug "Caught exception during local auth for #{usr} (#{ex.to_s})"
+ false
+ end
+
+ if true == result
+ return true
+ else
+ @logger.debug "Local authentication failed for #{usr}"
+ end
+ #
+ # Rate limit logins.
+ #
+ sleep 5
+ false
end
end
@@ -316,14 +407,13 @@ __MSG
status 403
session[:display_alerts] = Hash.new()
session[:display_folding] = Hash.new()
- haml :please_authenticate
end
########################################################################
# @see http://stackoverflow.com/questions/2239240/use-rackcommonlogger-in-sinatra
def call(env)
if true == @logger.nil?
- @logger = Log4r::Logger.new("mauve::Rack")
+ @logger = Log4r::Logger.new("Mauve::Rack")
end
env['rack.errors'] = RackErrorsProxy.new(@logger)
super(env)