anadea-identity 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +174 -0
  4. data/Rakefile +10 -0
  5. data/app/assets/images/facebook.png +0 -0
  6. data/app/assets/images/google_oauth2.png +0 -0
  7. data/app/assets/images/twitter.png +0 -0
  8. data/app/controllers/identity/base_controller.rb +5 -0
  9. data/app/controllers/identity/omniauth_callbacks_controller.rb +24 -0
  10. data/app/controllers/identity/users_controller.rb +58 -0
  11. data/app/models/identity/role.rb +16 -0
  12. data/app/models/identity/user.rb +47 -0
  13. data/app/views/devise/confirmations/new.html.erb +23 -0
  14. data/app/views/devise/mailer/confirmation_instructions.html.erb +6 -0
  15. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  16. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  17. data/app/views/devise/passwords/edit.html.erb +28 -0
  18. data/app/views/devise/passwords/new.html.erb +21 -0
  19. data/app/views/devise/registrations/edit.html.erb +34 -0
  20. data/app/views/devise/registrations/new.html.erb +28 -0
  21. data/app/views/devise/sessions/new.html.erb +31 -0
  22. data/app/views/devise/shared/_links.erb +25 -0
  23. data/app/views/devise/unlocks/new.html.erb +20 -0
  24. data/app/views/identity/users/edit.html.erb +70 -0
  25. data/app/views/identity/users/index.html.erb +55 -0
  26. data/config/locales/ca.yml +59 -0
  27. data/config/locales/de.yml +110 -0
  28. data/config/locales/en.yml +111 -0
  29. data/config/locales/es-AR.yml +51 -0
  30. data/config/locales/es-ES.yml +59 -0
  31. data/config/locales/es.yml +51 -0
  32. data/config/locales/fr.yml +51 -0
  33. data/config/locales/hu.yml +59 -0
  34. data/config/locales/it.yml +51 -0
  35. data/config/locales/nl.yml +59 -0
  36. data/config/locales/pl.yml +57 -0
  37. data/config/locales/pt-BR.yml +51 -0
  38. data/config/locales/ru.yml +56 -0
  39. data/config/locales/tr.yml +51 -0
  40. data/config/locales/zh-CN.yml +57 -0
  41. data/config/locales/zh-TW.yml +57 -0
  42. data/config/routes.rb +5 -0
  43. data/db/migrate/20150402142437_devise_create_identity_users.rb +42 -0
  44. data/db/migrate/20150402152859_rolify_create_identity_roles.rb +19 -0
  45. data/lib/anadea/identity.rb +1 -0
  46. data/lib/generators/identity/locales_generator.rb +8 -0
  47. data/lib/generators/identity/views_generator.rb +8 -0
  48. data/lib/identity.rb +50 -0
  49. data/lib/identity/admin/user.rb +89 -0
  50. data/lib/identity/devise_config.rb +31 -0
  51. data/lib/identity/engine.rb +21 -0
  52. data/lib/identity/version.rb +3 -0
  53. data/lib/identity/view_helper.rb +22 -0
  54. data/lib/tasks/whoami_tasks.rake +4 -0
  55. metadata +157 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b90fe456fe3459656452c7191052e3cf7b9e72bd
4
+ data.tar.gz: 7942ef52f965589850dc1e2d9b1be489aaf96fac
5
+ SHA512:
6
+ metadata.gz: 351d14c0435915e9e1324bbca2b9e53dbcda6764044e16b8138de4d24e2ca44bbf7525e343623104243ab18a0145b38028e2d62a0cd27a7718373bd413f46b8a
7
+ data.tar.gz: d072c2f56d804f4174305d38f4bc1bb3a412359b66a0d739e92742bd7f1a917a8f9d392e7d4c9c190eaa501c74cd81d60f3ed3ceeffe61e19571795de94ca112
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Anadea
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Identity
2
+
3
+ Аутентификация и авторизация для Rails приложения.
4
+
5
+ ## Установка
6
+
7
+ Добавьте строчку в Gemfile приложения:
8
+
9
+ ```ruby
10
+ gem 'anadea-identity'
11
+ ```
12
+
13
+ и запустите в консоли:
14
+
15
+ ```console
16
+ $ bundle
17
+ ```
18
+
19
+ Сгенерируйте миграции:
20
+
21
+ ```console
22
+ $ rake identity_engine:install:migrations
23
+ ```
24
+
25
+ проверьте их и запустите:
26
+
27
+ ```console
28
+ $ rake db:migrate
29
+ ```
30
+
31
+ ## Использование
32
+
33
+ ### Аутентификация
34
+
35
+ Проверьте маршруты: `rake routes`. Вы увидите набор маршрутов, подобных тем, что
36
+ даёт [Devise](https://github.com/plataformatec/devise). Собственно, Identity и
37
+ есть не слишком толстая обёртка поверх Devise.
38
+
39
+ У вас работает логин (через форму email/пароль), регистрация (через форму
40
+ email/пароль/подтверждение пароля), восстановление пароля и многое другое.
41
+
42
+ ### Модель User
43
+
44
+ Вызов `current_user` в контроллере вернёт `Identity::User`, соответствующий
45
+ таблице `identity_users`. Не нужно добавлять в эту модель методы и не нужно
46
+ добавлять в эту таблицу колонки, кроме тех, которые используются Devise или
47
+ Identity. Эту модель следует считать публичным интерфейсом, предоставляеым гемом.
48
+
49
+ Рекомендуется заводить модели типа `Profile` или `Account` которые будут
50
+ "принадлежать" (`belong_to :user, class_name: "Identity::User"`) этой модели
51
+ и ссылаться на неё с помощью внешнего ключа.
52
+
53
+ ### Авторизация
54
+
55
+ Модель `Identity::User` расширена ролями с помощью
56
+ [Rolify](https://github.com/RolifyCommunity/rolify). В частности, у вас есть
57
+ говорящие за себя методы:
58
+
59
+ ```ruby
60
+ user.add_role :manager
61
+ user.remove_role :manager
62
+ user.has_role? :manager
63
+
64
+ Identity::User.with_role :manager
65
+ ```
66
+
67
+ У вас есть многое другое – смотрите документацию Rolify.
68
+
69
+ Используйте эти методы в вызовах вашего авторизационного фреймворка, такого, как
70
+ [CanCanCan](https://github.com/CanCanCommunity/cancancan).
71
+
72
+ ### Админка
73
+
74
+ Чтобы получить админку по пользователям, подключите
75
+ [ActiveAdmin](https://github.com/activeadmin/activeadmin) и сгенерируйте
76
+ конфигурационный файл без генерации пользователей (`--skip-users`).
77
+
78
+ ### Конфигурация
79
+
80
+ Создайте руби-файл в `config/initializers` со следующим содержимым:
81
+
82
+ ```ruby
83
+ Identity.setup do |config|
84
+ config.devise_modules += [:confirmable]
85
+ # и много других конфигурационных опций
86
+ end
87
+ ```
88
+
89
+ #### Доступные опции
90
+
91
+ Вы всегда можете узнать полный список конфигурацинных опций и их значения по
92
+ умолчанию, ознакомившись [с исходным кодом](lib/identity.rb).
93
+
94
+ * `config.devise_modules` – модули Devise, которые вы используете. Например,
95
+ выключение `registerable` приведёт к невозможности зарегистрироваться, в том
96
+ числе, исчезнет соответствующая ссылка, а включение `confirmable` приведёт к
97
+ тому, что приложение станет требовать подтверждение адреса электронной почты,
98
+ при условии, что в таблице `identity_users` есть соответствующие колонки
99
+ (по умолчанию нет).
100
+
101
+ Вы можете как модифицировать этот массив, так и полностью его переопределить:
102
+
103
+ ```ruby
104
+ config.devise_modules += [:confirmable]
105
+ config.devise_modules = [:database_authenticatable, :omniauthable, ...]
106
+ ```
107
+
108
+ По умолчанию включены модули database_authenticatable, registerable,
109
+ recoverable, rememberable, trackable и validatable. Если включить хотя бы один
110
+ omniauth provider, автоматически подключится omniauthable. За подробным их
111
+ описанием обратитесь в документацию Devise.
112
+
113
+ * `config.layout` – макет (layout), используемый формами логина, регистрации и
114
+ прочего. По умолчанию используется главный макет вашего приложения –
115
+ `"application"`.
116
+
117
+ * `config.auth_routes` – если задать `false`, маршруты подключены не будут и вы
118
+ можете сами подключить их.
119
+
120
+ * `config.admin_role` – "главная" роль в приложении. Роль, которой можно
121
+ управлять из предлаемой гемом админки, и роль, которая по умолчанию является
122
+ допуском в эту админку.
123
+
124
+ Вы также можете использовать любые конфигурационные опции самого Devise.
125
+ Они будут переданы Devise в точности. Например:
126
+
127
+ ```ruby
128
+ config.parent_controller = "ApplicationController"
129
+ ```
130
+
131
+ За подробным списком того, что можно сконфигурировать в Devise, обратитесь к его
132
+ документации.
133
+
134
+ #### Сделанные кастомизации в конфигурации Devise.
135
+
136
+ Мы делаем небольшие изменения в конфигурации Devise по умолчанию. Вы можете это
137
+ увидеть в [исходном коде гема](lib/identity/devise_config.rb).
138
+
139
+ * `config.mailer_sender` – мы достаём это из переменной окружения MAIL_FROM.
140
+ * `config.sign_out_via` – GET и только GET. Это должно работать без джаваскрипта.
141
+ * `config.parent_controller` – мы не наследуемся от `ApplicationController` вашего
142
+ приложения. Devise предлагает для этого определять методы в
143
+ `ApplicationController`.Если вам нужно переопределить поведение аутентификационных
144
+ контроллеров, мы рекомендуем создать специальный базовый контроллер в
145
+ приложении и указать его в качестве `parent_controller`. Затем определять в
146
+ нём методы типа `after_sign_in_path_for`, как и предлагает Devise.
147
+
148
+ ### Логин через Facebook.
149
+
150
+ Для того, чтобы включить в приложении логин через Facebook нужно:
151
+
152
+ * подключить `gem 'omniauth-facebook'` в своем Gemfile.
153
+ * указать `config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']`
154
+ в `config/initializers/identity.rb`.
155
+ * создать приложение в Facebook можно с помощью [инструкции](https://getsocio.com/Help/How_to_set_up_Facebook_Application).
156
+
157
+ ### Логин через Twitter.
158
+
159
+ Для того, чтобы включить в приложении логин через Twitter нужно:
160
+
161
+ * подключить `gem 'omniauth-twitter'` в своем Gemfile.
162
+ * указать `config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']`
163
+ в `config/initializers/identity.rb`.
164
+ * создать приложение в Twitter можно [здесь](https://apps.twitter.com/).
165
+
166
+ ### Логин через Google.
167
+
168
+ Для того, чтобы включить в приложении логин через Google нужно:
169
+
170
+ * подключить `gem 'omniauth-google-oauth2'` в своем Gemfile.
171
+ * указать `config.omniauth :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET']`
172
+ в `config/initializers/identity.rb`.
173
+ * создать приложение в Google можно [здесь](https://console.developers.google.com/project).
174
+ * для создания приложения можно воспользоваться [инструкцией](https://developers.google.com/identity/protocols/OpenIDConnect#appsetup)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "bundler/setup"
3
+
4
+
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task default: :spec
8
+
9
+ APP_RAKEFILE = File.expand_path("../spec/rails_app/Rakefile", __FILE__)
10
+ load 'rails/tasks/engine.rake'
Binary file
Binary file
Binary file
@@ -0,0 +1,5 @@
1
+ module Identity
2
+ class BaseController < ActionController::Base
3
+ layout Identity.layout
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ module Identity
2
+ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
3
+ def facebook
4
+ omniauth_login('Facebook')
5
+ end
6
+
7
+ def twitter
8
+ omniauth_login('Twitter')
9
+ end
10
+
11
+ def google_oauth2
12
+ omniauth_login('Google')
13
+ end
14
+
15
+ private
16
+
17
+ def omniauth_login(title)
18
+ @user = Identity::User.from_omniauth!(request.env["omniauth.auth"])
19
+
20
+ set_flash_message(:notice, :success, :kind => title) if is_navigational_format?
21
+ sign_in_and_redirect @user, :event => :authentication
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ module Identity
2
+ class UsersController < ActionController::Base
3
+ layout Identity.admin_layout
4
+ before_action :ensure_allowed!
5
+ helper_method :resource, :resources
6
+
7
+ def index
8
+ @resources = User.search_and_order(params[:search], params[:page])
9
+ end
10
+
11
+ def show
12
+ redirect_to edit_identity_user_path(params[:id])
13
+ end
14
+
15
+ def edit
16
+ @resource = find_user
17
+ end
18
+
19
+ def update
20
+ @resource = find_user
21
+ if @resource.admin_update(user_params, current?(@resource))
22
+ @resource.skip_reconfirmation! if @resource.respond_to?(:skip_reconfirmation!)
23
+ @resource.save
24
+ redirect_to [Identity.admin_namespace, :users], notice: "#{@resource.email} updated."
25
+ else
26
+ render :edit
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :resource, :resources
33
+
34
+ def ensure_allowed!
35
+ unless Identity.admin_guard[current_user, self]
36
+ raise ActionController::RoutingError.new('Nothing here, move around')
37
+ end
38
+ end
39
+
40
+ def devise_mapping
41
+ request.env["devise.mapping"]
42
+ end
43
+
44
+ def current?(user)
45
+ user.id == current_user.id
46
+ end
47
+
48
+ def find_user
49
+ User.find params[:id]
50
+ end
51
+
52
+ def user_params
53
+ params.require(:identity_user).permit(
54
+ :email, :password, :password_confirmation, :active, Identity.admin_role
55
+ )
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,16 @@
1
+ require "rolify"
2
+
3
+ module Identity
4
+ class Role < ActiveRecord::Base
5
+ self.table_name = 'identity_roles'
6
+
7
+ has_and_belongs_to_many :users, :join_table => :identity_users_identity_roles
8
+ belongs_to :resource, :polymorphic => true
9
+
10
+ validates :resource_type,
11
+ :inclusion => { :in => Rolify.resource_types },
12
+ :allow_nil => true
13
+
14
+ scopify
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ require "devise"
2
+ require "rolify"
3
+ require "kaminari"
4
+
5
+ module Identity
6
+ class User < ActiveRecord::Base
7
+ self.table_name = 'identity_users'
8
+ devise *Identity.devise_modules
9
+
10
+ if Devise.omniauth_providers.any?
11
+ devise :omniauthable, omniauth_providers: Devise.omniauth_providers
12
+ end
13
+
14
+ rolify role_cname: 'Identity::Role'
15
+
16
+ def self.from_omniauth!(auth)
17
+ where(provider: auth.provider, uid: auth.uid).first_or_create! do |user|
18
+ user.email = auth.provider == "twitter" ? "#{auth.info.nickname}_email@example.com" : auth.info.email
19
+ user.password = Devise.friendly_token[0,20]
20
+ end
21
+ end
22
+
23
+ define_singleton_method Identity.admins_method do
24
+ with_role(Identity.admin_role)
25
+ end
26
+
27
+ def self.find_first_by_auth_conditions(tainted_conditions, opts={active: true})
28
+ super
29
+ end
30
+
31
+ def self.active
32
+ result = where(active: true)
33
+ result = result.where.not(confirmed_at: nil) if devise_modules.include?(:confirmable)
34
+ result
35
+ end
36
+
37
+ def role_names
38
+ roles.pluck(:name).sort.join(', ')
39
+ end
40
+
41
+ define_method Identity.admin_role do
42
+ has_role?(Identity.admin_role)
43
+ end
44
+ alias_method Identity.admin_predicate, Identity.admin_role
45
+
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ <div class="row">
2
+ <div class="col-sm-6">
3
+
4
+ <%= bootstrap_devise_error_messages! %>
5
+ <div class="panel panel-default">
6
+ <div class="panel-heading">
7
+ <h4><%= t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions') %></h4>
8
+ </div>
9
+ <div class="panel-body">
10
+ <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, role: "form" }) do |f| %>
11
+ <div class="form-group">
12
+ <%= f.label :email %>
13
+ <%= f.email_field :email, autofocus: true, class: "form-control" %>
14
+ </div>
15
+
16
+ <%= f.submit t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions'), class: "btn btn-primary" %>
17
+ <% end %>
18
+ </div>
19
+ </div>
20
+
21
+ <%= render "devise/shared/links" %>
22
+ </div>
23
+ </div>
@@ -0,0 +1,6 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Welcome #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.instruction', :default => "You can confirm your account email through the link below:") %></p>
4
+
5
+ <p><%= link_to t('.action', :default => "Confirm my account"),
6
+ confirmation_url(@resource, :confirmation_token => @token, locale: I18n.locale) %></p>
@@ -0,0 +1,8 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.instruction', :default => "Someone has requested a link to change your password, and you can do this through the link below.") %></p>
4
+
5
+ <p><%= link_to t('.action', :default => "Change my password"), edit_password_url(@resource, :reset_password_token => @token, locale: I18n.locale) %></p>
6
+
7
+ <p><%= t('.instruction_2', :default => "If you didn't request this, please ignore this email.") %></p>
8
+ <p><%= t('.instruction_3', :default => "Your password won't change until you access the link above and create a new one.") %></p>
@@ -0,0 +1,7 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.message', :default => "Your account has been locked due to an excessive amount of unsuccessful sign in attempts.") %></p>
4
+
5
+ <p><%= t('.instruction', :default => "Click the link below to unlock your account:") %></p>
6
+
7
+ <p><%= link_to t('.action', :default => "Unlock my account"), unlock_url(@resource, :unlock_token => @resource.unlock_token, locale: I18n.locale) %></p>
@@ -0,0 +1,28 @@
1
+ <div class="row">
2
+ <div class="col-sm-6">
3
+ <%= bootstrap_devise_error_messages! %>
4
+ <div class="panel panel-default">
5
+ <div class="panel-heading">
6
+ <h4><%= t('.change_your_password', :default => 'Change your password') %></h4>
7
+ </div>
8
+ <div class="panel-body">
9
+ <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, role: "form" }) do |f| %>
10
+ <%= f.hidden_field :reset_password_token %>
11
+
12
+ <div class="form-group">
13
+ <%= f.label :password, t('.new_password', :default => 'New password') %>
14
+ <%= f.password_field :password, autofocus: true, class: "form-control" %>
15
+ </div>
16
+
17
+ <div class="form-group">
18
+ <%= f.label :password_confirmation, t('.confirm_new_password', :default => 'Confirm new password') %>
19
+ <%= f.password_field :password_confirmation, class: "form-control" %>
20
+ </div>
21
+
22
+ <%= f.submit t('.change_my_password', :default => 'Change my password'), class: "btn btn-primary" %>
23
+ <% end %>
24
+ </div>
25
+ </div>
26
+ <%= render "devise/shared/links" %>
27
+ </div>
28
+ </div>