oa-vkontakte_alexandrov 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Nick Recobra, Igor Alexandrov
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.rdoc ADDED
@@ -0,0 +1,78 @@
1
+ = oa-vkontakte
2
+
3
+ Расширение для OmniAuth, реализующее аутентификацию через Vkontate Open Api.
4
+
5
+ == Установка
6
+
7
+ gem install oa-vkontakte
8
+
9
+ Добавить в config/initializers/omniauth.rb:
10
+
11
+ Rails.application.config.middleware.use OmniAuth::Builder do
12
+ provider :vkontakte, <ID приложения>, <Защищенный ключ приложения>
13
+ end
14
+
15
+ Если ещё не определен, добавить путь в config/routes.rb:
16
+
17
+ match '/auth/:provider/callback' => 'authentications#create'
18
+
19
+ В нужную вьюху добавить хелпер, рисующий кнопку входа:
20
+
21
+ <%= vkontakte_login_button %>
22
+
23
+ Также кнопка доступна по адресу /auth/vkontakte, но форма там передается GET-запросом. Можно пропробовать встроить её как iframe.
24
+
25
+ После клика на кнопку и разрешения добавления приложения, будет совершен POST-запрос на /auth/vkontakte/callback.
26
+ В action, к которому будет привязан этот путь, будет доступна переменная
27
+
28
+ request["omniauth.auth"]
29
+
30
+ Содержание этой переменной примерно следующее:
31
+
32
+ {
33
+ 'uid' => '1234567890', # ID пользователя vkontakte.ru
34
+ 'provider' => 'vkontakte',
35
+ 'user_info' => {
36
+ 'name' => 'Nick Recobra',
37
+ 'nickname' => 'oruen',
38
+ 'first_name' => 'Nick',
39
+ 'last_name' => 'Recobra',
40
+ 'image' => 'http://cs191.vkontakte.ru/u00001/e_375bc433.jpg', # путь до вконтактовского аватара
41
+ 'urls' => { 'Page' => 'http://vkontakte.ru/id1234567890' }
42
+ }
43
+ }
44
+
45
+ == Интеграция с Devise
46
+
47
+ Devise с версии 1.2.rc интегрирован с OmniAuth. Подключить к нему <tt>oa-vkontakte</tt> достаточно просто, дописав в <tt>config/initializers/devise.rb</tt>:
48
+ config.omniauth :vkontakte, <ID приложения>, <Защищенный ключ приложения>
49
+ Callback будет приходить действию Devise::OmniauthCallbacks#vkontakte, так что придется озаботиться его наличием. Это удобно сделать, поменяв контроллер для callback'ов OmniAuth в <tt>routes.rb</tt>:
50
+ devise_for :users, :controllers => { :omniauth_callbacks => "authentications" }
51
+ AuthenticationsController в этом случае выглядит как-то так:
52
+ class AuthenticationsController < Devise::OmniauthCallbacksController
53
+ def vkontakte
54
+ omniauth = request.env["omniauth.auth"]
55
+ # создание или аутентификация пользователя
56
+ ...
57
+ end
58
+ end
59
+
60
+ == Ссылки
61
+
62
+ OmniAuth: http://github.com/intridea/omniauth
63
+
64
+ Интеграция OmniAuth и Devise: http://railscasts.com/episodes/235-omniauth-part-1 и http://railscasts.com/episodes/236-omniauth-part-2
65
+
66
+ == Note on Patches/Pull Requests
67
+
68
+ * Fork the project.
69
+ * Make your feature addition or bug fix.
70
+ * Add tests for it. This is important so I don't break it in a
71
+ future version unintentionally.
72
+ * Commit, do not mess with rakefile, version, or history.
73
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
74
+ * Send me a pull request. Bonus points for topic branches.
75
+
76
+ == Copyright
77
+
78
+ Copyright (c) 2010 Nick Recobra. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
8
+ gem.name = "oa-vkontakte_alexandrov"
9
+ gem.homepage = "http://github.com/igor-alexandrov/oa-vkontakte"
10
+ gem.license = "MIT"
11
+ gem.summary = %Q{VKontakte OmniAuth module with view helpers}
12
+ gem.description = %Q{Include this gem into your project with OmniAuth gem and you will get VKontakte login in one line of code.}
13
+ gem.email = "igor.alexandrov@gmail.com"
14
+ gem.authors = ["Igor Alexandrov"]
15
+ gem.add_dependency 'oa-core', '~>0.1.4'
16
+ gem.add_development_dependency "rspec", ">= 1.2.9"
17
+ gem.add_development_dependency "yard", ">= 0"
18
+ end
19
+ Jeweler::RubygemsDotOrgTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :spec => :check_dependencies
38
+
39
+ task :default => :spec
40
+
41
+ begin
42
+ require 'yard'
43
+ YARD::Rake::YardocTask.new
44
+ rescue LoadError
45
+ task :yardoc do
46
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
47
+ end
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,5 @@
1
+ require 'omniauth/vkontakte'
2
+
3
+ if defined?(Rails)
4
+ ActionController::Base.helper OmniAuth::Strategies::Vkontakte::ViewHelper::PageHelper
5
+ end
@@ -0,0 +1,58 @@
1
+ require 'omniauth/vkontakte'
2
+ require 'omniauth/strategies/vkontakte/view_helper'
3
+
4
+ module OmniAuth
5
+ class Configuration
6
+ attr_accessor :vkontakte_app_id
7
+ attr_accessor :vkontakte_app_key
8
+ end
9
+ end
10
+
11
+ module OmniAuth
12
+ module Strategies
13
+ class Vkontakte
14
+ include OmniAuth::Strategy
15
+ include ViewHelper::PageHelper
16
+
17
+ def initialize(app, app_id, app_key, options = {})
18
+ @options = options
19
+ OmniAuth.config.vkontakte_app_id = app_id
20
+ OmniAuth.config.vkontakte_app_key = app_key
21
+ super(app, :vkontakte)
22
+ end
23
+
24
+ attr_reader :app_id
25
+
26
+ def request_phase
27
+ Rack::Response.new(vkontakte_login_page).finish
28
+ end
29
+
30
+ def callback_phase
31
+ app_cookie = request.cookies["vk_app_#{OmniAuth.config.vkontakte_app_id}"]
32
+ return fail!(:invalid_credentials) unless app_cookie
33
+ args = app_cookie.split("&")
34
+ sig_index = args.index { |arg| arg =~ /^sig=/ }
35
+ return fail!(:invalid_credentials) unless sig_index
36
+ sig = args.delete_at(sig_index)
37
+ puts Digest::MD5.new.hexdigest(args.sort.join('') + OmniAuth.config.vkontakte_app_key)
38
+ puts sig
39
+ return fail!(:invalid_credentials) unless Digest::MD5.new.hexdigest(args.sort.join('') + OmniAuth.config.vkontakte_app_key) == sig[4..-1]
40
+ super
41
+ end
42
+
43
+ def auth_hash
44
+ OmniAuth::Utils.deep_merge(super(), {
45
+ 'uid' => request[:uid],
46
+ 'user_info' => {
47
+ 'nickname' => request[:nickname],
48
+ 'name' => "#{request[:first_name]} #{request[:last_name]}",
49
+ 'first_name' => request[:first_name],
50
+ 'last_name' => request[:last_name],
51
+ 'image' => request[:photo],
52
+ 'urls' => { 'Page' => 'http://vkontakte.ru/id' + request[:uid] }
53
+ }
54
+ })
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,130 @@
1
+ # coding: utf-8
2
+ module OmniAuth
3
+ module Strategies
4
+ class Vkontakte
5
+ class ViewHelper
6
+ module PageHelper
7
+ def vkontakte_login_page
8
+ vkontakte_header +
9
+ vkontakte_login_button +
10
+ vkontakte_footer
11
+ end
12
+
13
+ def vkontakte_header
14
+ <<-HEADER
15
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
16
+ <html xmlns="http://www.w3.org/1999/xhtml">
17
+ <head>
18
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
19
+ <title>Вход во ВКонтакте</title>
20
+ </head>
21
+ <body>
22
+ HEADER
23
+ end
24
+
25
+ def vkontakte_login_button
26
+ <<-BUTTON
27
+ <div id="vk_api_transport"></div>
28
+ <script type="text/javascript">
29
+ window.vkAsyncInit = function() {
30
+ VK.init({
31
+ apiId: '#{OmniAuth.config.vkontakte_app_id}',
32
+ nameTransportPath: "/xd_receiver.html"
33
+ });
34
+ VK.UI.button('vk_login');
35
+ };
36
+ vkLogin = {
37
+ doLogin: function() {
38
+ VK.Auth.login(vkLogin.loginResult);
39
+ },
40
+ redirectWithPost: function(url, data) {
41
+ data = data || {};
42
+ #{ respond_to?(:request_forgery_protection_token) && respond_to?(:form_authenticity_token) ?
43
+ "data['#{request_forgery_protection_token}'] = '#{form_authenticity_token}'; var method = 'POST';" :
44
+ "var method = 'GET';" }
45
+ var form = document.createElement("form"),
46
+ input;
47
+ form.setAttribute("action", url);
48
+ form.setAttribute("method", method);
49
+
50
+ for (var property in data) {
51
+ if (data.hasOwnProperty(property)) {
52
+ var value = data[property];
53
+ if (value instanceof Array) {
54
+ for (var i = 0, l = value.length; i < l; i++) {
55
+ input = document.createElement("input");
56
+ input.setAttribute("type", "hidden");
57
+ input.setAttribute("name", property);
58
+ input.setAttribute("value", value[i]);
59
+ form.appendChild(input);
60
+ }
61
+ }
62
+ else {
63
+ input = document.createElement("input");
64
+ input.setAttribute("type", "hidden");
65
+ input.setAttribute("name", property);
66
+ input.setAttribute("value", value);
67
+ form.appendChild(input);
68
+ }
69
+ }
70
+ }
71
+ document.body.appendChild(form);
72
+ form.submit();
73
+ document.body.removeChild(form);
74
+ },
75
+ loginResult: function (r) {
76
+ if (r.session) {
77
+ if (r.session.expire != "0") {
78
+ vkLogin.getUserProfile(vkLogin.putUserProfile);
79
+ } else if (r.session.expire == "0") {
80
+ VK.Observer.subscribe("auth.sessionChange", function (r) {
81
+ VK.Observer.unsubscribe("auth.sessionChange");
82
+ if (r.session && r.session.expire != "0") {
83
+ vkLogin.getUserProfile(vkLogin.putUserProfile)
84
+ } else {
85
+ }
86
+ });
87
+ VK.Auth.login()
88
+ }
89
+ }
90
+ },
91
+ getUserProfile: function (callFunc) {
92
+ var code;
93
+ code = 'return {';
94
+ code += 'me: API.getProfiles({uids: API.getVariable({key: 1280}), fields: "nickname,sex,photo"})[0]';
95
+ code += '};';
96
+ VK.Api.call('execute', {
97
+ 'code': code
98
+ },
99
+ callFunc);
100
+ },
101
+ putUserProfile: function (data) {
102
+ if (data.response) {
103
+ r = data.response;
104
+ vkLogin.redirectWithPost('#{OmniAuth.config.path_prefix}/vkontakte/callback', r.me);
105
+ }
106
+ }
107
+ };
108
+ (function() {
109
+ var el = document.createElement("script");
110
+ el.type = "text/javascript";
111
+ el.charset = "windows-1251";
112
+ el.src = "http://vkontakte.ru/js/api/openapi.js";
113
+ el.async = true;
114
+ document.getElementById("vk_api_transport").appendChild(el);
115
+ }());
116
+ </script>
117
+ <div id="vk_login" onclick="vkLogin.doLogin();"></div>
118
+ BUTTON
119
+ end
120
+
121
+ def vkontakte_footer
122
+ <<-FOOTER
123
+ </body></html>
124
+ FOOTER
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,8 @@
1
+ require 'omniauth/core'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ autoload :Vkontakte, 'omniauth/strategies/vkontakte'
6
+ end
7
+ end
8
+
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "oa-vkontakte/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{oa-vkontakte}
7
+ s.version = Oa::Vkontakte::VERSION
8
+ s.authors = ["Nick Recobra"]
9
+ s.summary = %q{OmniAuth extension for vkontakte.ru authentication}
10
+ s.description = %q{OmniAuth extension for vkontakte.ru authentication}
11
+ s.email = %q{oruenu@gmail.com}
12
+ s.homepage = %q{http://github.com/oruen/oa-vkontakte}
13
+ s.rubyforge_project = %q{oa-vkontakte}
14
+
15
+ s.add_dependency(%q<oa-core>, [">= 0.1.6"])
16
+ s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
17
+ s.add_development_dependency(%q<yard>, [">= 0"])
18
+ s.add_development_dependency(%q<rack-test>, ["~> 0.5.6"])
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
25
+
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "OaVkontakte" do
4
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe OmniAuth::Strategies::Vkontakte, :type => :strategy do
4
+
5
+ include OmniAuth::Test::StrategyTestCase
6
+
7
+ def strategy
8
+ [OmniAuth::Strategies::Vkontakte, 1983892, '6FF1PUlZfEyutJxctvtd']
9
+ end
10
+
11
+ describe 'POST /auth/vkontakte_open_api/callback с логином и паролем' do
12
+ before(:each) do
13
+ @params = {
14
+ 'nickname' => 'oruen',
15
+ 'first_name' => 'Nick',
16
+ 'last_name' => 'Recobra',
17
+ 'photo' => 'http://cs191.vkontakte.ru/u00001/e_375bc433.jpg',
18
+ 'uid' => '1234567890'
19
+ }
20
+ end
21
+
22
+ context "неуспешный запрос" do
23
+ it "не должен быть успешным при отсутствии куки vk_app_<APP_ID>" do
24
+ clear_cookies
25
+ post '/auth/vkontakte/callback', @params
26
+ last_response.should_not be_ok
27
+ end
28
+
29
+ it "не должен быть успешным при невалидной куке vk_app_<APP_ID>" do
30
+ set_cookie "vk_app_#{OmniAuth.config.vkontakte_app_id}=expire"
31
+ post '/auth/vkontakte/callback', @params
32
+ last_response.should_not be_ok
33
+ end
34
+ end
35
+
36
+ context "успешный запрос" do
37
+ before(:each) do
38
+ strategy = nil
39
+ string = "expire=1271238742&mid=100172&secret=97c1e8933e&sid=549b550f608e4a4d247734941debb5e68df50a66c58dc6ee2a4f60a2&sig=372df9795fe8dd29684a2f996872457c"
40
+ set_cookie "vk_app_#{OmniAuth.config.vkontakte_app_id}=#{Rack::Utils::escape string}"
41
+ post '/auth/vkontakte/callback', @params
42
+ end
43
+
44
+ it "должен устанавливаться защищенный ключ" do
45
+ OmniAuth.config.vkontakte_app_key.should == '6FF1PUlZfEyutJxctvtd'
46
+ end
47
+
48
+
49
+ it 'должен быть успешным' do
50
+ last_response.should be_ok
51
+ end
52
+
53
+ sets_an_auth_hash
54
+
55
+ sets_provider_to 'vkontakte'
56
+
57
+ it 'должен устанавливать параметры' do
58
+ hash = last_request.env['omniauth.auth']
59
+ hash.should == {
60
+ 'uid' => '1234567890',
61
+ 'provider' => 'vkontakte',
62
+ 'user_info' => {
63
+ 'name' => 'Nick Recobra',
64
+ 'nickname' => 'oruen',
65
+ 'first_name' => 'Nick',
66
+ 'last_name' => 'Recobra',
67
+ 'image' => 'http://cs191.vkontakte.ru/u00001/e_375bc433.jpg',
68
+ 'urls' => { 'Page' => 'http://vkontakte.ru/id1234567890' }
69
+ }
70
+ }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+ require 'rspec'
5
+ require 'omniauth/test'
6
+ require 'rack/test'
7
+ require 'oa-vkontakte'
8
+
9
+ Rspec.configure do |c|
10
+ c.mock_with :rspec
11
+ c.include Rack::Test::Methods
12
+ c.extend OmniAuth::Test::StrategyMacros, :type => :strategy
13
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oa-vkontakte_alexandrov
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Igor Alexandrov
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-17 00:00:00 +03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: oa-core
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 19
30
+ segments:
31
+ - 0
32
+ - 1
33
+ - 4
34
+ version: 0.1.4
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 13
46
+ segments:
47
+ - 1
48
+ - 2
49
+ - 9
50
+ version: 1.2.9
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: yard
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :development
66
+ version_requirements: *id003
67
+ description: Include this gem into your project with OmniAuth gem and you will get VKontakte login in one line of code.
68
+ email: igor.alexandrov@gmail.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files:
74
+ - LICENSE
75
+ - README.rdoc
76
+ files:
77
+ - .document
78
+ - LICENSE
79
+ - README.rdoc
80
+ - Rakefile
81
+ - VERSION
82
+ - lib/oa-vkontakte.rb
83
+ - lib/omniauth/strategies/vkontakte.rb
84
+ - lib/omniauth/strategies/vkontakte/view_helper.rb
85
+ - lib/omniauth/vkontakte.rb
86
+ - oa-vkontakte.gemspec
87
+ - spec/oa-vkontakte_spec.rb
88
+ - spec/omniauth/strategires/vkontakte_spec.rb
89
+ - spec/spec_helper.rb
90
+ has_rdoc: true
91
+ homepage: http://github.com/igor-alexandrov/oa-vkontakte
92
+ licenses:
93
+ - MIT
94
+ post_install_message:
95
+ rdoc_options: []
96
+
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project:
120
+ rubygems_version: 1.5.2
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: VKontakte OmniAuth module with view helpers
124
+ test_files:
125
+ - spec/oa-vkontakte_spec.rb
126
+ - spec/omniauth/strategires/vkontakte_spec.rb
127
+ - spec/spec_helper.rb