lam_auth 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ Аутентификация для спецпроектов [Lookatme](http://www.lookatme.ru) и [The Village](http://www.the-village.ru)
2
+
3
+ ## Установка
4
+
5
+ gem install lam_auth
6
+
7
+ После установки/добавления в Gemfile:
8
+
9
+ rails generate lam_auth
10
+
11
+ после этого нужно добавить настройки приложения в `config/lam_auth.yml`.
12
+
13
+ Для спецпроектов The Village необходимо в `config/lam_auth.yml` добавить:
14
+
15
+ site: village
16
+
17
+ ## Подключение панели
18
+
19
+ Подключить js-код в head:
20
+
21
+ <%= lam_auth_include_tag %>
22
+
23
+ Затем:
24
+
25
+ <div id="lam-root"></div>
26
+ <%= lam_auth_init_tag %>
27
+
28
+ В случае с The Village дефолтный `id` панели `village-root`.
29
+
30
+ ## Модель
31
+
32
+ При аутентификации Lookatme/The Village возвращают данные пользователя в следующем виде:
33
+
34
+ ```ruby
35
+ {
36
+ "gender" => "male",
37
+ "last_name" => "Маковский",
38
+ "city" => "Москва",
39
+ "email" => "robotector@gmail.com",
40
+ "userpic" => {
41
+ "medium" => "http://assets3.lookatme.ru/assets/user-userpic/20/38/3/user-userpic-medium.jpg",
42
+ "big" => "http://assets0.lookatme.ru/assets/user-userpic/20/38/3/user-userpic-big.jpg",
43
+ "icon" => "http://assets3.lookatme.ru/assets/user-userpic/20/38/3/user-userpic-icon.jpg",
44
+ "thumb" => "http://assets0.lookatme.ru/assets/user-userpic/20/38/3/user-userpic-thumb.jpg"
45
+ },
46
+ "first_name" => "Шляпа",
47
+ "birthday" => "13-12-1979",
48
+ "login" => "macovsky"}
49
+ ```
50
+
51
+ В модели пользователя нужно подключить `LamAuth`:
52
+
53
+ ```ruby
54
+ class User < ActiveRecord::Base
55
+ include LamAuth::Model
56
+ end
57
+ ```
58
+
59
+ Теперь класс `User` имеет метод `create_or_update_by_auth_data`, принимающий данные пользователя:
60
+
61
+ ```ruby
62
+ def self.create_or_update_by_auth_data(data)
63
+ user = find_or_initialize_by_login(data['login'])
64
+ user.update_attributes! data.slice(*%w{email first_name last_name}).merge(
65
+ 'userpic' => data['userpic']['icon'],
66
+ 'profile' => data.except(*%w{login email first_name last_name userpic})
67
+ )
68
+ user
69
+ end
70
+ ```
71
+
72
+ Предполагает наличие соответствующих атрибутов и сериализацию атрибута `profile`:
73
+
74
+ ```ruby
75
+ class CreateUsers < ActiveRecord::Migration
76
+ def self.up
77
+ create_table(:users) do |t|
78
+ t.string :login, :null => false
79
+ t.string :email, :null => false
80
+ t.string :first_name
81
+ t.string :last_name
82
+ t.string :userpic
83
+ t.text :profile
84
+ t.timestamps
85
+ end
86
+
87
+ add_index :users, :login
88
+ add_index :users, :email
89
+ end
90
+
91
+ def self.down
92
+ drop_table :users
93
+ end
94
+ end
95
+ ```
96
+
97
+ Метод переопределяется для конкретных случаев.
98
+
99
+ ## Контроллер
100
+
101
+ Для подключения самого механизма аутентификации можно, например, использовать [RailsWarden](http://github.com/hassox/rails_warden):
102
+
103
+ ```ruby
104
+ # config/initializers/warden.rb
105
+ Rails.configuration.middleware.use RailsWarden::Manager do |manager|
106
+ manager.default_strategies :cookie_with_access_token
107
+ manager.failure_app = SessionsController
108
+ end
109
+
110
+ Warden::Strategies.add(:cookie_with_access_token) do
111
+ def authenticate!
112
+ access_token = LamAuth.access_token_from_cookie(request.cookies[LamAuth.cookie_id])
113
+ access_token ? success!(User.find_by_access_token(access_token)) : fail
114
+ end
115
+ end
116
+
117
+ # app/controllers/application_controller.rb
118
+ class ApplicationController < ActionController::Base
119
+ protect_from_forgery
120
+
121
+ before_filter :authenticate
122
+ before_filter :logout_if_no_cookie_available, :if => :logged_in?
123
+
124
+ private
125
+
126
+ def logout_if_no_cookie_available
127
+ logout if !LamAuth.access_token_from_cookie(cookies[LamAuth.cookie_id])
128
+ end
129
+ end
130
+
131
+ # app/controllers/sessions_controller.rb
132
+ # Контроллер, который в #unauthenticated рендерит сообщение о необходимости авторизоваться/зарегистрироваться.
133
+ class SessionsController < ApplicationController
134
+ def unauthenticated
135
+ end
136
+ end
137
+ ```
138
+
139
+ На страницах, где аутентификация обязательна, можно использовать соответствующий хелпер `RailsWarden`:
140
+
141
+ ```ruby
142
+ before_filter :authenticate!
143
+ ```
@@ -1,16 +1,10 @@
1
1
  module LamAuth
2
2
  module Generators
3
- class LamAuthGenerator < Rails::Generators::NamedBase
3
+ class LamAuthGenerator < Rails::Generators::Base
4
4
  namespace "lam_auth"
5
5
  source_root File.expand_path("../../templates", __FILE__)
6
6
 
7
- desc "Installs lam_auth: generates a model plus includes required extensions."
8
-
9
- hook_for :orm
10
-
11
- def inject_controller_content
12
- inject_into_class(File.join("app", "controllers", "application_controller.rb"), 'ApplicationController', " lam_auth_for :#{file_path}\n")
13
- end
7
+ desc "Installs lam_auth"
14
8
 
15
9
  def copy_xd_receiver
16
10
  copy_file 'xd_receiver.html', 'public/xd_receiver.html'
@@ -4,12 +4,10 @@
4
4
  <meta charset="UTF-8">
5
5
  <title></title>
6
6
  <script type="text/javascript">
7
- window.opener.LAM.successLogin(window.location.hash.substring(1));
7
+ (window.opener.LAM || window.opener.VLG).successLogin(window.location.hash.substring(1));
8
8
  </script>
9
9
  </head>
10
10
  <body><p>Loading...</p>
11
11
  </body>
12
12
  </html>
13
13
 
14
-
15
-
@@ -1,18 +1,18 @@
1
1
  module LamAuth
2
2
  module Helpers
3
3
  def lam_auth_include_tag
4
- javascript_include_tag(LamAuth.url + "/api/js/LAM.Login.js")
4
+ javascript_include_tag(LamAuth.config['api_url'])
5
5
  end
6
6
 
7
7
  def lam_auth_init_tag(options = {})
8
8
  options.reverse_merge!(
9
- :app_id => LamAuth.config['app_id'],
10
- :panel_node_id => 'lam-root',
9
+ :app_id => LamAuth.app['app_id'],
10
+ :panel_node_id => "#{LamAuth.config['prefix']}-root",
11
11
  :fixed => false
12
12
  )
13
- options.reverse_merge!(:xd_receiver_url => LamAuth.config['return_url']) if LamAuth.config['return_url']
13
+ options.reverse_merge!(:xd_receiver_url => LamAuth.app['return_url']) if LamAuth.app['return_url']
14
14
 
15
- javascript_tag("LAM.init({#{options.map{|k, v| "#{k.to_s.camelize(:lower)}: #{v.inspect}"}.join(",\n")}});")
15
+ javascript_tag("#{LamAuth.config['api']}.init({#{options.map{|k, v| "#{k.to_s.camelize(:lower)}: #{v.inspect}"}.join(",\n")}});")
16
16
  end
17
17
  end
18
18
  end
@@ -3,19 +3,16 @@ require 'net/https'
3
3
  module LamAuth
4
4
  module Model
5
5
  def self.included(base)
6
- base.validates_presence_of :login, :email
7
- base.validates_uniqueness_of :login, :email
8
- base.serialize :profile
9
- base.send(:extend, ClassMethods)
6
+ base.extend ClassMethods
10
7
  end
11
-
8
+
12
9
  module ClassMethods
13
10
  def find_by_access_token(access_token)
14
11
  Rails.logger.info("Trying to authorize a token #{access_token.inspect} ")
15
12
 
16
- lam_uri = LamAuth.uri
17
- http = Net::HTTP.new(lam_uri.host, lam_uri.port)
18
- response = http.get("#{lam_uri.path}/users/me", {'Authorization' => "Token token=\"#{access_token}\""})
13
+ uri = URI.parse(LamAuth.url)
14
+ http = Net::HTTP.new(uri.host, uri.port)
15
+ response = http.get("#{uri.path}/users/me", {'Authorization' => "Token token=\"#{access_token}\""})
19
16
  if response.code == "200"
20
17
  data = ActiveSupport::JSON.decode(response.body)
21
18
  Rails.logger.info("...success: #{data.inspect}")
@@ -24,31 +21,16 @@ module LamAuth
24
21
  Rails.logger.info("...failed with #{response.code}!")
25
22
  nil
26
23
  end
27
- rescue Net::ProtoRetriableError => detail
28
- Rails.logger.info("...failed!")
29
- Rails.logger.info(detail)
30
- nil
31
24
  end
32
25
 
33
26
  def create_or_update_by_auth_data(data)
34
27
  user = find_or_initialize_by_login(data['login'])
35
- user.update_attributes data.slice(*%w{email first_name last_name}).merge(
28
+ user.update_attributes! data.slice(*%w{email first_name last_name}).merge(
36
29
  'userpic' => data['userpic']['icon'],
37
30
  'profile' => data.except(*%w{login email first_name last_name userpic})
38
31
  )
39
32
  user
40
33
  end
41
34
  end
42
-
43
- def name
44
- [first_name, last_name].select(&:present?).join(" ")
45
- end
46
-
47
- def userpic(version = :icon)
48
- pic = read_attribute(:userpic)
49
- return nil if pic.blank?
50
- pic.sub(/user-userpic-\w+/, "user-userpic-#{version}")
51
- end
52
-
53
35
  end
54
36
  end
@@ -1,3 +1,3 @@
1
1
  module LamAuth
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
data/lib/lam_auth.rb CHANGED
@@ -1,39 +1,48 @@
1
1
  require 'rack/utils'
2
2
  require 'digest/md5'
3
3
 
4
- require 'lam_auth/controller_extensions'
5
4
  require 'lam_auth/helpers'
6
5
  require 'lam_auth/model'
7
- ActionController::Base.extend(LamAuth::ControllerExtensions)
8
6
  ActionController::Base.helper(LamAuth::Helpers)
9
7
 
10
8
  module LamAuth
11
- class LoginRequiredException < Exception
12
- end
13
-
14
9
  class << self
15
- def config
16
- @config ||= YAML.load_file(Rails.root.join("config/lam_auth.yml"))
10
+ def app
11
+ @app ||= YAML.load_file(Rails.root.join("config/lam_auth.yml"))
17
12
  end
18
-
19
- def url
20
- "http://www.lookatme.ru"
13
+
14
+ def config
15
+ {
16
+ 'lookatme' => {
17
+ 'prefix' => 'lam',
18
+ 'url' => 'http://www.lookatme.ru',
19
+ 'api' => 'LAM',
20
+ 'api_url' => 'http://www.lookatme.ru/api/js/LAM.Login.js',
21
+ },
22
+ 'village' => {
23
+ 'prefix' => 'village',
24
+ 'url' => 'http://www.the-village.ru',
25
+ 'api' => 'VLG',
26
+ 'api_url' => 'http://assets0.the-village.ru/api/js/VLG.Login.js',
27
+ }
28
+ }[site]
21
29
  end
22
-
23
- def signup_url
24
- "#{url}/signup"
30
+
31
+ def site
32
+ %w{lookatme village}.include?(app['site']) ? app['site'] : 'lookatme'
25
33
  end
26
34
 
27
- def uri
28
- URI.parse(url)
35
+ def url
36
+ config['url']
29
37
  end
30
38
 
31
39
  def cookie_id
32
- "lam_#{config['app_id']}"
40
+ "#{config['prefix']}_#{app['app_id']}"
33
41
  end
34
-
35
- def valid_cookie?(data)
36
- valid_hash?(parse_cookie_to_hash(data))
42
+
43
+ def access_token_from_cookie(cookie)
44
+ hash = parse_cookie_to_hash(cookie)
45
+ valid_hash?(hash) && hash['access_token']
37
46
  end
38
47
 
39
48
  def parse_cookie_to_hash(data)
@@ -41,7 +50,7 @@ module LamAuth
41
50
  end
42
51
 
43
52
  def valid_hash?(hash)
44
- Digest::MD5.hexdigest(hash.except('sig').sort.map{|v| v.join('=')}.join + LamAuth.config['secret']) == hash['sig']
53
+ Digest::MD5.hexdigest(hash.except('sig').sort.map{|v| v.join('=')}.join + app['secret']) == hash['sig']
45
54
  end
46
55
  end
47
56
  end
metadata CHANGED
@@ -1,63 +1,84 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: lam_auth
3
- version: !ruby/object:Gem::Version
4
- version: 1.1.0
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
5
  prerelease:
6
+ segments:
7
+ - 2
8
+ - 0
9
+ - 0
10
+ version: 2.0.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Max Macovsky
9
14
  - Anton Platonov
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2012-06-27 00:00:00.000000000 Z
18
+
19
+ date: 2012-08-21 00:00:00 -07:00
20
+ default_executable:
14
21
  dependencies: []
15
- description: ''
16
- email:
22
+
23
+ description: ""
24
+ email:
17
25
  - robotector@gmail.com
18
26
  - platosha@lookatme.ru
19
27
  executables: []
28
+
20
29
  extensions: []
30
+
21
31
  extra_rdoc_files: []
22
- files:
32
+
33
+ files:
23
34
  - .gitignore
24
35
  - Gemfile
25
- - README.rdoc
36
+ - README.md
26
37
  - Rakefile
27
38
  - lam_auth.gemspec
28
- - lib/generators/active_record/lam_auth_generator.rb
29
- - lib/generators/active_record/templates/migration.rb
30
- - lib/generators/lam_auth/helpers.rb
31
39
  - lib/generators/lam_auth/lam_auth_generator.rb
32
40
  - lib/generators/templates/lam_auth.yml
33
41
  - lib/generators/templates/xd_receiver.html
34
42
  - lib/lam_auth.rb
35
- - lib/lam_auth/controller_extensions.rb
36
43
  - lib/lam_auth/helpers.rb
37
44
  - lib/lam_auth/model.rb
38
45
  - lib/lam_auth/version.rb
46
+ has_rdoc: true
39
47
  homepage: http://github.com/macovsky/lam_auth
40
48
  licenses: []
49
+
41
50
  post_install_message:
42
51
  rdoc_options: []
43
- require_paths:
52
+
53
+ require_paths:
44
54
  - lib
45
- required_ruby_version: !ruby/object:Gem::Requirement
55
+ required_ruby_version: !ruby/object:Gem::Requirement
46
56
  none: false
47
- requirements:
48
- - - ! '>='
49
- - !ruby/object:Gem::Version
50
- version: '0'
51
- required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
65
  none: false
53
- requirements:
54
- - - ! '>='
55
- - !ruby/object:Gem::Version
56
- version: '0'
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
57
73
  requirements: []
74
+
58
75
  rubyforge_project:
59
- rubygems_version: 1.8.23
76
+ rubygems_version: 1.6.2
60
77
  signing_key:
61
78
  specification_version: 3
62
- summary: Аутентификация для спецпроектов Lookatme
79
+ summary: !binary |
80
+ 0JDRg9GC0LXQvdGC0LjRhNC40LrQsNGG0LjRjyDQtNC70Y8g0YHQv9C10YbQ
81
+ v9GA0L7QtdC60YLQvtCyIExvb2thdG1l
82
+
63
83
  test_files: []
84
+
data/README.rdoc DELETED
@@ -1,42 +0,0 @@
1
- Аутентификация для спецпроектов Lookatme
2
-
3
- == Установка
4
-
5
- gem install lam_auth
6
-
7
- После установки/добавления в Gemfile:
8
-
9
- rails generate lam_auth User
10
-
11
- после этого нужно добавить настройки приложения для соответствующих environment в config/lam_auth.yml.
12
-
13
- == Обработчик LoginRequiredException
14
-
15
- Для actions, где требуется залогиненный пользователь:
16
-
17
- before_filter :login_required
18
-
19
- можно сделать обработчик для LoginRequiredException:
20
-
21
- rescue_from LamAuth::LoginRequiredException, :with => :render_login_required
22
-
23
- private
24
-
25
- def render_login_required
26
- render :file => 'shared/login_required', :layout => 'application', :status => 401
27
- end
28
-
29
- == Подключение панели
30
-
31
- Подключить js-код в head:
32
-
33
- <%= lam_auth_include_tag %>
34
-
35
- Затем:
36
-
37
- <div id="lam-root"></div>
38
- <%= lam_auth_init_tag %>
39
-
40
- == Подробно о механизме аутентификации
41
-
42
- http://mindscan.msk.ru/downloads/lam_auth.pdf
@@ -1,23 +0,0 @@
1
- require 'rails/generators/active_record'
2
- require 'generators/lam_auth/helpers'
3
-
4
- module ActiveRecord
5
- module Generators
6
- class LamAuthGenerator < ActiveRecord::Generators::Base
7
- include LamAuth::Generators::Helpers
8
- source_root File.expand_path("../templates", __FILE__)
9
-
10
- def generate_model
11
- invoke "active_record:model", [name], :migration => false unless model_exists? && behavior == :invoke
12
- end
13
-
14
- def copy_lam_auth_migration
15
- migration_template "migration.rb", "db/migrate/create_#{table_name}"
16
- end
17
-
18
- def inject_lam_auth_content
19
- inject_into_class(model_path, class_name, model_contents) if model_exists?
20
- end
21
- end
22
- end
23
- end
@@ -1,20 +0,0 @@
1
- class Create<%= table_name.camelize %> < ActiveRecord::Migration
2
- def self.up
3
- create_table(:<%= table_name %>) do |t|
4
- t.string :login, :null => false
5
- t.string :email, :null => false
6
- t.string :first_name
7
- t.string :last_name
8
- t.string :userpic
9
- t.text :profile
10
- t.timestamps
11
- end
12
-
13
- add_index :<%= table_name %>, :login
14
- add_index :<%= table_name %>, :email
15
- end
16
-
17
- def self.down
18
- drop_table :<%= table_name %>
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- module LamAuth
2
- module Generators
3
- module Helpers
4
- def model_exists?
5
- File.exists?(File.join(destination_root, model_path))
6
- end
7
-
8
- def model_path
9
- @model_path ||= File.join("app", "models", "#{file_path}.rb")
10
- end
11
-
12
- def model_contents
13
- <<-CONTENT
14
- include LamAuth::Model
15
- CONTENT
16
- end
17
- end
18
- end
19
- end
@@ -1,53 +0,0 @@
1
- module LamAuth
2
- module ControllerExtensions
3
- def lam_auth_for(klass)
4
- class_attribute :user_model_class_name
5
- self.user_model_class_name = klass
6
-
7
- helper_method(:current_user, :logged_in?)
8
- before_filter :login_from_cookie
9
-
10
- extend ClassMethods
11
- include InstanceMethods
12
- protected :logged_in?, :current_user, :current_user=, :access_token, :login_from_cookie, :login_required
13
- end
14
-
15
- module ClassMethods
16
- def user_model_class
17
- user_model_class_name.to_s.classify.constantize
18
- end
19
- end
20
-
21
- module InstanceMethods
22
- def logged_in?
23
- !!current_user
24
- end
25
-
26
- def current_user
27
- @current_user ||= session[:user] && self.class.user_model_class.find_by_id(session[:user])
28
- end
29
-
30
- def current_user=(new_user)
31
- session[:user] = new_user && new_user.id
32
- @current_user = new_user
33
- end
34
-
35
- def access_token
36
- cookie = cookies[LamAuth.cookie_id]
37
- LamAuth.valid_cookie?(cookie) && LamAuth.parse_cookie_to_hash(cookie)['access_token']
38
- end
39
-
40
- def login_from_cookie
41
- if logged_in?
42
- !access_token && self.current_user = nil
43
- else
44
- access_token && self.current_user = self.class.user_model_class.find_by_access_token(access_token)
45
- end
46
- end
47
-
48
- def login_required
49
- logged_in? || raise(LoginRequiredException)
50
- end
51
- end
52
- end
53
- end