Added admin session management.
This commit is contained in:
parent
e47b20ec03
commit
cbca117f72
9 changed files with 200 additions and 7 deletions
55
app/assets/javascripts/app/controllers/session.js.coffee
Normal file
55
app/assets/javascripts/app/controllers/session.js.coffee
Normal 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' )
|
28
app/assets/javascripts/app/views/session.jst.eco
Normal file
28
app/assets/javascripts/app/views/session.jst.eco
Normal 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>
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ApplicationController < ActionController::Base
|
||||||
:mode_show_rendeder,
|
:mode_show_rendeder,
|
||||||
:model_index_render
|
:model_index_render
|
||||||
|
|
||||||
before_filter :set_user
|
before_filter :set_user, :session_update
|
||||||
before_filter :cors_preflight_check
|
before_filter :cors_preflight_check
|
||||||
|
|
||||||
after_filter :set_access_control_headers
|
after_filter :set_access_control_headers
|
||||||
|
@ -73,9 +73,26 @@ class ApplicationController < ActionController::Base
|
||||||
UserInfo.current_user_id = current_user.id
|
UserInfo.current_user_id = current_user.id
|
||||||
end
|
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
|
def authentication_check_only
|
||||||
|
|
||||||
puts 'authentication_check'
|
puts 'authentication_check'
|
||||||
|
session[:request_type] = 1
|
||||||
#puts params.inspect
|
#puts params.inspect
|
||||||
#puts session.inspect
|
#puts session.inspect
|
||||||
#puts cookies.inspect
|
#puts cookies.inspect
|
||||||
|
@ -83,6 +100,8 @@ class ApplicationController < ActionController::Base
|
||||||
# check http basic auth
|
# check http basic auth
|
||||||
authenticate_with_http_basic do |username, password|
|
authenticate_with_http_basic do |username, password|
|
||||||
puts 'http basic auth check'
|
puts 'http basic auth check'
|
||||||
|
session[:request_type] = 2
|
||||||
|
|
||||||
userdata = User.authenticate( username, password )
|
userdata = User.authenticate( username, password )
|
||||||
message = ''
|
message = ''
|
||||||
if !userdata
|
if !userdata
|
||||||
|
@ -113,6 +132,8 @@ class ApplicationController < ActionController::Base
|
||||||
userdata = User.find( logon_session.data[:user_id] )
|
userdata = User.find( logon_session.data[:user_id] )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
session[:request_type] = 3
|
||||||
|
|
||||||
# set logon session user to current user
|
# set logon session user to current user
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -148,4 +148,30 @@ class SessionsController < ApplicationController
|
||||||
redirect_to '/#'
|
redirect_to '/#'
|
||||||
end
|
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
|
end
|
||||||
|
|
25
app/models/observer/session.rb
Normal file
25
app/models/observer/session.rb
Normal 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
|
|
@ -26,6 +26,7 @@ module Zammad
|
||||||
# Activate observers that should always be running.
|
# Activate observers that should always be running.
|
||||||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||||
config.active_record.observers =
|
config.active_record.observers =
|
||||||
|
'observer::_session',
|
||||||
'observer::_history',
|
'observer::_history',
|
||||||
'observer::_ticket::_first_response',
|
'observer::_ticket::_first_response',
|
||||||
'observer::_ticket::_last_contact',
|
'observer::_ticket::_last_contact',
|
||||||
|
|
|
@ -2,16 +2,18 @@ module ExtraRoutes
|
||||||
def add(map)
|
def add(map)
|
||||||
|
|
||||||
# omniauth
|
# 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
|
# sso
|
||||||
map.match '/auth/sso', :to => 'sessions#create_sso'
|
map.match '/auth/sso', :to => 'sessions#create_sso', :via => [:post, :get]
|
||||||
|
|
||||||
# sessions
|
# sessions
|
||||||
map.match '/signin', :to => 'sessions#create'
|
map.match '/signin', :to => 'sessions#create', :via => :post
|
||||||
map.match '/signshow', :to => 'sessions#show'
|
map.match '/signshow', :to => 'sessions#show', :via => :get
|
||||||
map.match '/signout', :to => 'sessions#destroy'
|
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
|
end
|
||||||
module_function :add
|
module_function :add
|
||||||
end
|
end
|
||||||
|
|
9
db/migrate/20130726000001_update_session.rb
Normal file
9
db/migrate/20130726000001_update_session.rb
Normal 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
26
lib/geoip.rb
Normal 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
|
Loading…
Reference in a new issue