devise_userbin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a9d187a96d8b7b0e8a5b7f8b65b4858d2ce695f6
4
+ data.tar.gz: 8f0f15fcc67bffedc6f27d122c1d11b28f1a54ce
5
+ SHA512:
6
+ metadata.gz: 0dda852d3e5db62bac675a4de00e92b7f3a6a2c9b64864261225104e4b790b8d716a09856942b2e408f73778c530b0b1231a1bd27b88f7fc96579f1bb64827bd
7
+ data.tar.gz: 88dcd33100f805e93197169ddff36bf72eac617b128a5e75efe3373b693c1da60c3d9def12d8e8dee7afc22edf7ec500ca6e388a3e3f84a6e2d61c705f45558c
@@ -0,0 +1,37 @@
1
+ class Devise::DeviseUserbinController < DeviseController
2
+ include Devise::Controllers::Helpers
3
+
4
+ def show
5
+ self.resource = resource_class.new
6
+ end
7
+
8
+ def update
9
+ render :show and return if params[:code].nil?
10
+
11
+ Devise.mappings.keys.flatten.any? do |scope|
12
+ begin
13
+ session["#{scope}_userbin"] =
14
+ Userbin.verify_code(session["#{scope}_userbin"], params[:code])
15
+ set_flash_message :notice, :success
16
+ redirect_to after_sign_in_path_for(scope)
17
+ rescue Userbin::UserUnauthorizedError => error
18
+ set_flash_message :alert, :failed
19
+ self.resource = resource_class.new
20
+ respond_with_navigational(resource_name) { render :show }
21
+ rescue Userbin::Forbidden => error
22
+ sign_out_with_message(:no_retries_remaining, :alert)
23
+ rescue Userbin::Error => error
24
+ sign_out_with_message(:alert, :alert)
25
+ end
26
+ end
27
+ end
28
+
29
+ protected
30
+
31
+ def sign_out_with_message(message, kind = :notice)
32
+ signed_out = sign_out(resource_name)
33
+ set_flash_message kind, message if signed_out
34
+ redirect_to after_sign_out_path_for(resource_name)
35
+ end
36
+
37
+ end
@@ -0,0 +1,8 @@
1
+ class Devise::SecuritySettingsController < DeviseController
2
+ include Devise::Controllers::Helpers
3
+
4
+ def show
5
+ session_token = session["#{resource_name}_userbin"]
6
+ redirect_to Userbin.security_page_url(session_token)
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Devise
2
+ class TwoFactorAuthenticationController < DeviseUserbinController; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Devise
2
+ class TwoFactorRecoveryController < DeviseUserbinController; end
3
+ end
@@ -0,0 +1,15 @@
1
+ <h2><%= t "devise.two_factor_authentication.show.header" %></h2>
2
+
3
+ <p><%= t "devise.two_factor_authentication.show.instructions" %></p>
4
+
5
+ <%= form_tag([resource_name, :two_factor_authentication], :method => :put) do %>
6
+ <%= devise_error_messages! %>
7
+ <p><%= label_tag :code, t("devise.two_factor_authentication.show.code_label") %><br />
8
+ <%= text_field_tag :code %></p>
9
+ <p><%= submit_tag t("devise.two_factor_authentication.show.submit_button") %></p>
10
+ <% end -%>
11
+
12
+ <p><%= t "devise.two_factor_authentication.show.recovery_message" %><br />
13
+ <%= link_to t("devise.two_factor_authentication.show.recovery_action"), [resource_name, :two_factor_recovery] %></p>
14
+
15
+ <%= link_to "Sign out", destroy_session_path(resource_name), :method => Devise.sign_out_via %>
@@ -0,0 +1,10 @@
1
+ <h2><%= t "devise.two_factor_recovery.show.header" %></h2>
2
+
3
+ <%= form_tag([resource_name, :two_factor_recovery], :method => :put) do %>
4
+ <%= devise_error_messages! %>
5
+ <p><%= label_tag :code, t("devise.two_factor_recovery.show.code_label")%><br />
6
+ <%= text_field_tag :code %></p>
7
+ <p><%= submit_tag t("devise.two_factor_recovery.show.submit_button") %></p>
8
+ <% end -%>
9
+
10
+ <p><%= t "devise.two_factor_recovery.show.message" %></p>
@@ -0,0 +1,31 @@
1
+ require 'active_support/concern'
2
+ require 'devise'
3
+ require 'devise_userbin/hooks'
4
+ require 'devise_userbin/routes'
5
+ require 'devise_userbin/hooks'
6
+ require 'devise_userbin/import'
7
+ require 'userbin'
8
+
9
+ if defined?(Rails::Railtie)
10
+ require 'devise_userbin/railtie'
11
+ Rails::Engine
12
+ end
13
+
14
+ module Devise
15
+ mattr_accessor :userbin_api_secret
16
+ @@userbin_api_secret = ''
17
+ end
18
+
19
+ module DeviseUserbin
20
+ module Controllers
21
+ autoload :Helpers, 'devise_userbin/controllers/helpers'
22
+ end
23
+ module Views
24
+ autoload :Helpers, 'devise_userbin/controllers/view_helpers'
25
+ end
26
+ end
27
+
28
+ Devise.add_module(:userbin,
29
+ :controller => :two_factor_authentication,
30
+ :route => :userbin,
31
+ :model => 'devise_userbin/model')
@@ -0,0 +1,41 @@
1
+ module DeviseUserbin
2
+ module Controllers
3
+ module Helpers
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_filter :handle_two_factor_authentication
8
+ end
9
+
10
+ private
11
+
12
+ def handle_two_factor_authentication
13
+ unless devise_controller?
14
+ Devise.mappings.keys.flatten.any? do |scope|
15
+ if signed_in?(scope)
16
+ if Userbin.two_factor_authenticate!(session["#{scope}_userbin"])
17
+ handle_required_two_factor_authentication(scope)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def handle_required_two_factor_authentication(scope)
25
+ if request.format.present? and request.format.html?
26
+ session["#{scope}_return_to"] = request.path if request.get?
27
+ redirect_to two_factor_authentication_path_for(scope)
28
+ else
29
+ render nothing: true, status: :unauthorized
30
+ end
31
+ end
32
+
33
+ def two_factor_authentication_path_for(resource_or_scope = nil)
34
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
35
+ change_path = "#{scope}_two_factor_authentication_path"
36
+ send(change_path)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ module DeviseUserbin
2
+ module Views
3
+ module Helpers
4
+
5
+ def security_page_url(opts = {})
6
+ scope = opts[:scope] || ::Devise.default_scope
7
+ session_token = session["#{scope}_userbin"]
8
+ Userbin.security_page_url(session_token)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # Everytime current_<scope> is prepared
2
+ #
3
+ Warden::Manager.after_set_user :only => :fetch do |record, warden, opts|
4
+ scope = opts[:scope]
5
+
6
+ begin
7
+ session_token = warden.request.session["#{scope}_userbin"]
8
+
9
+ session_token =
10
+ Userbin.authenticate(session_token, record._userbin_id, {
11
+ properties: {
12
+ email: record.email
13
+ },
14
+ context: {
15
+ ip: warden.request.ip,
16
+ user_agent: warden.request.user_agent
17
+ }
18
+ })
19
+
20
+ warden.request.session["#{scope}_userbin"] = session_token
21
+
22
+ rescue Userbin::Error => error
23
+ warden.logout(scope)
24
+ throw :warden, :scope => scope, :message => :timeout
25
+ end
26
+
27
+ end
28
+
29
+ Warden::Manager.before_logout do |record, warden, opts|
30
+ begin
31
+ session_token = warden.request.session.delete("#{opts[:scope]}_userbin")
32
+ Userbin.deauthenticate(session_token)
33
+ rescue Userbin::Error; end
34
+ end
@@ -0,0 +1,85 @@
1
+ module DeviseUserbin
2
+ class ImportError < Exception; end
3
+
4
+ class Import
5
+ attr_reader :resource_class, :batch_size
6
+
7
+ def initialize(options = {})
8
+ begin
9
+ @resource_class = eval(options[:resource_class])
10
+ rescue NameError
11
+ raise ImportError, "No such class: #{options[:resource_class]}"
12
+ end
13
+
14
+ unless supported_orm?
15
+ raise ImportError, "Only ActiveRecord and Mongoid models are supported"
16
+ end
17
+
18
+ unless Userbin.config.api_secret.present?
19
+ raise ImportError, "Please add an Userbin API secret to your devise.rb"
20
+ end
21
+
22
+ @batch_size = [(options[:batch_size] || 100), 100].min
23
+ end
24
+
25
+ def self.run(*args)
26
+ new(*args).run
27
+ end
28
+
29
+ def run
30
+ batches do |batch, resources|
31
+ begin
32
+ users = Userbin::User.import(users: batch)
33
+ rescue Userbin::Error => error
34
+ raise ImportError, error.message
35
+ end
36
+
37
+ users.zip(resources).each do |user, resource|
38
+ resource.userbin_id = user.id
39
+ resource.save(validate: false)
40
+ end
41
+ end
42
+ end
43
+
44
+ def batches
45
+ if active_record?
46
+ resource_class.where("userbin_id IS NULL").find_in_batches(:batch_size => batch_size) do |resources|
47
+ resources_for_wire = map_resources_to_userbin_format(resources)
48
+ yield(resources_for_wire, resources) unless resources.count.zero?
49
+ end
50
+ elsif mongoid?
51
+ 0.step(resource_class.where(:userbin_id => nil).count, batch_size) do |offset|
52
+ resources_for_wire = map_resources_to_userbin_format(resource_class.limit(batch_size).skip(offset))
53
+ yield(resources_for_wire, resources) unless resources.count.zero?
54
+ end
55
+ end
56
+ end
57
+
58
+ def map_resources_to_userbin_format(resources)
59
+ resources.map do |resource|
60
+ format = {}
61
+ format[:email] = resource.email unless resource.email.blank?
62
+ format[:id] = resource._userbin_id
63
+ format[:created_at] = resource.created_at if resource.respond_to? :created_at
64
+ format
65
+ end.compact
66
+ end
67
+
68
+ def prepare_batch(batch)
69
+ { :users => batch }.to_json
70
+ end
71
+
72
+ def active_record?
73
+ (defined?(ActiveRecord::Base) && (resource_class < ActiveRecord::Base))
74
+ end
75
+
76
+ def mongoid?
77
+ (defined?(Mongoid::Document) && (resource_class < Mongoid::Document))
78
+ end
79
+
80
+ def supported_orm?
81
+ active_record? || mongoid?
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,53 @@
1
+ module Devise
2
+ module Models
3
+ module Userbin
4
+ extend ActiveSupport::Concern
5
+
6
+ ::Userbin.api_secret = Devise.userbin_api_secret
7
+
8
+ included do
9
+ before_destroy :destroy_userbin_user
10
+
11
+ def destroy_userbin_user
12
+ userbin_user_block do
13
+ ::Userbin::User.destroy_existing(id)
14
+ end
15
+ end
16
+
17
+ def userbin_user_block
18
+ begin
19
+ yield
20
+ rescue ::Userbin::Error => error
21
+ self.errors[:base] << error.to_s
22
+ false
23
+ end
24
+ end
25
+
26
+ # Override this in your Devise model to use a custom identifier
27
+ # for the Userbin API:s
28
+ def userbin_id
29
+ id
30
+ end
31
+
32
+ # Since the identifier will be used in API routes, it needs to be
33
+ # URI encoded
34
+ def _userbin_id
35
+ URI.encode(userbin_id.to_s)
36
+ end
37
+ end
38
+
39
+ # Overwrites valid_for_authentication? from Devise::Models::Authenticatable
40
+ # for verifying whether a user is allowed to sign in or not.
41
+ def valid_for_authentication?
42
+ return super unless persisted?
43
+
44
+ if super
45
+ true
46
+ else
47
+ # TODO: track unsuccessful login
48
+ false
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,10 @@
1
+ module DeviseUserbin
2
+ class Engine < ::Rails::Engine
3
+ ActiveSupport.on_load(:action_controller) do
4
+ include DeviseUserbin::Controllers::Helpers
5
+ end
6
+ ActiveSupport.on_load(:action_view) do
7
+ include DeviseUserbin::Views::Helpers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ protected
4
+
5
+ def devise_userbin(mapping, controllers)
6
+ resource :two_factor_authentication, :only => [:show, :update], :path => mapping.path_names[:two_factor_authentication], :controller => controllers[:two_factor_authentication]
7
+
8
+ resource :two_factor_recovery, :only => [:show, :update], :path => mapping.path_names[:two_factor_recovery], :controller => controllers[:two_factor_recovery]
9
+
10
+ resource :security_settings, :only => [:show], :path => mapping.path_names[:security_settings], :controller => controllers[:security_settings]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module DeviseUserbin
2
+ VERSION = "0.1.0".freeze
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class DeviseUserbinGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def copy_devise_userbin_migration
9
+ migration_template "migration.rb", "db/migrate/add_userbin_to_#{table_name}.rb"
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class AddUserbinTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def up
3
+ change_table :<%= table_name %> do |t|
4
+ t.string :userbin_id
5
+ end
6
+
7
+ add_index :<%= table_name %>, :userbin_id, :unique => true
8
+ end
9
+
10
+ def down
11
+ remove_column :<%= table_name %>, :userbin_id
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module DeviseUserbin
2
+ module Generators
3
+ class DeviseUserbinGenerator < Rails::Generators::NamedBase
4
+ namespace "devise_userbin"
5
+
6
+ desc "Add :userbin directive in the given model. Also generate migration for ActiveRecord"
7
+
8
+ def inject_devise_userbin_content
9
+ path = File.join("app", "models", "#{file_path}.rb")
10
+ if File.exists?(path)
11
+ inject_into_file(path, "userbin, :", :after => "devise :")
12
+ end
13
+ end
14
+
15
+ hook_for :orm
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module DeviseUserbin
2
+ module Generators
3
+ class ImportGenerator < Rails::Generators::NamedBase
4
+ desc "Import users to Userbin"
5
+
6
+ def import_users_to_userbin
7
+ Import.run(resource_class: class_name)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ module DeviseUserbin
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../templates", __FILE__)
5
+ desc "Add DeviseUserbin config variables to the Devise initializer"
6
+ argument :api_secret, :desc => "Your Userbin API secret, which can be found on your Userbin dashboard."
7
+
8
+ def add_config_options_to_initializer
9
+ devise_initializer_path = "config/initializers/devise.rb"
10
+ if File.exist?(devise_initializer_path)
11
+ old_content = File.read(devise_initializer_path)
12
+
13
+ if old_content.match(Regexp.new(/^\s*# ==> Configuration for :userbin\n/))
14
+ false
15
+ else
16
+ inject_into_file(devise_initializer_path, :before => " # ==> Mailer Configuration\n") do
17
+ <<-CONTENT
18
+ # ==> Configuration for :userbin
19
+ config.userbin_api_secret = '#{api_secret}'
20
+
21
+ CONTENT
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def copy_locale
28
+ copy_file "../../../config/locales/en.yml", "config/locales/devise_userbin.en.yml"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ require 'generators/devise/views_generator'
2
+
3
+ module DeviseUserbin
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ desc 'Copies all DeviseUserbin views to your application.'
7
+
8
+ argument :scope, :required => false, :default => nil,
9
+ :desc => "The scope to copy views to"
10
+
11
+ include ::Devise::Generators::ViewPathTemplates
12
+ source_root File.expand_path("../../../../app/views/devise", __FILE__)
13
+ def copy_views
14
+ view_directory :two_factor_authentication
15
+ view_directory :two_factor_recovery
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ require 'generators/devise/orm_helpers'
2
+
3
+ module Mongoid
4
+ module Generators
5
+ class DeviseUserbinGenerator < Rails::Generators::NamedBase
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_userbin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Johan Brissmyr
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: devise
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: userbin
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '3.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '3.1'
83
+ description: Devise extension for Userbin. Secure your application with multi-factor
84
+ authentication, user activity monitoring, and real-time threat protection.
85
+ email: johan@userbin.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - app/controllers/devise/devise_userbin_controller.rb
91
+ - app/controllers/devise/security_settings_controller.rb
92
+ - app/controllers/devise/two_factor_authentication_controller.rb
93
+ - app/controllers/devise/two_factor_recovery_controller.rb
94
+ - app/views/devise/two_factor_authentication/show.html.erb
95
+ - app/views/devise/two_factor_recovery/show.html.erb
96
+ - lib/devise_userbin.rb
97
+ - lib/devise_userbin/controllers/helpers.rb
98
+ - lib/devise_userbin/controllers/view_helpers.rb
99
+ - lib/devise_userbin/hooks.rb
100
+ - lib/devise_userbin/import.rb
101
+ - lib/devise_userbin/model.rb
102
+ - lib/devise_userbin/railtie.rb
103
+ - lib/devise_userbin/routes.rb
104
+ - lib/devise_userbin/version.rb
105
+ - lib/generators/active_record/devise_userbin_generator.rb
106
+ - lib/generators/active_record/templates/migration.rb
107
+ - lib/generators/devise_userbin/devise_userbin_generator.rb
108
+ - lib/generators/devise_userbin/import_generator.rb
109
+ - lib/generators/devise_userbin/install_generator.rb
110
+ - lib/generators/devise_userbin/views_generator.rb
111
+ - lib/generators/mongoid/devise_userbin_generator.rb
112
+ homepage: https://github.com/userbin/devise_userbin
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.2.2
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Devise extension for Userbin
136
+ test_files: []