Martin Edenhofer 9 лет назад
Родитель
Сommit
72bb0eb067

+ 5 - 1
app/assets/javascripts/app/lib/app_post/auth.js.coffee

@@ -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, ...)

+ 41 - 18
app/controllers/application_controller.rb

@@ -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
-  def check_user_device
+  # user device recent action update
+  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
-    session[:check_user_device_at] = Time.zone.now
+    return if session[:user_device_update_at] && session[:user_device_update_at] > Time.zone.now - 5.minutes
+    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]
-      session[:check_user_device_id] = user_device.id
+  end
+
+  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

+ 6 - 0
app/controllers/sessions_controller.rb

@@ -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)
 
 

+ 7 - 6
app/controllers/user_devices_controller.rb

@@ -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']
-        attributes['location'] += ", #{device.location_details['city']}"
+      if device.location_details['city_name']
+        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['check_user_device_id'] != user_device.id
+        next if !session.data['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

+ 74 - 12
app/models/user_device.rb

@@ -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
-    location = Service::GeoIp.location(ip)
-    country = location['country_name']
+    # if not identified, use user agent
+    if name == 'Other, Other'
+      name = user_agent
+      browser[:name] = user_agent
+    end
 
 
     # check if exists
     # check if exists
-    exists = self.find_by(
-      :user_id => user_id,
+    user_device = self.find_by(
+      user_id: user_id,
       os: browser[:plattform],
       os: browser[:plattform],
       browser: browser[:name],
       browser: browser[:name],
-      location: country,
+      location: location,
     )
     )
 
 
-    if exists
-      exists.touch
-      return exists
+    if user_device
+      return action(user_device.id, user_agent, ip, user_id) if user_device
     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

+ 1 - 1
config/routes/auth.rb

@@ -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 - 0
db/migrate/20150818000001_update_user_devices2.rb

@@ -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