Added admin session management.

This commit is contained in:
Martin Edenhofer 2013-07-26 23:45:16 +02:00
parent e47b20ec03
commit cbca117f72
9 changed files with 200 additions and 7 deletions

View file

@ -0,0 +1,55 @@
class Session extends App.ControllerContent
events:
'click [data-type="delete"]': 'destroy'
constructor: ->
super
# check authentication
return if !@authenticate()
@load()
@interval(
=>
@load
10000
)
# fetch data, render view
load: ->
App.Com.ajax(
id: 'sessions'
type: 'GET'
url: 'api/sessions'
success: (data) =>
@render(data)
)
render: (data) ->
App.Collection.load( type: 'User', data: data.users )
# fill users
for session in data.sessions
if session.data && session.data.user_id
session.data.user = App.User.find( session.data.user_id )
@html App.view('session')(
sessions: data.sessions
)
# show frontend times
@frontendTimeUpdate()
destroy: (e) ->
e.preventDefault()
sessionId = $( e.target ).data('session-id')
App.Com.ajax(
id: 'sessions/' + sessionId
type: 'DELETE'
url: 'api/sessions/' + sessionId
success: (data) =>
@load()
)
App.Config.set( 'session', Session, 'Routes' )
App.Config.set( 'session', { prio: 3700, parent: '#admin', name: 'Sessions', target: '#session', role: ['Admin'] }, 'NavBar' )

View file

@ -0,0 +1,28 @@
<div class="page-header">
<h1><%- @T('Sessions') %><small></small></h1>
</div>
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="span4"><%- @T('User') %></th>
<th class="span3"><%- @T('Browser') %></th>
<th class="span3"><%- @T('Location') %></th>
<th class="span1"><%- @T('Age') %></th>
<th class="span1"><%- @T('Update') %></th>
<th class="span1"></th>
</tr>
</thead>
<tbody>
<% for session in @sessions: %>
<tr>
<td><% if session.data.user: %><%= session.data.user.displayName() %><% end %></td>
<td><% if session.data.user_agent: %><%= session.data.user_agent %><% end %></td>
<td><% if session.data.geo: %><%= session.data.geo.country_code %> <%= session.data.geo.city %><% end %></td>
<td><span class="humanTimeFromNow" data-time="<%- session.created_at %>">?</span></td>
<td><span class="humanTimeFromNow" data-time="<%- session.updated_at %>">?</span></td>
<td><a href="#" data-session-id="<%- session.id %>" data-type="delete" class="icon-trash" title="<%- @T('Delete') %>"></a></td>
</tr>
<% end %>
</tbody>
</table>

View file

@ -14,7 +14,7 @@ class ApplicationController < ActionController::Base
:mode_show_rendeder,
:model_index_render
before_filter :set_user
before_filter :set_user, :session_update
before_filter :cors_preflight_check
after_filter :set_access_control_headers
@ -73,9 +73,26 @@ class ApplicationController < ActionController::Base
UserInfo.current_user_id = current_user.id
end
# update session updated_at
def session_update
session[:ping] = Time.now.utc.iso8601
# check if remote ip need to be updated
if !session[:remote_id] || session[:remote_id] != request.remote_ip
session[:remote_id] = request.remote_ip
session[:geo] = Geoip.location( request.remote_ip )
end
# fill user agent
if !session[:user_agent]
session[:user_agent] = request.env['HTTP_USER_AGENT']
end
end
def authentication_check_only
puts 'authentication_check'
session[:request_type] = 1
#puts params.inspect
#puts session.inspect
#puts cookies.inspect
@ -83,6 +100,8 @@ class ApplicationController < ActionController::Base
# check http basic auth
authenticate_with_http_basic do |username, password|
puts 'http basic auth check'
session[:request_type] = 2
userdata = User.authenticate( username, password )
message = ''
if !userdata
@ -113,6 +132,8 @@ class ApplicationController < ActionController::Base
userdata = User.find( logon_session.data[:user_id] )
end
session[:request_type] = 3
# set logon session user to current user
current_user_set(userdata)
return {

View file

@ -148,4 +148,30 @@ class SessionsController < ApplicationController
redirect_to '/#'
end
def list
return if deny_if_not_role('Admin')
sessions = ActiveRecord::SessionStore::Session.order('created_at DESC').limit(10000)
users = {}
sessions_clean = []
sessions.each {|session|
next if !session.data['user_id']
sessions_clean.push session
if session.data['user_id']
if !users[ session.data['user_id'] ]
users[ session.data['user_id'] ] = User.user_data_full( session.data['user_id'] )
end
end
}
render :json => {
:sessions => sessions_clean,
:users => users,
}
end
def delete
return if deny_if_not_role('Admin')
session = ActiveRecord::SessionStore::Session.find(params[:id])
session.destroy
render :json => {}
end
end

View file

@ -0,0 +1,25 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
require 'history'
class Observer::Session < ActiveRecord::Observer
observe 'active_record::_session_store::_session'
def before_create(record)
check(record)
end
def before_update(record)
check(record)
end
def check(record)
return if !record.data
# remember request type
if record.data['request_type']
record[:request_type] = record.data['request_type']
record.data.delete('request_type')
end
end
end

View file

@ -26,6 +26,7 @@ module Zammad
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
config.active_record.observers =
'observer::_session',
'observer::_history',
'observer::_ticket::_first_response',
'observer::_ticket::_last_contact',

View file

@ -2,16 +2,18 @@ module ExtraRoutes
def add(map)
# omniauth
map.match '/auth/:provider/callback', :to => 'sessions#create_omniauth'
map.match '/auth/:provider/callback', :to => 'sessions#create_omniauth',:via => [:post, :get, :puts, :delete]
# sso
map.match '/auth/sso', :to => 'sessions#create_sso'
map.match '/auth/sso', :to => 'sessions#create_sso', :via => [:post, :get]
# sessions
map.match '/signin', :to => 'sessions#create'
map.match '/signshow', :to => 'sessions#show'
map.match '/signout', :to => 'sessions#destroy'
map.match '/signin', :to => 'sessions#create', :via => :post
map.match '/signshow', :to => 'sessions#show', :via => :get
map.match '/signout', :to => 'sessions#destroy', :via => [:get, :delete]
map.match '/api/sessions', :to => 'sessions#list', :via => :get
map.match '/api/sessions/:id', :to => 'sessions#delete', :via => :delete
end
module_function :add
end
end

View file

@ -0,0 +1,9 @@
class UpdateSession < ActiveRecord::Migration
def up
add_column :sessions, :request_type, :integer, :null => true
add_index :sessions, :request_type
end
def down
end
end

26
lib/geoip.rb Normal file
View file

@ -0,0 +1,26 @@
require 'faraday'
require 'cache'
module Geoip
def self.location(address)
# check cache
cache_key = "geoip::#{address}"
cache = Cache.get( cache_key )
return cache if cache
# do lookup
host = "http://freegeoip.net"
url = "/json/#{CGI::escape address}"
data = {}
begin
conn = Faraday.new( :url => host )
response = conn.get url
data = JSON.parse( response.body )
Cache.write( cache_key, data, { :expires_in => 90.days } )
rescue
Cache.write( cache_key, data, { :expires_in => 60.minutes } )
end
data
end
end