From d214b15d2a65a69d50ff0506d30a0678ad53cc44 Mon Sep 17 00:00:00 2001 From: Dmitrii Samoilov Date: Wed, 20 Apr 2011 20:42:26 +0300 Subject: [PATCH] added Vkontakte OAuth2 provider --- README.markdown | 1 + oa-oauth/lib/omniauth/oauth.rb | 1 + oa-oauth/lib/omniauth/strategies/vkontakte.rb | 84 +++++++++++++++++++ .../omniauth/strategies/vkontakte_spec.rb | 5 ++ 4 files changed, 91 insertions(+) create mode 100644 oa-oauth/lib/omniauth/strategies/vkontakte.rb create mode 100644 oa-oauth/spec/omniauth/strategies/vkontakte_spec.rb diff --git a/README.markdown b/README.markdown index 6f83059d1..b405966dc 100644 --- a/README.markdown +++ b/README.markdown @@ -45,6 +45,7 @@ OmniAuth currently supports the following external providers: * Tumblr (credit: [jamiew](https://github.com/jamiew)) * Twitter * Vimeo (credit: [jamiew](https://github.com/jamiew)) + * Vkontakte (credit: [german](https://github.com/german)) * YouTube (credit: [jamiew](https://github.com/jamiew)) * OpenID * Google Apps (via OpenID) diff --git a/oa-oauth/lib/omniauth/oauth.rb b/oa-oauth/lib/omniauth/oauth.rb index 92091b61c..baee93a67 100644 --- a/oa-oauth/lib/omniauth/oauth.rb +++ b/oa-oauth/lib/omniauth/oauth.rb @@ -39,5 +39,6 @@ module Strategies autoload :TradeMe, 'omniauth/strategies/trade_me' autoload :Teambox, 'omniauth/strategies/teambox' autoload :Tumblr, 'omniauth/strategies/tumblr' + autoload :Vkontakte, 'omniauth/strategies/vkontakte' end end diff --git a/oa-oauth/lib/omniauth/strategies/vkontakte.rb b/oa-oauth/lib/omniauth/strategies/vkontakte.rb new file mode 100644 index 000000000..4d49654b6 --- /dev/null +++ b/oa-oauth/lib/omniauth/strategies/vkontakte.rb @@ -0,0 +1,84 @@ +require 'omniauth/oauth' +require 'multi_json' + +module OmniAuth + module Strategies + # + # Authenticate to Vkontakte utilizing OAuth 2.0 and retrieve + # basic user information. + # documentation available here: + # http://vkontakte.ru/developers.php?o=-17680044&p=Authorization&s=0 + # + # @example Basic Usage + # use OmniAuth::Strategies::Vkontakte, 'API Key', 'Secret Key' + class Vkontakte < OAuth2 + # @param [Rack Application] app standard middleware application parameter + # @param [String] api_key the application id as [registered in Vkontakte] + # @param [String] secret_key the application secret as [registered in Vkontakte] + def initialize(app, api_key = nil, secret_key = nil, options = {}, &block) + client_options = { + :site => 'https://vkontakte.ru', + :authorize_url => 'http://api.vkontakte.ru/oauth/authorize', + :access_token_url => 'https://api.vkontakte.ru/oauth/token' + } + + super(app, :vkontakte, api_key, secret_key, client_options, options, &block) + end + + protected + + def user_data + # http://vkontakte.ru/developers.php?o=-17680044&p=Description+of+Fields+of+the+fields+Parameter + @fields ||= ['uid', 'first_name', 'last_name', 'nickname', 'domain', 'sex', 'city', 'country', 'timezone', 'photo', 'photo_big'] + + # http://vkontakte.ru/developers.php?o=-1&p=getProfiles + @data ||= MultiJson.decode(@access_token.get("https://api.vkontakte.ru/method/getProfiles?uid=#{@access_token['user_id']}&fields=#{@fields.join(',')}&access_token=#{@access_token.token}"))['response'][0] + + # we need these 2 additional requests since vkontakte returns only ids of the City and Country + # http://vkontakte.ru/developers.php?o=-17680044&p=getCities + @city ||= MultiJson.decode(@access_token.get("https://api.vkontakte.ru/method/getCities?cids=#{@data['city']}&access_token=#{@access_token.token}"))['response'][0]['name'] + + # http://vkontakte.ru/developers.php?o=-17680044&p=getCountries + @country ||= MultiJson.decode(@access_token.get("https://api.vkontakte.ru/method/getCountries?cids=#{@data['country']}&access_token=#{@access_token}"))['response'][0]['name'] + end + + def request_phase + options[:response_type] ||= 'code' + super + end + + def user_info + { + 'firstname' => @data['first_name'], + 'last_name' => @data['last_name'], + 'name' => "#{@data['first_name']} #{@data['last_name']}", + 'nickname' => @data['nickname'], + 'image' => @data['photo'], + 'location' => "#{@country}, #{@city}", + 'urls' => { + 'Vkontakte' => "http://vkontakte.ru/#{@data['domain']}" + } + } + end + + def user_hash + { + "user_hash" => { + "gender" => @data["sex"], + "timezone" => @data["timezone"], + "photo_big" => @data["photo_big"] # 200px maximum resolution of the avatar (http://vkontakte.ru/developers.php?o=-17680044&p=Description+of+Fields+of+the+fields+Parameter) + } + } + end + + def auth_hash + user_data # process user's info + OmniAuth::Utils.deep_merge(super, { + 'uid' => @data['uid'], + 'user_info' => user_info, + 'extra' => user_hash + }) + end + end +end +end diff --git a/oa-oauth/spec/omniauth/strategies/vkontakte_spec.rb b/oa-oauth/spec/omniauth/strategies/vkontakte_spec.rb new file mode 100644 index 000000000..884aa0e03 --- /dev/null +++ b/oa-oauth/spec/omniauth/strategies/vkontakte_spec.rb @@ -0,0 +1,5 @@ +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') + +describe OmniAuth::Strategies::Vkontakte do + it_should_behave_like "an oauth2 strategy" +end