Improved device logging.
This commit is contained in:
parent
2760137eef
commit
72bb0eb067
7 changed files with 145 additions and 38 deletions
|
@ -2,6 +2,7 @@ class App.Auth
|
||||||
|
|
||||||
@login: (params) ->
|
@login: (params) ->
|
||||||
App.Log.notice 'Auth', 'login', params
|
App.Log.notice 'Auth', 'login', params
|
||||||
|
params.data['fingerprint'] = App.Browser.fingerprint()
|
||||||
App.Ajax.request(
|
App.Ajax.request(
|
||||||
id: 'login'
|
id: 'login'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
|
@ -21,12 +22,15 @@ class App.Auth
|
||||||
)
|
)
|
||||||
|
|
||||||
@loginCheck: ->
|
@loginCheck: ->
|
||||||
|
params =
|
||||||
|
fingerprint: App.Browser.fingerprint()
|
||||||
App.Log.debug 'Auth', 'loginCheck'
|
App.Log.debug 'Auth', 'loginCheck'
|
||||||
App.Ajax.request(
|
App.Ajax.request(
|
||||||
id: 'login_check'
|
id: 'login_check'
|
||||||
async: false
|
async: false
|
||||||
type: 'GET'
|
type: 'POST'
|
||||||
url: App.Config.get('api_path') + '/signshow'
|
url: App.Config.get('api_path') + '/signshow'
|
||||||
|
data: JSON.stringify(params)
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
# set login (config, session, ...)
|
# set login (config, session, ...)
|
||||||
|
|
|
@ -14,10 +14,10 @@ class ApplicationController < ActionController::Base
|
||||||
:model_index_render
|
:model_index_render
|
||||||
|
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
before_action :set_user, :session_update, :check_user_device
|
before_action :set_user, :session_update
|
||||||
before_action :cors_preflight_check
|
before_action :cors_preflight_check
|
||||||
|
|
||||||
after_action :set_access_control_headers
|
after_action :user_device_update, :set_access_control_headers
|
||||||
after_action :trigger_events
|
after_action :trigger_events
|
||||||
|
|
||||||
# For all responses in this controller, return the CORS access control headers.
|
# For all responses in this controller, return the CORS access control headers.
|
||||||
|
@ -95,8 +95,8 @@ class ApplicationController < ActionController::Base
|
||||||
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
||||||
end
|
end
|
||||||
|
|
||||||
# check user device
|
# user device recent action update
|
||||||
def check_user_device
|
def user_device_update
|
||||||
|
|
||||||
# return if we are in switch to user mode
|
# return if we are in switch to user mode
|
||||||
return if session[:switched_from_user_id]
|
return if session[:switched_from_user_id]
|
||||||
|
@ -104,21 +104,46 @@ class ApplicationController < ActionController::Base
|
||||||
# only if user_id exists
|
# only if user_id exists
|
||||||
return if !session[:user_id]
|
return if !session[:user_id]
|
||||||
|
|
||||||
# only if write action
|
# only with user device
|
||||||
|
if !session[:user_device_id]
|
||||||
|
if params[:fingerprint]
|
||||||
|
return false if !user_device_log(current_user, 'session')
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# check if entry exists / only if write action
|
||||||
return if request.method == 'GET' || request.method == 'OPTIONS'
|
return if request.method == 'GET' || request.method == 'OPTIONS'
|
||||||
|
|
||||||
# only update if needed
|
# only update if needed
|
||||||
return if session[:check_user_device_at] && session[:check_user_device_at] > Time.zone.now - 5.minutes
|
return if session[:user_device_update_at] && session[:user_device_update_at] > Time.zone.now - 5.minutes
|
||||||
session[:check_user_device_at] = Time.zone.now
|
session[:user_device_update_at] = Time.zone.now
|
||||||
|
|
||||||
user_device = UserDevice.add(
|
UserDevice.action(
|
||||||
|
session[:user_device_id],
|
||||||
session[:user_agent],
|
session[:user_agent],
|
||||||
session[:remote_id],
|
session[:remote_id],
|
||||||
session[:user_id],
|
session[:user_id],
|
||||||
)
|
)
|
||||||
if user_device.id != session[:check_user_device_id]
|
end
|
||||||
session[:check_user_device_id] = user_device.id
|
|
||||||
|
def user_device_log(user, type)
|
||||||
|
|
||||||
|
# for sessions we need the fingperprint
|
||||||
|
if !params[:fingerprint] && type == 'session'
|
||||||
|
render json: { error: 'Need fingerprint param!' }, status: :unprocessable_entity
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# add defice if needed
|
||||||
|
user_device = UserDevice.add(
|
||||||
|
request.env['HTTP_USER_AGENT'],
|
||||||
|
request.remote_ip,
|
||||||
|
user.id,
|
||||||
|
params[:fingerprint],
|
||||||
|
type,
|
||||||
|
)
|
||||||
|
session[:user_device_id] = user_device.id
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_check_only(auth_param)
|
def authentication_check_only(auth_param)
|
||||||
|
@ -130,7 +155,8 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
# already logged in, early exit
|
# already logged in, early exit
|
||||||
if session.id && session[:user_id]
|
if session.id && session[:user_id]
|
||||||
userdata = User.find( session[:user_id] )
|
|
||||||
|
userdata = User.find(session[:user_id])
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -143,11 +169,10 @@ class ApplicationController < ActionController::Base
|
||||||
# check sso
|
# check sso
|
||||||
sso_userdata = User.sso(params)
|
sso_userdata = User.sso(params)
|
||||||
if sso_userdata
|
if sso_userdata
|
||||||
|
session[:persistent] = true
|
||||||
|
|
||||||
current_user_set(sso_userdata)
|
current_user_set(sso_userdata)
|
||||||
|
|
||||||
session[:persistent] = true
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
|
@ -161,8 +186,9 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
next if !userdata
|
next if !userdata
|
||||||
|
|
||||||
# set basic auth user to current user
|
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
|
user_device_log(userdata, 'basic_auth')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
|
@ -180,8 +206,8 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
next if !userdata
|
next if !userdata
|
||||||
|
|
||||||
# set token user to current user
|
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
|
user_device_log(userdata, 'token_auth')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
|
@ -216,9 +242,6 @@ class ApplicationController < ActionController::Base
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
# store current user id into the session
|
|
||||||
session[:user_id] = current_user.id
|
|
||||||
|
|
||||||
# return auth ok
|
# return auth ok
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,9 @@ class SessionsController < ApplicationController
|
||||||
# set session user
|
# set session user
|
||||||
current_user_set(user)
|
current_user_set(user)
|
||||||
|
|
||||||
|
# log device
|
||||||
|
return if !user_device_log(user, 'session')
|
||||||
|
|
||||||
# log new session
|
# log new session
|
||||||
user.activity_stream_log( 'session started', user.id, true )
|
user.activity_stream_log( 'session started', user.id, true )
|
||||||
|
|
||||||
|
@ -85,6 +88,9 @@ class SessionsController < ApplicationController
|
||||||
# subsequent requests
|
# subsequent requests
|
||||||
user = User.find( user_id )
|
user = User.find( user_id )
|
||||||
|
|
||||||
|
# log device
|
||||||
|
return if !user_device_log(user, 'session')
|
||||||
|
|
||||||
# auto population of default collections
|
# auto population of default collections
|
||||||
collections, assets = SessionHelper.default_collections(user)
|
collections, assets = SessionHelper.default_collections(user)
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,18 @@ class UserDevicesController < ApplicationController
|
||||||
before_action :authentication_check
|
before_action :authentication_check
|
||||||
|
|
||||||
def index
|
def index
|
||||||
devices = UserDevice.where(user_id: current_user.id).order('updated_at DESC')
|
devices = UserDevice.where(user_id: current_user.id).order('created_at DESC')
|
||||||
devices_full = []
|
devices_full = []
|
||||||
devices.each {|device|
|
devices.each {|device|
|
||||||
attributes = device.attributes
|
attributes = device.attributes
|
||||||
if device.location_details['city']
|
if device.location_details['city_name']
|
||||||
attributes['location'] += ", #{device.location_details['city']}"
|
attributes['location'] += ", #{device.location_details['city_name']}"
|
||||||
end
|
end
|
||||||
attributes.delete('created_at')
|
attributes.delete('created_at')
|
||||||
attributes.delete('device_details')
|
attributes.delete('device_details')
|
||||||
attributes.delete('location_details')
|
attributes.delete('location_details')
|
||||||
|
|
||||||
if session[:check_user_device_id] == device.id
|
if session[:user_device_id] == device.id
|
||||||
attributes['current'] = true
|
attributes['current'] = true
|
||||||
end
|
end
|
||||||
devices_full.push attributes
|
devices_full.push attributes
|
||||||
|
@ -24,6 +24,7 @@ class UserDevicesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
|
|
||||||
# find device
|
# find device
|
||||||
user_device = UserDevice.find_by(user_id: current_user.id, id: params[:id])
|
user_device = UserDevice.find_by(user_id: current_user.id, id: params[:id])
|
||||||
|
|
||||||
|
@ -31,8 +32,8 @@ class UserDevicesController < ApplicationController
|
||||||
if user_device
|
if user_device
|
||||||
SessionHelper.list.each {|session|
|
SessionHelper.list.each {|session|
|
||||||
next if !session.data['user_id']
|
next if !session.data['user_id']
|
||||||
next if !session.data['check_user_device_id']
|
next if !session.data['user_device_id']
|
||||||
next if session.data['check_user_device_id'] != user_device.id
|
next if session.data['user_device_id'] != user_device.id
|
||||||
SessionHelper.destroy( session.id )
|
SessionHelper.destroy( session.id )
|
||||||
}
|
}
|
||||||
user_device.destroy
|
user_device.destroy
|
||||||
|
|
|
@ -13,11 +13,37 @@ store device for user
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36',
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36',
|
||||||
'172.0.0.1',
|
'172.0.0.1',
|
||||||
user.id,
|
user.id,
|
||||||
|
'fingerprintABC123',
|
||||||
|
'session', # session|basic_auth|token_auth|sso
|
||||||
)
|
)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.add(user_agent, ip, user_id)
|
def self.add(user_agent, ip, user_id, fingerprint, type)
|
||||||
|
|
||||||
|
# get location info
|
||||||
|
location_details = Service::GeoIp.location(ip)
|
||||||
|
location = location_details['country_name']
|
||||||
|
|
||||||
|
# find device by fingerprint
|
||||||
|
if fingerprint
|
||||||
|
user_device = UserDevice.find_by(
|
||||||
|
user_id: user_id,
|
||||||
|
fingerprint: fingerprint,
|
||||||
|
location: location,
|
||||||
|
)
|
||||||
|
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||||
|
end
|
||||||
|
|
||||||
|
# for basic_auth|token_auth search for user agent
|
||||||
|
if type == 'basic_auth' || type == 'token_auth'
|
||||||
|
user_device = UserDevice.find_by(
|
||||||
|
user_id: user_id,
|
||||||
|
user_agent: user_agent,
|
||||||
|
location: location,
|
||||||
|
)
|
||||||
|
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||||
|
end
|
||||||
|
|
||||||
# get browser details
|
# get browser details
|
||||||
browser = Browser.new(:ua => user_agent, :accept_language => 'en-us')
|
browser = Browser.new(:ua => user_agent, :accept_language => 'en-us')
|
||||||
|
@ -37,21 +63,22 @@ store device for user
|
||||||
name += browser[:name]
|
name += browser[:name]
|
||||||
end
|
end
|
||||||
|
|
||||||
# get location info
|
# if not identified, use user agent
|
||||||
location = Service::GeoIp.location(ip)
|
if name == 'Other, Other'
|
||||||
country = location['country_name']
|
name = user_agent
|
||||||
|
browser[:name] = user_agent
|
||||||
|
end
|
||||||
|
|
||||||
# check if exists
|
# check if exists
|
||||||
exists = self.find_by(
|
user_device = self.find_by(
|
||||||
:user_id => user_id,
|
user_id: user_id,
|
||||||
os: browser[:plattform],
|
os: browser[:plattform],
|
||||||
browser: browser[:name],
|
browser: browser[:name],
|
||||||
location: country,
|
location: location,
|
||||||
)
|
)
|
||||||
|
|
||||||
if exists
|
if user_device
|
||||||
exists.touch
|
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||||
return exists
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# create new device
|
# create new device
|
||||||
|
@ -60,10 +87,45 @@ store device for user
|
||||||
name: name,
|
name: name,
|
||||||
os: browser[:plattform],
|
os: browser[:plattform],
|
||||||
browser: browser[:name],
|
browser: browser[:name],
|
||||||
location: country,
|
location: location,
|
||||||
device_details: browser,
|
device_details: browser,
|
||||||
location_details: location,
|
location_details: location_details,
|
||||||
|
user_agent: user_agent,
|
||||||
|
ip: ip,
|
||||||
|
fingerprint: fingerprint,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
log user device action
|
||||||
|
|
||||||
|
UserDevice.action(
|
||||||
|
user_device_id,
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36',
|
||||||
|
'172.0.0.1',
|
||||||
|
user.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def self.action(user_device_id, user_agent, ip, user_id)
|
||||||
|
user_device = UserDevice.find(user_device_id)
|
||||||
|
|
||||||
|
# update location if needed
|
||||||
|
if user_device.ip != ip
|
||||||
|
user_device.ip = ip
|
||||||
|
location_details = Service::GeoIp.location(ip)
|
||||||
|
user_device.location_details = location_details
|
||||||
|
|
||||||
|
location = location_details['country_name']
|
||||||
|
user_device.location = location
|
||||||
|
end
|
||||||
|
|
||||||
|
# update attributes
|
||||||
|
user_device.save
|
||||||
|
user_device
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ Zammad::Application.routes.draw do
|
||||||
|
|
||||||
# sessions
|
# sessions
|
||||||
match api_path + '/signin', to: 'sessions#create', via: :post
|
match api_path + '/signin', to: 'sessions#create', via: :post
|
||||||
match api_path + '/signshow', to: 'sessions#show', via: :get
|
match api_path + '/signshow', to: 'sessions#show', via: [:get, :post]
|
||||||
match api_path + '/signout', to: 'sessions#destroy', via: [:get, :delete]
|
match api_path + '/signout', to: 'sessions#destroy', via: [:get, :delete]
|
||||||
|
|
||||||
match api_path + '/sessions/switch/:id', to: 'sessions#switch_to_user', via: :get
|
match api_path + '/sessions/switch/:id', to: 'sessions#switch_to_user', via: :get
|
||||||
|
|
11
db/migrate/20150818000001_update_user_devices2.rb
Normal file
11
db/migrate/20150818000001_update_user_devices2.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class UpdateUserDevices2 < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :user_devices, :user_agent, :string, limit: 250, null: true
|
||||||
|
add_column :user_devices, :ip, :string, limit: 160, null: true
|
||||||
|
add_column :user_devices, :fingerprint, :string, limit: 160, null: true
|
||||||
|
add_index :user_devices, [:fingerprint]
|
||||||
|
add_index :user_devices, [:created_at]
|
||||||
|
UserDevice.reset_column_information
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue