Commit 1213fdf1e3ceed079b54779296dcd26cf60e65e4

Authored by Braulio Bhavamitra
2 parents c6f5b484 8408ffac

Merge branch 'oauth_rails3' into 'master'

Two oauth plugins: oauth_client and oauth_provider

See merge request !415
Showing 47 changed files with 1138 additions and 1 deletions   Show diff stats
app/views/account/_signup_form.html.erb
... ... @@ -16,7 +16,7 @@
16 16 <input type="hidden" id="signup_time_key" name="signup_time_key" />
17 17 <script type="text/javascript">
18 18 jQuery.ajax({
19   - type: "POST",
  19 + type: "GET",
20 20 url: "<%= url_for :controller=>'account', :action=>'signup_time' %>",
21 21 dataType: 'json',
22 22 success: function(data) {
... ...
plugins/oauth_client/Gemfile 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +gem 'omniauth', '~> 1.2.2'
  2 +gem 'omniauth-facebook', '~> 2.0.0'
  3 +gem "omniauth-google-oauth2", '~> 0.2.6'
... ...
plugins/oauth_client/README.md 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +README - Oauth Client Plugin
  2 +================================
  3 +
  4 +OauthClient is a plugin which allow users to login/signup to noosfero with some oauth providers (for now, google, facebook and noosfero itself).
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_client
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Client Plugin" check-box
  22 +
  23 +Provider Settings
  24 +=================
  25 +
  26 +Goggle
  27 +------
  28 +
  29 +[Create Google+ application](https://developers.google.com/+/web/signin/javascript-flow)
  30 +
  31 +Facebook
  32 +--------
  33 +
  34 +[Create Facebook application](https://developers.facebook.com/docs/facebook-login/v2.1)
  35 +
  36 +Varnish Settings
  37 +================
  38 +If varnish has been used in your stack, you've to bypass the cache for signup page and prevent cookies to be removed when calling the oauth_client plugin callback. E.g.:
  39 +
  40 +```
  41 +if (req.url !~ "^/account/*" && req.url !~ "^/plugin/oauth_provider/*" && req.url !~ "^/plugin/oauth_client/*" && req.http.cookie !~ "_noosfero_.*") {
  42 + unset req.http.cookie;
  43 + return(lookup);
  44 +}
  45 +```
  46 +
  47 +Using Oauth Provider Plugin
  48 +===========================
  49 +The oauth_provider plugin may be used as a provider in the same noosfero installation that hosts your oauth_client plugin (this is usefull in a multi environment setup).
  50 +
  51 +However, you've to use a distinct set of thin processes to handle the authorization requests (to avoid deadlock).
  52 +
  53 +Apache settings example:
  54 +```
  55 +RewriteRule ^/oauth_provider/oauth/(authorize|token).*$ balancer://noosfero-oauth-provider%{REQUEST_URI} [P,QSA,L]
  56 +```
  57 +
  58 +
  59 +Development
  60 +===========
  61 +
  62 +Running OauthClient tests
  63 +--------------------
  64 +
  65 +$ rake test:noosfero_plugins:oauth_client
  66 +
  67 +License
  68 +=======
  69 +
  70 +Copyright (c) The Author developers.
  71 +
  72 +See Noosfero license.
... ...
plugins/oauth_client/controllers/oauth_client_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class OauthClientPluginAdminController < AdminController
  2 +
  3 + def index
  4 + end
  5 +
  6 + def new
  7 + @provider = environment.oauth_providers.new
  8 + render :file => 'oauth_client_plugin_admin/edit'
  9 + end
  10 +
  11 + def remove
  12 + environment.oauth_providers.find(params[:id]).destroy
  13 + redirect_to :action => 'index'
  14 + end
  15 +
  16 + def edit
  17 + @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new
  18 + if request.post?
  19 + if @provider.update_attributes(params['oauth_client_plugin_provider'])
  20 + session[:notice] = _('Saved!')
  21 + else
  22 + session[:notice] = _('Error!')
  23 + end
  24 + end
  25 + end
  26 +
  27 +end
... ...
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +class OauthClientPluginPublicController < PublicController
  2 +
  3 + skip_before_filter :login_required
  4 +
  5 + def callback
  6 + auth = request.env["omniauth.auth"]
  7 + user = environment.users.find_by_email(auth.info.email)
  8 + user ? login(user) : signup(auth)
  9 + end
  10 +
  11 + def failure
  12 + session[:notice] = _('Failed to login')
  13 + redirect_to root_url
  14 + end
  15 +
  16 + def destroy
  17 + session[:user] = nil
  18 + redirect_to root_url
  19 + end
  20 +
  21 + protected
  22 +
  23 + def login(user)
  24 + provider = OauthClientPlugin::Provider.find(session[:provider_id])
  25 + user_provider = user.oauth_user_providers.find_by_provider_id(provider.id)
  26 + unless user_provider
  27 + user_provider = user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => true)
  28 + end
  29 + if user_provider.enabled? && provider.enabled?
  30 + session[:user] = user.id
  31 + else
  32 + session[:notice] = _("Can't login with #{provider.name}")
  33 + end
  34 +
  35 + redirect_to :controller => :account, :action => :login
  36 + end
  37 +
  38 + def signup(auth)
  39 + login = auth.info.email.split('@').first
  40 + session[:oauth_data] = auth
  41 + name = auth.info.name
  42 + name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : ''
  43 + redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name}
  44 + end
  45 +
  46 +end
... ...
plugins/oauth_client/db/migrate/20141010135314_create_oauth_client_plugin_provider.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class CreateOauthClientPluginProvider < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + create_table :oauth_client_plugin_providers do |t|
  5 + t.integer :environment_id
  6 + t.string :strategy
  7 + t.string :name
  8 + t.text :options
  9 + t.boolean :enabled
  10 + t.integer :image_id
  11 +
  12 + t.timestamps
  13 + end
  14 + end
  15 +
  16 + def self.down
  17 + drop_table :oauth_client_plugin_providers
  18 + end
  19 +end
... ...
plugins/oauth_client/db/migrate/20141014162710_create_oauth_client_user_providers.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateOauthClientUserProviders < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :oauth_client_plugin_user_providers do |t|
  4 + t.references :user
  5 + t.references :provider
  6 + t.boolean :enabled
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :oauth_client_plugin_user_providers
  13 + end
  14 +end
... ...
plugins/oauth_client/lib/ext/environment.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 +
  5 + has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider'
  6 +
  7 +end
... ...
plugins/oauth_client/lib/ext/user.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +require_dependency 'user'
  2 +
  3 +class User
  4 +
  5 + has_many :oauth_user_providers, :class_name => 'OauthClientPlugin::UserProvider'
  6 + has_many :oauth_providers, :through => :oauth_user_providers, :source => :provider
  7 +
  8 + def password_required_with_oauth?
  9 + password_required_without_oauth? && oauth_providers.empty?
  10 + end
  11 +
  12 + alias_method_chain :password_required?, :oauth
  13 +
  14 + after_create :activate_oauth_user
  15 +
  16 + def activate_oauth_user
  17 + unless oauth_providers.empty?
  18 + activate
  19 + oauth_providers.each do |provider|
  20 + OauthClientPlugin::UserProvider.create!(:user => self, :provider => provider, :enabled => true)
  21 + end
  22 + end
  23 + end
  24 +
  25 + def make_activation_code_with_oauth
  26 + oauth_providers.blank? ? make_activation_code_without_oauth : nil
  27 + end
  28 +
  29 + alias_method_chain :make_activation_code, :oauth
  30 +
  31 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +require 'omniauth/strategies/noosfero_oauth2'
  2 +
  3 +class OauthClientPlugin < Noosfero::Plugin
  4 +
  5 + def self.plugin_name
  6 + "Oauth Client Plugin"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("Login with Oauth.")
  11 + end
  12 +
  13 + def login_extra_contents
  14 + plugin = self
  15 + proc do
  16 + render :partial => 'auth/oauth_login', :locals => {:providers => environment.oauth_providers.enabled}
  17 + end
  18 + end
  19 +
  20 + def signup_extra_contents
  21 + plugin = self
  22 +
  23 + proc do
  24 + if plugin.context.session[:oauth_data].present?
  25 + render :partial => 'account/oauth_signup'
  26 + else
  27 + ''
  28 + end
  29 + end
  30 + end
  31 +
  32 + PROVIDERS = {
  33 + :facebook => {
  34 + :name => 'Facebook'
  35 + },
  36 + :google_oauth2 => {
  37 + :name => 'Google'
  38 + },
  39 + :noosfero_oauth2 => {
  40 + :name => 'Noosfero'
  41 + }
  42 + }
  43 +
  44 + def stylesheet?
  45 + true
  46 + end
  47 +
  48 + OmniAuth.config.on_failure = OauthClientPluginPublicController.action(:failure)
  49 +
  50 + Rails.application.config.middleware.use OmniAuth::Builder do
  51 + PROVIDERS.each do |provider, options|
  52 + setup = lambda { |env|
  53 + request = Rack::Request.new(env)
  54 + strategy = env['omniauth.strategy']
  55 +
  56 + Noosfero::MultiTenancy.setup!(request.host)
  57 + domain = Domain.find_by_name(request.host)
  58 + environment = domain.environment rescue Environment.default
  59 +
  60 + provider_id = request.params['id']
  61 + provider_id ||= request.session['omniauth.params']['id'] if request.session['omniauth.params']
  62 + provider = environment.oauth_providers.find(provider_id)
  63 + strategy.options.merge!(provider.options.symbolize_keys)
  64 +
  65 + request.session[:provider_id] = provider_id
  66 + }
  67 +
  68 + provider provider, :setup => setup,
  69 + :path_prefix => '/plugin/oauth_client',
  70 + :callback_path => "/plugin/oauth_client/public/callback/#{provider}",
  71 + :client_options => { :connection_opts => { :proxy => ENV["OAUTH_HTTP_PROXY"] } }
  72 + end
  73 +
  74 + unless Rails.env.production?
  75 + provider :developer, :path_prefix => "/plugin/oauth_client", :callback_path => "/plugin/oauth_client/public/callback/developer"
  76 + end
  77 + end
  78 +
  79 + def account_controller_filters
  80 + {
  81 + :type => 'before_filter', :method_name => 'signup',
  82 + :block => proc {
  83 + auth = session[:oauth_data]
  84 +
  85 + if auth.present? && params[:user].present?
  86 + params[:user][:oauth_providers] = [OauthClientPlugin::Provider.find(session[:provider_id])]
  87 + if request.post? && auth.info.email != params[:user][:email]
  88 + raise "Wrong email for oauth signup"
  89 + end
  90 + end
  91 + }
  92 + }
  93 + end
  94 +
  95 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/provider.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +class OauthClientPlugin::Provider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :environment
  4 +
  5 + validates_presence_of :name, :strategy
  6 +
  7 + acts_as_having_image
  8 + acts_as_having_settings :field => :options
  9 +
  10 + settings_items :client_id, :type => :string
  11 + settings_items :client_secret, :type => :string
  12 + settings_items :client_options, :type => Hash
  13 +
  14 + attr_accessible :name, :environment, :strategy, :client_id, :client_secret, :enabled, :client_options, :image_builder
  15 +
  16 + scope :enabled, :conditions => {:enabled => true}
  17 +
  18 + acts_as_having_image
  19 +
  20 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/user_provider.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class OauthClientPlugin::UserProvider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :user, :class_name => 'User'
  4 + belongs_to :provider, :class_name => 'OauthClientPlugin::Provider'
  5 +
  6 + set_table_name :oauth_client_plugin_user_providers
  7 +
  8 + attr_accessible :user, :provider, :enabled
  9 +
  10 +end
... ...
plugins/oauth_client/lib/omniauth/strategies/noosfero_oauth2.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +require 'omniauth/strategies/oauth2'
  2 +
  3 +module OmniAuth
  4 + module Strategies
  5 + class NoosferoOauth2 < OmniAuth::Strategies::OAuth2
  6 + option :name, :noosfero_oauth2
  7 + option :client_options, {
  8 + :authorize_url => '/oauth_provider/oauth/authorize',
  9 + :token_url => '/oauth_provider/oauth/token'
  10 + }
  11 +
  12 + uid { raw_info["id"] }
  13 +
  14 + info do
  15 + {
  16 + :email => raw_info["email"]
  17 + }
  18 + end
  19 +
  20 + def raw_info
  21 + #FIXME access the noosfero api (coming soon)
  22 + @raw_info ||= access_token.get('/plugin/oauth_provider/public/me').parsed
  23 + end
  24 + end
  25 + end
  26 +end
... ...
plugins/oauth_client/public/style.css 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +.oauth-login .provider a {
  2 + min-width: 20px;
  3 + min-height: 20px;
  4 + background-size: 20px;
  5 + display: inline-block;
  6 + text-decoration: none;
  7 + background-repeat: no-repeat;
  8 + line-height: 20px;
  9 +}
  10 +.oauth-login .provider a img {
  11 + max-width: 40px;
  12 +}
  13 +.oauth-login .provider a:hover {
  14 + opacity: 0.7;
  15 +}
  16 +.oauth-login .provider .developer {
  17 + display: none;
  18 +}
... ...
plugins/oauth_client/test/functional/oauth_client_plugin_public_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,80 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginPublicControllerTest < ActionController::TestCase
  4 +
  5 + def setup
  6 + @auth = mock
  7 + @auth.stubs(:info).returns(mock)
  8 + request.env["omniauth.auth"] = @auth
  9 + @environment = Environment.default
  10 + @provider = OauthClientPlugin::Provider.create!(:name => 'provider', :strategy => 'provider', :enabled => true)
  11 + end
  12 + attr_reader :auth, :environment, :provider
  13 +
  14 + should 'redirect to signup when user is not found' do
  15 + auth.info.stubs(:email).returns("xyz123@noosfero.org")
  16 + auth.info.stubs(:name).returns('xyz123')
  17 + session[:provider_id] = provider.id
  18 +
  19 + get :callback
  20 + assert_match /.*\/account\/signup/, @response.redirect_url
  21 + end
  22 +
  23 + should 'redirect to login when user is found' do
  24 + user = fast_create(User, :environment_id => environment.id)
  25 + auth.info.stubs(:email).returns(user.email)
  26 + auth.info.stubs(:name).returns(user.name)
  27 + session[:provider_id] = provider.id
  28 +
  29 + get :callback
  30 + assert_redirected_to :controller => :account, :action => :login
  31 + assert_equal user.id, session[:user]
  32 + end
  33 +
  34 + should 'do not login when the provider is disabled' do
  35 + user = fast_create(User, :environment_id => environment.id)
  36 + auth.info.stubs(:email).returns(user.email)
  37 + auth.info.stubs(:name).returns(user.name)
  38 + session[:provider_id] = provider.id
  39 + provider.update_attribute(:enabled, false)
  40 +
  41 + get :callback
  42 + assert_redirected_to :controller => :account, :action => :login
  43 + assert_equal nil, session[:user]
  44 + end
  45 +
  46 + should 'do not login when the provider is disabled for a user' do
  47 + user = fast_create(User, :environment_id => environment.id)
  48 + auth.info.stubs(:email).returns(user.email)
  49 + auth.info.stubs(:name).returns(user.name)
  50 + session[:provider_id] = provider.id
  51 + user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => false)
  52 +
  53 + get :callback
  54 + assert_redirected_to :controller => :account, :action => :login
  55 + assert_equal nil, session[:user]
  56 + end
  57 +
  58 + should 'save provider when an user login with it' do
  59 + user = fast_create(User, :environment_id => environment.id)
  60 + auth.info.stubs(:email).returns(user.email)
  61 + auth.info.stubs(:name).returns(user.name)
  62 + session[:provider_id] = provider.id
  63 +
  64 + get :callback
  65 + assert_equal [provider], user.oauth_providers
  66 + end
  67 +
  68 + should 'do not duplicate relations between an user and a provider when the same provider was used again in a login' do
  69 + user = fast_create(User, :environment_id => environment.id)
  70 + auth.info.stubs(:email).returns(user.email)
  71 + auth.info.stubs(:name).returns(user.name)
  72 + session[:provider_id] = provider.id
  73 +
  74 + get :callback
  75 + assert_no_difference 'user.oauth_user_providers.count' do
  76 + 3.times { get :callback }
  77 + end
  78 + end
  79 +
  80 +end
... ...
plugins/oauth_client/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
... ...
plugins/oauth_client/test/unit/environment_test.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + should 'be able to add oauth providers in a environment' do
  6 + env = fast_create(Environment)
  7 + env.oauth_providers << OauthClientPlugin::Provider.new(:name => 'test', :strategy => 'test')
  8 + end
  9 +
  10 +end
... ...
plugins/oauth_client/test/unit/oauth_client_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,86 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = OauthClientPlugin.new(self)
  7 + @params = {}
  8 + @plugin.stubs(:context).returns(self)
  9 + @environment = Environment.default
  10 + @session = {}
  11 + @request = mock
  12 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  13 + end
  14 +
  15 + attr_reader :params, :plugin, :environment, :session, :request, :provider
  16 +
  17 + should 'has extra contents for login' do
  18 + assert plugin.login_extra_contents
  19 + end
  20 +
  21 + should 'has no signup extra contents if no provider was enabled' do
  22 + assert_equal '', instance_eval(&plugin.signup_extra_contents)
  23 + end
  24 +
  25 + should 'has signup extra contents if oauth_data exists in session' do
  26 + session[:oauth_data] = {:oauth => 'test'}
  27 + expects(:render).with(:partial => 'account/oauth_signup').once
  28 + instance_eval(&plugin.signup_extra_contents)
  29 + end
  30 +
  31 + should 'define before filter for account controller' do
  32 + assert plugin.account_controller_filters
  33 + end
  34 +
  35 + should 'raise error if oauth email was changed' do
  36 + request.expects(:post?).returns(true)
  37 +
  38 + oauth_data = mock
  39 + info = mock
  40 + oauth_data.stubs(:info).returns(info)
  41 + oauth_data.stubs(:uid).returns('uid')
  42 + oauth_data.stubs(:provider).returns('provider')
  43 + info.stubs(:email).returns('test@example.com')
  44 + session[:oauth_data] = oauth_data
  45 + session[:provider_id] = provider.id
  46 +
  47 + params[:user] = {:email => 'test2@example.com'}
  48 + assert_raises RuntimeError do
  49 + instance_eval(&plugin.account_controller_filters[:block])
  50 + end
  51 + end
  52 +
  53 + should 'do not raise error if oauth email was not changed' do
  54 + request.expects(:post?).returns(true)
  55 +
  56 + oauth_data = mock
  57 + info = mock
  58 + oauth_data.stubs(:info).returns(info)
  59 + oauth_data.stubs(:uid).returns('uid')
  60 + oauth_data.stubs(:provider).returns('provider')
  61 + info.stubs(:email).returns('test@example.com')
  62 + session[:oauth_data] = oauth_data
  63 + session[:provider_id] = provider.id
  64 +
  65 + params[:user] = {:email => 'test@example.com'}
  66 + instance_eval(&plugin.account_controller_filters[:block])
  67 + end
  68 +
  69 + should 'do not raise error if oauth session is not set' do
  70 + instance_eval(&plugin.account_controller_filters[:block])
  71 + end
  72 +
  73 + should 'do not raise error if it is not a post' do
  74 + request.expects(:post?).returns(false)
  75 + params[:user] = {:email => 'test2@example.com'}
  76 +
  77 + oauth_data = mock
  78 + oauth_data.stubs(:uid).returns('uid')
  79 + oauth_data.stubs(:provider).returns('provider')
  80 + session[:provider_id] = provider.id
  81 +
  82 + session[:oauth_data] = oauth_data
  83 + instance_eval(&plugin.account_controller_filters[:block])
  84 + end
  85 +
  86 +end
... ...
plugins/oauth_client/test/unit/user_test.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  7 + end
  8 + attr_reader :provider
  9 +
  10 + should 'password is not required if there is a oauth provider' do
  11 + User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  12 + end
  13 +
  14 + should 'password is required if there is a oauth provider' do
  15 + user = User.new(:email => 'testoauth@example.com', :login => 'testoauth')
  16 + user.save
  17 + assert user.errors[:password].present?
  18 + end
  19 +
  20 + should 'activate user when created with oauth' do
  21 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  22 + assert user.activated?
  23 + end
  24 +
  25 + should 'not activate user when created without oauth' do
  26 + user = fast_create(User)
  27 + assert !user.activated?
  28 + end
  29 +
  30 + should 'not make activation code when created with oauth' do
  31 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  32 + assert !user.activation_code
  33 + end
  34 +
  35 + should 'make activation code when created without oauth' do
  36 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :password => 'test', :password_confirmation => 'test')
  37 + assert user.activation_code
  38 + end
  39 +
  40 +end
... ...
plugins/oauth_client/views/account/_oauth_signup.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<%= hidden_field_tag 'return_to', '/' %>
  2 +
  3 +<style>
  4 + #signup-password, #signup-password-confirmation, #signup-email {
  5 + display: none;
  6 + }
  7 +</style>
  8 +
  9 +<div id='signup-email-readonly'>
  10 + <%= labelled_form_field(_('Email'), text_field(:user, :email, :class => "disabled", :readonly => true)) %>
  11 +</div>
... ...
plugins/oauth_client/views/auth/_oauth_login.html.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<div class="oauth-login">
  2 + <% unless providers.empty? %>
  3 + <%= _('Login with:') %>
  4 + <% end %>
  5 + <% providers.each do |provider| %>
  6 + <span class="provider">
  7 + <%= link_to provider.image ? image_tag(provider.image.public_filename) : provider.name, "/plugin/oauth_client/#{provider.strategy}?id=#{provider.id}", :class => provider.strategy, :title => provider.name %>
  8 + </span>
  9 + <% end %>
  10 +
  11 + <span class="provider">
  12 + <% unless Rails.env.production? %>
  13 + <%= link_to _('Developer Login'), "/plugin/oauth_client/developer", :class => 'developer' %>
  14 + <% end %>
  15 + </span>
  16 +</div>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/_noosfero_oauth2.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%= f.fields_for :client_options, OpenStruct.new(provider.options[:client_options]) do |c| %>
  2 + <div class="client-url">
  3 + <%= labelled_form_field _('Client Url'), c.text_field(:site) %>
  4 + </div>
  5 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Edit Provider') %></h3>
  3 +
  4 +<%= form_for @provider, :url => {:action => 'edit'}, :method => 'post' do |f| %>
  5 +
  6 + <div class="enabled">
  7 + <%= labelled_form_field f.check_box(:enabled) + _('Enabled'), '' %>
  8 + </div>
  9 +
  10 + <div class="name">
  11 + <%= labelled_form_field _('Name'), f.text_field(:name) %>
  12 + </div>
  13 +
  14 + <div class="strategy">
  15 + <%= labelled_form_field _('Strategy'), f.select(:strategy, OauthClientPlugin::PROVIDERS) %>
  16 + </div>
  17 +
  18 + <div class="client-id">
  19 + <%= labelled_form_field _('Client Id'), f.text_field(:client_id) %>
  20 + </div>
  21 +
  22 + <div class="client-secret">
  23 + <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %>
  24 + </div>
  25 +
  26 + <% if File.exists?(File.join(File.dirname(__FILE__), "_#{@provider.strategy}.html.erb")) %>
  27 + <%= render :partial => "#{@provider.strategy}", :locals => {:f => f, :provider => @provider} %>
  28 + <% end %>
  29 +
  30 + <div class="image-icon">
  31 + <%= f.fields_for :image_builder, @provider.image do |i| %>
  32 + <%= file_field_or_thumbnail(_('Image:'), @provider.image, i) %><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
  33 + <% end %>
  34 + </div>
  35 +
  36 + <% button_bar do %>
  37 + <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
  38 + <% end %>
  39 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Providers') %></h3>
  3 +<%= button :add, _('New'), {:action => 'new'} %>
  4 +<table>
  5 + <tr>
  6 + <th><%= _('Name') %></th>
  7 + <th><%= _('Strategy') %></th>
  8 + <th><%= _('Actions') %></th>
  9 + </tr>
  10 +
  11 + <% environment.oauth_providers.each do |provider| %>
  12 + <tr>
  13 + <td><%= provider.name %></td>
  14 + <td><%= provider.strategy %></td>
  15 + <td>
  16 + <%= link_to _('Edit'), {:action => 'edit', :id => provider.id} %>
  17 + <%= link_to _('Remove'), {:action => 'remove', :id => provider.id} %>
  18 + </td>
  19 + </tr>
  20 + <% end %>
  21 +</table>
  22 +<div class="actions">
  23 + <%= button(:back, _('Go back'), {:controller => 'plugins', :action => 'index'}) %>
  24 +</div>
... ...
plugins/oauth_provider/Gemfile 0 → 100644
... ... @@ -0,0 +1 @@
  1 +gem 'doorkeeper', '~> 1.4.0'
... ...
plugins/oauth_provider/README.md 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +README - Oauth Provider Plugin
  2 +================================
  3 +
  4 +OauthProvider is a plugin which allow noosfero to be used as an oauth provider
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_provider
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Provider Plugin" check-box
  22 +
  23 +Varnish Settings
  24 +================
  25 +If varnish has been used in your stack, you've to prevent cookies to be removed when calling authorization actions for oauth_provider. E.g.:
  26 +
  27 +```
  28 +if (req.url !~ "^/plugin/oauth_provider/*" && req.http.cookie !~ "_noosfero_.*") {
  29 + unset req.http.cookie;
  30 + return(lookup);
  31 +}
  32 +```
  33 +
  34 +Development
  35 +===========
  36 +
  37 +Running OauthProvider tests
  38 +--------------------
  39 +
  40 +$ rake test:noosfero_plugins:oauth_provider
  41 +
  42 +License
  43 +=======
  44 +
  45 +Copyright (c) The Author developers.
  46 +
  47 +See Noosfero license.
... ...
plugins/oauth_provider/controllers/doorkeeper/application_controller.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +module Doorkeeper
  2 + class ApplicationController < ApplicationController
  3 +
  4 + include Helpers::Controller
  5 + helper 'doorkeeper/form_errors'
  6 +
  7 + end
  8 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_applications_controller.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class OauthProviderApplicationsController < Doorkeeper::ApplicationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 + def show
  7 + end
  8 +
  9 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_authorizations_controller.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class OauthProviderAuthorizationsController < Doorkeeper::AuthorizationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 + def index
  7 + end
  8 +
  9 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_authorized_applications_controller.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class OauthProviderAuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class OauthProviderPluginAdminController < AdminController
  2 +
  3 + def index
  4 + end
  5 +
  6 +end
... ...
plugins/oauth_provider/controllers/public/oauth_provider_plugin_public_controller.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class OauthProviderPluginPublicController < PublicController
  2 +
  3 + doorkeeper_for :me
  4 +
  5 + def me
  6 + user = environment.users.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
  7 + render :json => {:id =>user.login, :email => user.email}.to_json
  8 + end
  9 +
  10 +end
... ...
plugins/oauth_provider/db/migrate/20140829153047_create_doorkeeper_tables.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +class CreateDoorkeeperTables < ActiveRecord::Migration
  2 + def change
  3 + create_table :oauth_applications do |t|
  4 + t.string :name, null: false
  5 + t.string :uid, null: false
  6 + t.string :secret, null: false
  7 + t.text :redirect_uri, null: false
  8 + t.timestamps
  9 + end
  10 +
  11 + add_index :oauth_applications, :uid, unique: true
  12 +
  13 + create_table :oauth_access_grants do |t|
  14 + t.integer :resource_owner_id, null: false
  15 + t.integer :application_id, null: false
  16 + t.string :token, null: false
  17 + t.integer :expires_in, null: false
  18 + t.text :redirect_uri, null: false
  19 + t.datetime :created_at, null: false
  20 + t.datetime :revoked_at
  21 + t.string :scopes
  22 + end
  23 +
  24 + add_index :oauth_access_grants, :token, unique: true
  25 +
  26 + create_table :oauth_access_tokens do |t|
  27 + t.integer :resource_owner_id
  28 + t.integer :application_id
  29 + t.string :token, null: false
  30 + t.string :refresh_token
  31 + t.integer :expires_in
  32 + t.datetime :revoked_at
  33 + t.datetime :created_at, null: false
  34 + t.string :scopes
  35 + end
  36 +
  37 + add_index :oauth_access_tokens, :token, unique: true
  38 + add_index :oauth_access_tokens, :resource_owner_id
  39 + add_index :oauth_access_tokens, :refresh_token, unique: true
  40 + end
  41 +end
... ...
plugins/oauth_provider/lib/oauth_provider_plugin.rb 0 → 100644
... ... @@ -0,0 +1,55 @@
  1 +class OauthProviderPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + "Oauth Provider Plugin"
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("Oauth Provider.")
  9 + end
  10 +
  11 + def stylesheet?
  12 + true
  13 + end
  14 +
  15 + Doorkeeper.configure do
  16 + orm :active_record
  17 +
  18 + resource_owner_authenticator do
  19 + domain = Domain.find_by_name(request.host)
  20 + environment = domain ? domain.environment : Environment.default
  21 + environment.users.find_by_id(session[:user]) || redirect_to('/account/login')
  22 + end
  23 +
  24 + admin_authenticator do
  25 + domain = Domain.find_by_name(request.host)
  26 + environment = domain ? domain.environment : Environment.default
  27 + user = environment.users.find_by_id(session[:user])
  28 + unless user && user.person.is_admin?(environment)
  29 + redirect_to('/account/login')
  30 + end
  31 + user
  32 + end
  33 +
  34 + default_scopes :public
  35 + end
  36 +
  37 + Rails.configuration.to_prepare do
  38 + Rails.application.routes.prepend do
  39 + scope 'oauth_provider' do
  40 + use_doorkeeper do
  41 + controllers ({
  42 + :applications => 'oauth_provider_applications',
  43 + :authorized_applications => 'oauth_provider_authorized_applications',
  44 + :authorizations => 'oauth_provider_authorizations'
  45 + })
  46 + end
  47 + end
  48 + end
  49 + end
  50 +
  51 + SCOPE_TRANSLATION = {
  52 + 'public' => _('Access your public data')
  53 + }
  54 +
  55 +end
... ...
plugins/oauth_provider/public/style.css 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +.oauth-provider-authorize .actions form {
  2 + display: inline-block;
  3 +}
  4 +.oauth-provider-authorize .h4 {
  5 + font-size: 14px;
  6 + color: rgb(36, 36, 36)
  7 +}
  8 +.oauth-provider-authorize #oauth-permissions {
  9 + color: rgb(92, 92, 92);
  10 +}
  11 +.oauth-provider .actions {
  12 + margin-top: 10px;
  13 +}
... ...
plugins/oauth_provider/views/doorkeeper/applications/_delete_form.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%- submit_btn_css ||= 'btn btn-link' %>
  2 +<%= form_tag [:oauth, application] do %>
  3 + <input type="hidden" name="_method" value="delete">
  4 + <%= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css %>
  5 +<% end %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/_form.html.erb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +<%= form_for [:oauth, application], html: {class: 'form-horizontal', role: 'form'} do |f| %>
  2 + <% if application.errors.any? %>
  3 + <div class="alert alert-danger" data-alert>
  4 + <p><%= _('Whoops! Check your form for possible errors') %></p>
  5 + </div>
  6 + <% end %>
  7 +
  8 + <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do %>
  9 + <%= f.label :name, class: 'col-sm-2 control-label', for: 'application_name' %>
  10 + <div class="col-sm-10">
  11 + <%= f.text_field :name, class: 'form-control' %>
  12 + <%= doorkeeper_errors_for application, :name %>
  13 + </div>
  14 + <% end %>
  15 +
  16 + <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do %>
  17 + <%= f.label :redirect_uri, class: 'col-sm-2 control-label', for: 'application_redirect_uri' %>
  18 + <div class="col-sm-10">
  19 + <%= f.text_area :redirect_uri, class: 'form-control' %>
  20 + <%= doorkeeper_errors_for application, :redirect_uri %>
  21 + <span class="help-block">
  22 + <%= _('Use one line per URI') %>
  23 + </span>
  24 + <% if Doorkeeper.configuration.native_redirect_uri %>
  25 + <span class="help-block">
  26 + Use <code><%= Doorkeeper.configuration.native_redirect_uri %></code> for local tests
  27 + </span>
  28 + <% end %>
  29 + </div>
  30 + <% end %>
  31 +
  32 + <div class="form-group">
  33 + <div class="col-sm-offset-2 col-sm-10">
  34 + <%= f.submit _('Submit'), class: "btn btn-primary" %>
  35 + <%= link_to _("Cancel"), oauth_applications_path, :class => "btn btn-default" %>
  36 + </div>
  37 + </div>
  38 +<% end %>
  39 +
... ...
plugins/oauth_provider/views/doorkeeper/applications/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<div class="page-header">
  2 + <h1><%= _('Edit application') %></h1>
  3 +</div>
  4 +
  5 +<%= render 'form', application: @application %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/index.html.erb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="oauth-provider">
  2 +<div class="page-header">
  3 + <h3><%= link_to _('Oauh Provider'), '/admin/plugin/oauth_provider' %></h3>
  4 +</div>
  5 +
  6 +<p><%= link_to _('New Application'), new_oauth_application_path, class: 'btn btn-success' %></p>
  7 +
  8 +<table class="table table-striped">
  9 + <thead>
  10 + <tr>
  11 + <th><%= _('Name') %></th>
  12 + <th><%= _('Callback URL') %></th>
  13 + <th></th>
  14 + <th></th>
  15 + </tr>
  16 + </thead>
  17 + <tbody>
  18 + <% @applications.each do |application| %>
  19 + <tr id="application_<%= application.id %>">
  20 + <td><%= link_to application.name, [:oauth, application] %></td>
  21 + <td><%= application.redirect_uri %></td>
  22 + <td><%= link_to _('Edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
  23 + <td><%= render 'delete_form', application: application %></td>
  24 + </tr>
  25 + <% end %>
  26 + </tbody>
  27 +</table>
  28 +<div class="actions">
  29 + <%= button(:back, _('Go back'), {:controller => 'oauth_provider_plugin_admin', :action => 'index'}) %>
  30 +</div>
  31 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/applications/new.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<div class="page-header">
  2 + <h1>New application</h1>
  3 +</div>
  4 +
  5 +<%= render 'form', application: @application %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/show.html.erb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +<div class="page-header">
  2 + <h1><%= _('Application: %s' % @application.name) %></h1>
  3 +</div>
  4 +
  5 +<div class="row">
  6 + <div class="col-md-8">
  7 + <h4><%= _('Application Id:') %></h4>
  8 +
  9 + <p><code id="application_id"><%= @application.uid %></code></p>
  10 +
  11 + <h4><%= _('Secret:') %></h4>
  12 +
  13 + <p><code id="secret"><%= @application.secret %></code></p>
  14 +
  15 + <h4><%= _('Callback urls:') %></h4>
  16 +
  17 + <table>
  18 + <% @application.redirect_uri.split.each do |uri| %>
  19 + <tr>
  20 + <td>
  21 + <code><%= uri %></code>
  22 + </td>
  23 + <td>
  24 + </td>
  25 + </tr>
  26 + <% end %>
  27 + </table>
  28 + </div>
  29 +
  30 + <div class="col-md-4">
  31 + <h3><%= _('Actions') %></h3>
  32 +
  33 + <p>
  34 + <%= link_to _('Edit'), edit_oauth_application_path(@application), class: 'btn btn-primary' %>
  35 + <%= link_to _("Cancel"), oauth_applications_path, :class => "btn btn-default" %>
  36 + </p>
  37 +
  38 + <p><%= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger' %></p>
  39 + </div>
  40 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/error.html.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<div class="page-header">
  2 + <h1>An error has occurred</h1>
  3 +</div>
  4 +
  5 +<main role="main">
  6 + <pre><%= @pre_auth.error_response.body[:error_description] %></pre>
  7 +</main>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/new.html.erb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +<div class="oauth-provider-authorize">
  2 +
  3 +<header class="page-header" role="banner">
  4 + <h1><%= _('Authorize required') %></h1>
  5 +</header>
  6 +
  7 +<main role="main">
  8 + <p class="h4">
  9 + <%= _('Authorize %s to use your account?' % "<strong class=\"text-info\">#{@pre_auth.client.name}</strong>") %>
  10 + </p>
  11 +
  12 + <% if @pre_auth.scopes %>
  13 + <div id="oauth-permissions">
  14 + <p><%= _('This application will be able to:') %></p>
  15 +
  16 + <ul class="text-info">
  17 + <% @pre_auth.scopes.each do |scope| %>
  18 + <li><%= OauthProviderPlugin::SCOPE_TRANSLATION[scope] %></li>
  19 + <% end %>
  20 + </ul>
  21 + </div>
  22 + <% end %>
  23 +
  24 + <div class="actions">
  25 + <%= form_tag oauth_authorization_path, method: :post do %>
  26 + <%= hidden_field_tag :client_id, @pre_auth.client.uid %>
  27 + <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
  28 + <%= hidden_field_tag :state, @pre_auth.state %>
  29 + <%= hidden_field_tag :response_type, @pre_auth.response_type %>
  30 + <%= hidden_field_tag :scope, @pre_auth.scope %>
  31 + <%= submit_button :ok, _("Authorize") %>
  32 + <% end %>
  33 + <%= form_tag oauth_authorization_path, method: :delete do %>
  34 + <%= hidden_field_tag :client_id, @pre_auth.client.uid %>
  35 + <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
  36 + <%= hidden_field_tag :state, @pre_auth.state %>
  37 + <%= hidden_field_tag :response_type, @pre_auth.response_type %>
  38 + <%= hidden_field_tag :scope, @pre_auth.scope %>
  39 + <%= submit_button :cancel, _("Deny") %>
  40 + <% end %>
  41 + </div>
  42 +</main>
  43 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/show.html.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<header class="page-header">
  2 + <h1>Authorization code:</h1>
  3 +</header>
  4 +
  5 +<main role="main">
  6 + <code id="authorization_code"><%= params[:code] %></code>
  7 +</main>
... ...
plugins/oauth_provider/views/doorkeeper/authorized_applications/_delete_form.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%- submit_btn_css ||= 'btn btn-link' %>
  2 +<%= form_tag oauth_authorized_application_path(application) do %>
  3 + <input type="hidden" name="_method" value="delete">
  4 + <%= submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: submit_btn_css %>
  5 +<% end %>
... ...
plugins/oauth_provider/views/doorkeeper/authorized_applications/index.html.erb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="oauth-provider">
  2 +<header class="page-header">
  3 + <h1>Your authorized applications</h1>
  4 +</header>
  5 +
  6 +<main role="main">
  7 + <table class="table table-striped">
  8 + <thead>
  9 + <tr>
  10 + <th>Application</th>
  11 + <th>Created At</th>
  12 + <th></th>
  13 + <th></th>
  14 + </tr>
  15 + </thead>
  16 + <tbody>
  17 + <% @applications.each do |application| %>
  18 + <tr>
  19 + <td><%= application.name %></td>
  20 + <td><%= application.created_at.strftime('%Y-%m-%d %H:%M:%S') %></td>
  21 + <td><%= render 'delete_form', application: application %></td>
  22 + </tr>
  23 + <% end %>
  24 + </tbody>
  25 + </table>
  26 +</main>
  27 +
  28 +<div class="actions">
  29 + <%= button(:back, _('Go back'), :back) %>
  30 +</div>
  31 +</div>
... ...
plugins/oauth_provider/views/oauth_provider_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +<div class="oauth-provider">
  2 +<h3><%= _('Oauh Provider') %></h3>
  3 +
  4 + <div class="applications">
  5 + <%= link_to _('Applications'), oauth_applications_path %>
  6 + </div>
  7 + <div class="authorized-applications">
  8 + <%= link_to _('Authorized Applications'), oauth_authorized_applications_path %>
  9 + </div>
  10 +
  11 + <div class="actions">
  12 + <%= button(:back, _('Go back'), {:controller => 'plugins', :action => 'index'}) %>
  13 + </div>
  14 +</div>
... ...