exvo_auth 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ coverage/*
6
+ pkg/*
7
+ log/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in exvo_auth.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright © 2011-2012 Exvo.com Development BV
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.
@@ -0,0 +1,245 @@
1
+ # exvo_auth
2
+
3
+ This gem supplements the [omniauth-exvo](https://github.com/Exvo/omniauth-exvo/) gem. Together they implement the oauth2 protocol for handling users and applications authentication at Exvo.
4
+
5
+ This gem depends on the [exvo_helpers](https://github.com/Exvo/exvo_helpers) gem for all of its configuration.
6
+
7
+
8
+ Note, that this gem was previously named "exvo-auth".
9
+
10
+
11
+
12
+ ## Requirements
13
+
14
+ * Runs on Ruby 1.8.7 & 1.9.2 (preferred version)
15
+ * Rails 3.0+ (works with Rails 3.1) or Merb
16
+
17
+
18
+
19
+ ## Installation
20
+
21
+ Add it to Gemfile:
22
+
23
+ ```ruby
24
+ gem "exvo_auth"
25
+ ```
26
+
27
+ Run bundle:
28
+
29
+ ```bash
30
+ $ bundle
31
+ ```
32
+
33
+ The preferred way to configure this gem is via the ENV variables:
34
+
35
+ ```ruby
36
+ ENV['AUTH_CLIENT_ID'] = "foo"
37
+ ENV['AUTH_CLIENT_SECRET'] = "bar"
38
+ ENV['AUTH_DEBUG'] = "true" # [OPTIONAL] dumps all HTTP traffic to STDERR, useful during development; it *has to be a string, not a boolean*
39
+ ENV['AUTH_REQUIRE_SSL'] = "false" # [OPTIONAL] disable SSL, useful in development (note that all apps API urls must be http, not https); it *has to be a string, not a boolean*
40
+ ENV['AUTH_HOST'] = "test.exvo.com" # [OPTIONAL] override the default auth host
41
+ ```
42
+
43
+ But you can also set things directly in the `config/application.rb` file (before the middleware declaration):
44
+
45
+ ```ruby
46
+ Exvo::Helpers.auth_client_id = "foo"
47
+ Exvo::Helpers.auth_client_secret = "bar"
48
+ Exvo::Helpers.auth_debug = true # boolean
49
+ Exvo::Helpers.auth_require_ssl = false # boolean
50
+ Exvo::Helpers.auth_host = "test.exvo.com"
51
+ ```
52
+
53
+ Add this line to `config/application.rb`:
54
+
55
+ ```ruby
56
+ config.middleware.use ExvoAuth::Middleware
57
+ ```
58
+
59
+ Add routes (Rails example):
60
+
61
+ ```ruby
62
+ match "/auth/exvo/callback" => "sessions#create"
63
+ match "/auth/failure" => "sessions#failure"
64
+ match "/sign_out" => "sessions#destroy"
65
+ ```
66
+
67
+ Include controller helpers in your `ApplicationController.rb`:
68
+
69
+ ```ruby
70
+ include ExvoAuth::Controllers::Rails # (or Merb)
71
+ ```
72
+
73
+ Implement a sessions controller (Rails example):
74
+
75
+ ```ruby
76
+ class SessionsController < ApplicationController
77
+ def create
78
+ sign_in_and_redirect!
79
+ end
80
+
81
+ def destroy
82
+ sign_out_and_redirect!
83
+ end
84
+
85
+ def failure
86
+ render :text => "Sorry!"
87
+ end
88
+ end
89
+ ```
90
+
91
+ It's good to have your `SessionsController`'s `#create` action a little more extended, so that each time the user logs in into the app, his user data (like email, nickname, etc.) is updated from the auth app (i.e. from his profile):
92
+
93
+ ```ruby
94
+ def create
95
+ auth_hash = request.env["omniauth.auth"]
96
+ user = User.find_or_create_by_uid(auth_hash["uid"])
97
+
98
+ if user && user.update_from_auth_hash(auth_hash)
99
+ sign_in_and_redirect!
100
+ else
101
+ fail "Could not update user"
102
+ end
103
+ end
104
+ ```
105
+
106
+ and your `#update_from_auth_hash` method at `User` model might look like this:
107
+
108
+ ```ruby
109
+ def update_from_auth_hash(auth_hash)
110
+ update_attributes({
111
+ :nickname => auth_hash["info"]["nickname"],
112
+ :email => auth_hash["info"]["email"],
113
+ :plan => auth_hash["extra"]["raw_info"]["plan"],
114
+ :language => auth_hash["extra"]["raw_info"]["language"]
115
+ })
116
+ end
117
+ ```
118
+
119
+ Note, that you don't have to update all user attributes. You can update only ones you want.
120
+
121
+
122
+ This is what you get (and what you can use/save for the local user) from auth (example data as of 2012-01):
123
+
124
+ ```ruby
125
+ request.env["omniauth.auth"].to_hash.inspect
126
+
127
+ {
128
+ "provider" => "exvo",
129
+ "uid" => 1,
130
+
131
+ "credentials" => {
132
+ "token" => "a2d09701559b9f26a8284d6f94670477d882ad6d9f3d92ce9917262a6b54085fa3fb99e111340459",
133
+ "expires" => false
134
+ },
135
+
136
+ "info" => {
137
+ "nickname" => "Pawel",
138
+ "email" => "pawel@exvo.com",
139
+ "name" => "Pawel"
140
+ },
141
+
142
+ "extra" => {
143
+ "raw_info" => {
144
+ "id" => 1,
145
+ "nickname" => "Pawel",
146
+ "country_code" => nil,
147
+ "plan" => "basic",
148
+ "language" => "en",
149
+ "email" => "pawel@exvo.com",
150
+ "referring_user_id" => nil
151
+ }
152
+ }
153
+ }
154
+ ```
155
+
156
+
157
+ Implement `#find_or_create_user_by_uid(uid)` in your `ApplicationController`:
158
+
159
+ This method will be called by `#current_user`. Previously we did this in `sessions_controller` but since the sharing sessions changes this controller will not be used in most cases because the session comes from another app through a shared cookie. This method should find user by uid or create it.
160
+
161
+ Exemplary implementation (Rails):
162
+
163
+ ```ruby
164
+ def find_or_create_user_by_uid(uid)
165
+ User.find_or_create_by_uid(uid)
166
+ end
167
+ ```
168
+
169
+ It's best to leave this method as it is (without updating any user data inside this method, better to do this in the SessionsController#create action). Updating user in this method might lead to some very hard to debug cyclic executions possibly leading to stack-level too deep errors and/or general slowness, so please proceed with extreme caution.
170
+
171
+
172
+ ## Sign up and sign in paths for use in links
173
+
174
+ ```ruby
175
+ sign in path: "/auth/exvo"
176
+ sign up path: "/auth/exvo?x_sign_up=true" # this is OAuth2 custom param
177
+ sign in path with a return address: "/auth/exvo?state=url" # using OAuth2 state param
178
+ ```
179
+
180
+ You have a handy methods available in controllers (and views in Rails): `sign_in_path` and `sign_up_path`.
181
+
182
+
183
+ ## Require authentication in your controllers
184
+
185
+ In `ApplicationController` (for all controllers) or in some controller just add:
186
+
187
+ ```ruby
188
+ before_filter :authenticate_user!
189
+ ```
190
+
191
+ ## Fetching user information
192
+
193
+ All info about any particular user can be obtained using auth api (`/users/uid.json` path).
194
+
195
+
196
+
197
+ ## Inter-Application Communication
198
+
199
+ You need to have "App Authorization" created by Exvo first.
200
+
201
+ Contact us and provide following details:
202
+
203
+ * `consumer_id` - Id of an app that will be a consumer (this is you)
204
+ * `provider_id` - Id of the provider app
205
+ * `scope` - The tag associated with the api you want to use in the provider app
206
+
207
+
208
+ ### Consumer side
209
+
210
+ ```ruby
211
+ consumer = ExvoAuth::Autonomous::Consumer.new(
212
+ :app_id => "this is client_id of the app you want to connect to"
213
+ )
214
+ consumer.get(*args) # interface is exactly the same like in HTTParty. All http methods are available (post, put, delete, head, options).
215
+ ```
216
+
217
+
218
+ ### Provider side
219
+
220
+ See `#authenticate_app_in_scope!(scope)` method in `ExvoAuth::Controllers::Rails` (or Merb). This method lets you create a before filter.
221
+ Scopes are used by providing app to check if a given consuming app should have access to a given resource inside a scope.
222
+ If scopes are empty, then provider app should not present any resources to consumer.
223
+
224
+
225
+ Example of the before filter for provider controller:
226
+
227
+ ```ruby
228
+ before_filter { |c| c.authenticate_app_in_scope!("payments") }
229
+ ```
230
+
231
+ In the provider controller, which is just a fancy name for API controller, you can use `#current_app_id` method to get the `app_id` of the app connecting.
232
+
233
+
234
+ ## Dejavu
235
+
236
+ Replay non-GET requests after authentication redirects.
237
+
238
+ Limitations:
239
+
240
+ * doesn't work with file uploads
241
+ * all request params become query params when replayed
242
+
243
+
244
+
245
+ Copyright © 2011-2012 Exvo.com Development BV, released under the MIT license
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'lib' << 'test'
8
+ test.pattern = 'test/**/test_*.rb'
9
+ test.verbose = true
10
+ end
11
+ task :default => :test
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "exvo_auth/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "exvo_auth"
7
+ gem.version = ExvoAuth::VERSION
8
+ gem.authors = ["Jacek Becela", "Paweł Gościcki"]
9
+ gem.email = ["jacek.becela@gmail.com", "pawel.goscicki@gmail.com"]
10
+ gem.homepage = "https://github.com/Exvo/exvo_auth"
11
+ gem.summary = "User and App authentication for Exvo"
12
+ gem.description = "Collection of users and applications authentication methods for use when you want your users or applications authorize using the Exvo platform."
13
+
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency "httparty"
20
+ gem.add_dependency "activemodel", "~> 3.0"
21
+ gem.add_dependency "actionpack", "~> 3.0"
22
+ gem.add_dependency "exvo_helpers", "~> 0.2"
23
+
24
+ gem.add_development_dependency "mocha"
25
+ gem.add_development_dependency "test-unit"
26
+ gem.add_development_dependency "rake"
27
+ gem.add_development_dependency "guard"
28
+ gem.add_development_dependency "guard-test"
29
+ gem.add_development_dependency "rb-fsevent"
30
+ gem.add_development_dependency "rb-inotify"
31
+ gem.add_development_dependency "simplecov"
32
+ gem.add_development_dependency "simplecov-rcov"
33
+ end
@@ -0,0 +1,31 @@
1
+ require 'multi_json'
2
+ require 'httparty'
3
+ require 'uri'
4
+ require 'base64'
5
+ require 'exvo_helpers'
6
+
7
+ module ExvoAuth
8
+ autoload :Middleware, 'exvo_auth/middleware'
9
+ autoload :SessionStore, 'exvo_auth/session_store'
10
+ autoload :Dejavu, 'exvo_auth/dejavu'
11
+ autoload :VERSION, 'exvo_auth/version'
12
+
13
+ module Controllers
14
+ autoload :Base, 'exvo_auth/controllers/base'
15
+ autoload :Rails, 'exvo_auth/controllers/rails'
16
+ autoload :Merb, 'exvo_auth/controllers/merb'
17
+ end
18
+
19
+ module Models
20
+ autoload :Message, 'exvo_auth/models/message'
21
+ end
22
+
23
+ module Autonomous
24
+ autoload :Base, 'exvo_auth/autonomous/base'
25
+ autoload :Consumer, 'exvo_auth/autonomous/consumer'
26
+ autoload :Provider, 'exvo_auth/autonomous/provider'
27
+ autoload :Cache, 'exvo_auth/autonomous/cache'
28
+ autoload :Auth, 'exvo_auth/autonomous/auth'
29
+ autoload :Http, 'exvo_auth/autonomous/http'
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ require 'singleton'
2
+
3
+ class ExvoAuth::Autonomous::Auth
4
+ include Singleton
5
+ include ExvoAuth::Autonomous::Http
6
+
7
+ def base_uri
8
+ Exvo::Helpers.auth_uri
9
+ end
10
+
11
+ def username
12
+ Exvo::Helpers.auth_client_id
13
+ end
14
+
15
+ def password
16
+ Exvo::Helpers.auth_client_secret
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ class ExvoAuth::Autonomous::Base
2
+ attr_reader :params
3
+ @@cache = ExvoAuth::Autonomous::Cache.new
4
+
5
+ def initialize(params = {})
6
+ @params = params
7
+ end
8
+
9
+ protected
10
+
11
+ def validate_params!(*keys)
12
+ missing = keys - params.keys
13
+ raise(ArgumentError, "Please configure following keys: #{missing.join(", ")}") if missing.any?
14
+ end
15
+
16
+ # Makes testing easy
17
+ def auth
18
+ ExvoAuth::Autonomous::Auth.instance
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ class ExvoAuth::Autonomous::Cache
2
+ def initialize
3
+ @data = {}
4
+ end
5
+
6
+ def read(key)
7
+ o = @data[key]
8
+ o[:value] if o && (now - o[:timestamp]) < 3600 # cache for one hour
9
+ end
10
+
11
+ def write(key, value)
12
+ @data[key] = {
13
+ :value => value,
14
+ :timestamp => now
15
+ }
16
+
17
+ value
18
+ end
19
+
20
+ def fetch(key)
21
+ if block_given?
22
+ read(key) || write(key, yield)
23
+ else
24
+ read(key)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def now
31
+ Time.now
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ class ExvoAuth::Autonomous::Consumer < ExvoAuth::Autonomous::Base
2
+ include ExvoAuth::Autonomous::Http
3
+
4
+ def initialize(params = {})
5
+ super
6
+ validate_params!(:app_id)
7
+ end
8
+
9
+ def base_uri
10
+ authorization["url"]
11
+ end
12
+
13
+ def username
14
+ Exvo::Helpers.auth_client_id
15
+ end
16
+
17
+ def password
18
+ authorization["access_token"]
19
+ end
20
+
21
+ def authorization
22
+ @@cache.fetch(params) do
23
+ authorization!
24
+ end
25
+ end
26
+
27
+ def authorization!
28
+ response = auth.get("/apps/consumer/authorizations/#{URI.escape(params[:app_id])}.json")
29
+
30
+ if response["authorization"]
31
+ @@cache.write(params, response["authorization"])
32
+ else
33
+ raise "Authorization not found. You need an auhorization to contact provider app (#{ params[:app_id] })"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,43 @@
1
+ module ExvoAuth::Autonomous::Http
2
+ def get(*args)
3
+ http.get(*args)
4
+ end
5
+
6
+ def post(*args)
7
+ http.post(*args)
8
+ end
9
+
10
+ def put(path, options = {})
11
+ # This fixes 411 responses from nginx (on heroku)
12
+ # when Content-Length is missing on put requests.
13
+ options[:body] ||= ""
14
+ http.put(path, options)
15
+ end
16
+
17
+ def delete(*args)
18
+ http.delete(*args)
19
+ end
20
+
21
+ def head(*args)
22
+ http.head(*args)
23
+ end
24
+
25
+ def options(*args)
26
+ http.options(*args)
27
+ end
28
+
29
+ protected
30
+
31
+ def http
32
+ basement.base_uri(base_uri)
33
+ basement.basic_auth(username, password)
34
+ basement
35
+ end
36
+
37
+ def basement
38
+ @basement ||= Class.new do
39
+ include HTTParty
40
+ debug_output if Exvo::Helpers.auth_debug
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ class ExvoAuth::Autonomous::Provider < ExvoAuth::Autonomous::Base
2
+ def initialize(params = {})
3
+ super
4
+ validate_params!(:app_id, :access_token)
5
+ end
6
+
7
+ def scopes
8
+ @@cache.fetch(params) do
9
+ scopes!
10
+ end
11
+ end
12
+
13
+ def scopes!
14
+ response = auth.get("/apps/provider/authorizations/#{URI.escape(params[:app_id])}.json",
15
+ :query => { :access_token => params[:access_token] }
16
+ )
17
+
18
+ if scope = response["scope"]
19
+ @@cache.write(params, scope.split)
20
+ else
21
+ [] # only cache positive responses
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,123 @@
1
+ module ExvoAuth::Controllers::Base
2
+ # A before filter to protect your sensitive actions.
3
+ def authenticate_user!(opts = {})
4
+ if !signed_in?
5
+ store_request!
6
+
7
+ callback_value = params[callback_key]
8
+
9
+ if callback_value
10
+ redirect_to non_interactive_sign_in_path(callback_key => callback_value)
11
+ else
12
+ redirect_to opts[:redirect_to] || sign_in_path
13
+ end
14
+ end
15
+ end
16
+
17
+ # Usually this method is called from your sessions#create.
18
+ def sign_in_and_redirect!
19
+ session[:user_uid] = request.env["omniauth.auth"]["uid"]
20
+
21
+ url = if params[:state] == "popup"
22
+ Exvo::Helpers..auth_uri + "/close_popup.html"
23
+ elsif params[:state] # if not popup then an url
24
+ params[:state]
25
+ else
26
+ request_replay_url || "/"
27
+ end
28
+
29
+ redirect_to url
30
+ end
31
+
32
+ # Redirect to sign_out_url, signs out and redirects back to "/" (by default).
33
+ # Usuallly this method is called from your sessions#destroy.
34
+ def sign_out_and_redirect!(return_to = "/")
35
+ session.clear
36
+ remove_instance_variable(:@current_user) if instance_variable_defined?(:@current_user)
37
+ redirect_to sign_out_url(return_to)
38
+ end
39
+
40
+ def authenticate_app_in_scope!(scope)
41
+ raise("SSL not configured. Your api needs to be exposed using https protocol.") unless request.ssl? || Exvo::Helpers.auth_require_ssl == false
42
+
43
+ send(basic_authentication_method_name) do |app_id, access_token|
44
+ current_scopes = ExvoAuth::Autonomous::Provider.new(
45
+ :app_id => app_id,
46
+ :access_token => access_token
47
+ ).scopes
48
+
49
+ @current_app_id = app_id
50
+
51
+ current_scopes.include?(scope.to_s)
52
+ end
53
+ end
54
+
55
+ def sign_in_path
56
+ "/auth/exvo"
57
+ end
58
+
59
+ def sign_up_path
60
+ "/auth/exvo?x_sign_up=true"
61
+ end
62
+
63
+ def callback_key
64
+ "_callback"
65
+ end
66
+
67
+ def current_user
68
+ return @current_user unless @current_user.nil?
69
+ @current_user = session[:user_uid] && find_or_create_user_by_uid(session[:user_uid])
70
+ end
71
+
72
+ def current_app_id
73
+ @current_app_id
74
+ end
75
+
76
+ def signed_in?
77
+ !!current_user
78
+ end
79
+
80
+ protected
81
+
82
+ def find_or_create_user_by_uid(uid)
83
+ raise "Implement find_or_create_user_by_uid in a controller"
84
+ end
85
+
86
+ def sign_out_url(return_to)
87
+ Exvo::Helpers.auth_uri + "/users/sign_out?" + Rack::Utils.build_query({ :return_to => return_to })
88
+ end
89
+
90
+ def non_interactive_sign_in_path(params = {})
91
+ path = "/auth/exvo"
92
+ query = Rack::Utils.build_query(params)
93
+ query.empty? ? path : "#{path}?#{query}"
94
+ end
95
+
96
+ def current_request
97
+ request.params.reject{ |k, v| ["controller", "action"].include?(k) || v.nil? }.merge(
98
+ :_dejavu => {
99
+ :script_name => request.script_name, # for Rack::Request
100
+ :path_info => request.path_info, # for Rack::Request
101
+ :request_path => request.path, # for Merb::Request
102
+ :method => request_method,
103
+ :content_type => request.content_type
104
+ }
105
+ )
106
+ end
107
+
108
+ def store_request!
109
+ session[:stored_request] = Base64.encode64(MultiJson.encode(current_request))
110
+ end
111
+
112
+ def request_replay_url
113
+ if stored_request = session.delete(:stored_request)
114
+ params = MultiJson.decode(Base64.decode64(stored_request))
115
+ dejavu = params.delete("_dejavu")
116
+ if dejavu["method"] == "GET"
117
+ dejavu["script_name"] + dejavu["path_info"] + (params.any? ? "?" + Rack::Utils.build_nested_query(params) : "")
118
+ else
119
+ "/auth/dejavu?" + Rack::Utils.build_nested_query(params.merge(:_dejavu => dejavu))
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,27 @@
1
+ module ExvoAuth::Controllers::Merb
2
+ def self.included(base)
3
+ base.send :include, ExvoAuth::Controllers::Base
4
+ base.send :include, InstanceMethods
5
+ end
6
+
7
+ module InstanceMethods
8
+ def authenticate_user!
9
+ super
10
+ throw :halt unless signed_in?
11
+ end
12
+
13
+ protected
14
+
15
+ def request_method
16
+ request.method.to_s.upcase
17
+ end
18
+
19
+ def basic_authentication_method_name
20
+ :basic_authentication
21
+ end
22
+
23
+ def redirect_to(*args)
24
+ redirect(*args)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module ExvoAuth::Controllers::Rails
2
+ def self.included(base)
3
+ base.send :include, ExvoAuth::Controllers::Base
4
+ base.send :include, InstanceMethods
5
+ base.helper_method :current_user, :signed_in?, :sign_up_path, :sign_in_path
6
+ end
7
+
8
+ module InstanceMethods
9
+ protected
10
+
11
+ def request_method
12
+ request.request_method
13
+ end
14
+
15
+ def basic_authentication_method_name
16
+ :authenticate_or_request_with_http_basic
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ class ExvoAuth::Dejavu
2
+ def initialize(app)
3
+ @app = app
4
+ end
5
+
6
+ def call(env)
7
+ dejavu(env) if Rack::Request.new(env).path == "/auth/dejavu"
8
+ @app.call(env)
9
+ end
10
+
11
+ private
12
+
13
+ def dejavu(env)
14
+ params = Rack::Request.new(env).params
15
+ dejavu = params.delete("_dejavu")
16
+
17
+ env["QUERY_STRING"] = Rack::Utils.build_nested_query(params) # Will not work with file uploads.
18
+ env["SCRIPT_NAME"] = dejavu["script_name"] # for Rack::Request
19
+ env["PATH_INFO"] = dejavu["path_info"] # for Rack::Request
20
+ env["REQUEST_PATH"] = dejavu["request_path"] # for Merb::Request
21
+ env["REQUEST_METHOD"] = dejavu["method"]
22
+ env["CONTENT_TYPE"] = dejavu["content_type"]
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ class ExvoAuth::Middleware
2
+ def initialize(app)
3
+ @app = middlewares.inject(app){ |a, m| a = m.new(a) }
4
+ end
5
+
6
+ def call(env)
7
+ @app.call(env)
8
+ end
9
+
10
+ private
11
+
12
+ def middlewares
13
+ [ExvoAuth::Dejavu]
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ class ExvoAuth::Models::Message
2
+ include ActiveModel::Validations
3
+ include ActiveModel::Serialization
4
+
5
+ class RecordInvalid < StandardError; end
6
+ class RecordNotFound < StandardError; end
7
+
8
+ validates :label, :presence => true, :format => /^[_a-z0-9]+$/ix
9
+ validates :text, :presence => true
10
+ validates :user_uid, :presence => true, :numericality => true
11
+
12
+ attr_accessor :id, :label, :text, :user_uid, :created_at, :read
13
+
14
+ def initialize(attributes = {})
15
+ attributes.each do |name, value|
16
+ send("#{name}=", value)
17
+ end
18
+ end
19
+
20
+ def self.create(attributes = {})
21
+ message = new(attributes)
22
+ if message.valid?
23
+ message.deliver
24
+ message
25
+ else
26
+ raise RecordInvalid, message.errors.full_messages.join(", ")
27
+ end
28
+ end
29
+
30
+ def self.all
31
+ auth = ExvoAuth::Autonomous::Auth.instance
32
+ response = auth.get("/api/private/app_messages.json")
33
+ response.map{ |m| new(m) }
34
+ end
35
+
36
+ def self.find(id)
37
+ auth = ExvoAuth::Autonomous::Auth.instance
38
+ response = auth.get("/api/private/app_messages/#{id}.json")
39
+ if response.code == 200
40
+ new(response)
41
+ else
42
+ raise RecordNotFound, "Couldn't find #{model_name} with ID=#{id}"
43
+ end
44
+ end
45
+
46
+ def deliver
47
+ auth = ExvoAuth::Autonomous::Auth.instance
48
+ attributes = {
49
+ :label => label,
50
+ :text => text,
51
+ :user_uid => user_uid
52
+ }
53
+ response = auth.post("/api/private/app_messages.json", :body => attributes)
54
+ case response.code
55
+ when 201 then
56
+ response.parsed_response.each do |k, v|
57
+ send("#{k}=", v)
58
+ end
59
+ when 422 then
60
+ response.parsed_response.each{ |attr, error| errors.add(attr, error) }
61
+ raise RecordInvalid, errors.full_messages.join(", ")
62
+ else
63
+ raise "Unknown error"
64
+ end
65
+
66
+ end
67
+
68
+ def persisted?
69
+ !!id
70
+ end
71
+
72
+ end
@@ -0,0 +1,37 @@
1
+ require "action_dispatch"
2
+ require 'active_support/core_ext/hash/reverse_merge'
3
+
4
+ # For Merb apps only. This replaces merb sessions with Rails3 sessions. We use this to share sessions between merb and rails apps.
5
+ class ExvoAuth::SessionStore
6
+ def initialize(app, options = {})
7
+ raise "Please configure :secret_token" unless @secret_token = options[:secret_token]
8
+ raise "Please configure :domain" unless @domain = options[:domain]
9
+
10
+ @app = ActionDispatch::Cookies.new(ActionDispatch::Session::CookieStore.new(ActionDispatch::Flash.new(app), :key => "_exvo_session", :domain => @domain, :expire_after => 2.weeks))
11
+ end
12
+ def call(env)
13
+ @app.call(env.reverse_merge!(env_defaults))
14
+ end
15
+ def env_defaults
16
+ @env_defaults ||= {
17
+ "action_dispatch.secret_token" => @secret_token
18
+ }
19
+ end
20
+ def self.replace_merb_sessions_with_rails_3_sessions! # this is crazy
21
+ [Merb::BootLoader::MixinSession, Merb::BootLoader::SetupSession, Merb::BootLoader::Cookies].each do |c|
22
+ c.class_eval do
23
+ def self.run; end
24
+ end
25
+ end
26
+ Merb::Controller.class_eval do
27
+ def session; request.session end
28
+ def cookies; request.env["action_dispatch.cookies"] ||= ActionDispatch::Cookies::CookieJar.build(request) end
29
+ end
30
+ Merb::Request.class_eval do
31
+ def session?; true end
32
+ def session; Rack::Request.new(env).session end
33
+ def cookies; Rack::Request.new(env).cookies end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,3 @@
1
+ module ExvoAuth
2
+ VERSION = "0.15.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'simplecov'
2
+ require 'simplecov-rcov'
3
+ SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
4
+ SimpleCov.start
5
+
6
+ require 'rubygems'
7
+ require 'test/unit'
8
+ require 'mocha'
9
+ require 'exvo_auth'
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ class TestExvoAuth < Test::Unit::TestCase
4
+ def setup
5
+ Exvo::Helpers.auth_client_id = "foo"
6
+ Exvo::Helpers.auth_client_secret = "bar"
7
+ end
8
+
9
+ test "consumer sanity" do
10
+ c = ExvoAuth::Autonomous::Consumer.new(:app_id => "baz")
11
+ authorization = { "access_token" => "qux", "url" => "https://foo/api" }
12
+ auth = stub(:get => { "authorization" => authorization })
13
+ c.expects(:auth).returns(auth)
14
+
15
+ assert_equal authorization, c.send(:authorization)
16
+ assert_equal authorization, c.send(:authorization) # second time from cache, without touching httparty
17
+ end
18
+
19
+ test "provider sanity" do
20
+ p = ExvoAuth::Autonomous::Provider.new(:app_id => "baz", :access_token => "qux")
21
+ auth = stub(:get => {"scope" => "qux quux"})
22
+ p.expects(:auth).returns(auth)
23
+
24
+ assert_equal ["qux", "quux"], p.scopes
25
+ assert_equal ["qux", "quux"], p.scopes # second time from cache, without touching httparty
26
+ end
27
+
28
+ test "integration of httparty interface with auth" do
29
+ c = ExvoAuth::Autonomous::Consumer.new(:app_id => "baz")
30
+ basement = mock("basement")
31
+ basement.expects(:base_uri)
32
+ basement.expects(:basic_auth)
33
+ basement.expects(:get).with("/bar").returns(true)
34
+ c.expects(:basement).at_least_once.returns(basement)
35
+ assert_true c.get("/bar")
36
+ end
37
+
38
+ test "basement includes httparty" do
39
+ c = ExvoAuth::Autonomous::Consumer.new(:app_id => "baz")
40
+ assert_true c.send(:basement).included_modules.include?(HTTParty)
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ require 'helper'
2
+
3
+ class TestIntegration < Test::Unit::TestCase
4
+ def setup
5
+ Exvo::Helpers.auth_host = "staging.auth.exvo.com"
6
+ Exvo::Helpers.auth_client_id = "foo"
7
+ Exvo::Helpers.auth_client_secret = "bar"
8
+ Exvo::Helpers.auth_require_ssl = true
9
+ end
10
+
11
+ test "integration with staging.auth.exvo.com" do
12
+ c = ExvoAuth::Autonomous::Consumer.new(:app_id => "bar")
13
+ authorization = c.send(:authorization)
14
+ assert authorization["access_token"].size > 0
15
+ assert_equal "https://bar/api", authorization["url"]
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exvo_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.15.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jacek Becela
9
+ - Paweł Gościcki
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-01-26 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: httparty
17
+ requirement: &77112060 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *77112060
26
+ - !ruby/object:Gem::Dependency
27
+ name: activemodel
28
+ requirement: &77110930 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *77110930
37
+ - !ruby/object:Gem::Dependency
38
+ name: actionpack
39
+ requirement: &77108390 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '3.0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *77108390
48
+ - !ruby/object:Gem::Dependency
49
+ name: exvo_helpers
50
+ requirement: &77089050 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '0.2'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *77089050
59
+ - !ruby/object:Gem::Dependency
60
+ name: mocha
61
+ requirement: &77087470 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *77087470
70
+ - !ruby/object:Gem::Dependency
71
+ name: test-unit
72
+ requirement: &77086220 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *77086220
81
+ - !ruby/object:Gem::Dependency
82
+ name: rake
83
+ requirement: &77085280 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *77085280
92
+ - !ruby/object:Gem::Dependency
93
+ name: guard
94
+ requirement: &77082500 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: *77082500
103
+ - !ruby/object:Gem::Dependency
104
+ name: guard-test
105
+ requirement: &77030890 !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: *77030890
114
+ - !ruby/object:Gem::Dependency
115
+ name: rb-fsevent
116
+ requirement: &76952630 !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ type: :development
123
+ prerelease: false
124
+ version_requirements: *76952630
125
+ - !ruby/object:Gem::Dependency
126
+ name: rb-inotify
127
+ requirement: &76941060 !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: *76941060
136
+ - !ruby/object:Gem::Dependency
137
+ name: simplecov
138
+ requirement: &76936810 !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: *76936810
147
+ - !ruby/object:Gem::Dependency
148
+ name: simplecov-rcov
149
+ requirement: &76882790 !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ type: :development
156
+ prerelease: false
157
+ version_requirements: *76882790
158
+ description: Collection of users and applications authentication methods for use when
159
+ you want your users or applications authorize using the Exvo platform.
160
+ email:
161
+ - jacek.becela@gmail.com
162
+ - pawel.goscicki@gmail.com
163
+ executables: []
164
+ extensions: []
165
+ extra_rdoc_files: []
166
+ files:
167
+ - .gitignore
168
+ - Gemfile
169
+ - MIT-LICENSE
170
+ - README.md
171
+ - Rakefile
172
+ - exvo_auth.gemspec
173
+ - lib/exvo_auth.rb
174
+ - lib/exvo_auth/autonomous/auth.rb
175
+ - lib/exvo_auth/autonomous/base.rb
176
+ - lib/exvo_auth/autonomous/cache.rb
177
+ - lib/exvo_auth/autonomous/consumer.rb
178
+ - lib/exvo_auth/autonomous/http.rb
179
+ - lib/exvo_auth/autonomous/provider.rb
180
+ - lib/exvo_auth/controllers/base.rb
181
+ - lib/exvo_auth/controllers/merb.rb
182
+ - lib/exvo_auth/controllers/rails.rb
183
+ - lib/exvo_auth/dejavu.rb
184
+ - lib/exvo_auth/middleware.rb
185
+ - lib/exvo_auth/models/message.rb
186
+ - lib/exvo_auth/session_store.rb
187
+ - lib/exvo_auth/version.rb
188
+ - test/helper.rb
189
+ - test/test_exvo_auth.rb
190
+ - test/test_integration.rb
191
+ homepage: https://github.com/Exvo/exvo_auth
192
+ licenses: []
193
+ post_install_message:
194
+ rdoc_options: []
195
+ require_paths:
196
+ - lib
197
+ required_ruby_version: !ruby/object:Gem::Requirement
198
+ none: false
199
+ requirements:
200
+ - - ! '>='
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ required_rubygems_version: !ruby/object:Gem::Requirement
204
+ none: false
205
+ requirements:
206
+ - - ! '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubyforge_project:
211
+ rubygems_version: 1.8.10
212
+ signing_key:
213
+ specification_version: 3
214
+ summary: User and App authentication for Exvo
215
+ test_files: []
216
+ has_rdoc: