devise-proxy 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack'
4
+
5
+ group :development do
6
+ # gem "shoulda"
7
+ # gem "rdoc", "~> 3.12"
8
+ # gem "bundler", "~> 1.0.0"
9
+ gem "jeweler", "~> 1.8.4"
10
+ gem 'rake'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.8.4)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rdoc
10
+ json (1.7.5)
11
+ rack (1.4.1)
12
+ rake (0.9.2.2)
13
+ rdoc (3.12)
14
+ json (~> 1.4)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ jeweler (~> 1.8.4)
21
+ rack
22
+ rake
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2012, Preston Lee
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ 3. All advertising materials mentioning features or use of this software
12
+ must display the following acknowledgement:
13
+ This product includes software developed by Preston Lee.
14
+ 4. Neither the name of Preston Lee nor the
15
+ names of its contributors may be used to endorse or promote products
16
+ derived from this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY Preston Lee ''AS IS'' AND ANY
19
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL Preston Lee BE LIABLE FOR ANY
22
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Devise Proxy #
2
+
3
+ devise-proxy is a standalone Rack Middleware application that authenticates a username/password against
4
+ a devise-powered backend application before forwarding the original HTTP request to the same application.
5
+
6
+ Authentication is done on *every* request, so it is advisable to use devise-proxy sparingly.
7
+
8
+ # Quick Start #
9
+
10
+ - Create a devise-proxy.yml using the provided .sample.
11
+ - `rackup config.ru' to start the proxy server.
12
+ - Configure you web browser or other client software to use the proxy and set a username (email) and password.
13
+ - Enjoy!
14
+
15
+ # Authors #
16
+
17
+ Preston Lee
18
+
19
+ # Legal #
20
+
21
+ See LICENSE file for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "devise-proxy"
18
+ gem.homepage = "http://github.com/preston/devise-proxy"
19
+ gem.license = "BSD"
20
+ gem.summary = %Q{A standalone Rack Middleware application that authenticates a username/password against a devise-powered backend application before forwarding the original HTTP request to the same application.}
21
+ gem.description = %Q{A standalone Rack Middleware application that authenticates a username/password against a devise-powered backend application before forwarding the original HTTP request to the same application. Authentication is done on *every* request, so it is advisable to use devise-proxy sparingly.}
22
+ gem.email = "conmotto@gmail.com"
23
+ gem.authors = ["Preston Lee"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ require 'rdoc/task'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "devise-proxy #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/config.ru ADDED
@@ -0,0 +1,19 @@
1
+
2
+ current_dir = File.dirname(File.expand_path(__FILE__))
3
+ lib_path = File.join(current_dir, 'lib')
4
+ puts lib_path
5
+ $LOAD_PATH.unshift lib_path
6
+
7
+ require 'devise-proxy'
8
+
9
+ # For development only.
10
+ # use Rack::Reloader
11
+
12
+ config_file = File.join(current_dir, 'config', 'devise-proxy.yml')
13
+ if File.exists? config_file
14
+ conf = YAML::load(File.open(config_file))
15
+ run DeviseProxy::Proxy.new(conf['backend']['hostname'], conf['backend']['port'])
16
+ else
17
+ puts "\nPlease create a config file prior to starting the proxy using the provided .sample file, at:\n\n\t#{config_file}\n\n"
18
+ exit 1
19
+ end
@@ -0,0 +1,3 @@
1
+ backend:
2
+ hostname: localhost
3
+ port: 3000
@@ -0,0 +1,2 @@
1
+ require 'devise-proxy/authenticator'
2
+ require 'devise-proxy/proxy'
@@ -0,0 +1,75 @@
1
+ require "net/http"
2
+ require "json"
3
+
4
+ module DeviseProxy
5
+
6
+ class Authenticator
7
+
8
+ attr_accessor :host
9
+ attr_accessor :port
10
+ @@POST_SIGN = "/users/sign_in.json"
11
+ @@POST_WS = "/external/rd"
12
+
13
+
14
+ def initialize(host = 'localhost', port = 3000)
15
+ @host = host
16
+ @port = port
17
+ end
18
+
19
+ def authenticate(email, password)
20
+
21
+ @credentials = {
22
+ "user" => {
23
+ "email" => email,
24
+ "password" => password
25
+ }
26
+ }.to_json
27
+
28
+
29
+
30
+ sig = Net::HTTP::Post.new(@@POST_SIGN, initheader = {'Content-Type' => 'application/json'})
31
+ sig.body = @credentials
32
+
33
+
34
+ http = Net::HTTP.new(@host, @port).start
35
+ resp1 = http.request(sig)
36
+ puts "Response: #{resp1.code} , Message: #{resp1.message} , Body: #{resp1.body}"
37
+ result = []
38
+ if resp1.code == "200" then
39
+ puts "logged in"
40
+ json_resp = JSON.parse(resp1.body)
41
+ @auth_token = json_resp['auth_token']
42
+
43
+ @req_body = {
44
+ "device" => {
45
+ "name" => "device_json",
46
+ "operating_system_id" => "7",
47
+ "hash_string" => "jfsg3k4ovj0j02jv"
48
+ },
49
+ "auth_token" => @auth_token
50
+ }.to_json
51
+ req = Net::HTTP::Post.new(@@POST_WS, initheader = {'Content-Type' =>'application/json'})
52
+ req.body = @req_body
53
+
54
+ response = http.request(req)
55
+ puts "Response: #{response.code} , Message: #{response.message} , Body: #{response.body}"
56
+
57
+ headers = {}
58
+ sub_response.each_header do |k,v|
59
+ headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
60
+ end
61
+ result = [response.code, headers, response.body]
62
+ else
63
+ headers = {}
64
+ resp1.each_header do |k,v|
65
+ headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
66
+ end
67
+ result = [resp1.code, headers, resp1.body]
68
+ end
69
+ return result
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+
@@ -0,0 +1,89 @@
1
+ require "net/http"
2
+ require "enumerator"
3
+ require 'base64'
4
+ # require 'authenticator'
5
+
6
+ module DeviseProxy
7
+
8
+ class Proxy
9
+
10
+ attr_accessor :host
11
+ attr_accessor :port
12
+ attr_accessor :authenticator
13
+
14
+ def initialize(remote_host, remote_port)
15
+ @host = remote_host
16
+ @port = remote_port
17
+ @authenticator = DeviseProxy::Authenticator.new(@host, port)
18
+ end
19
+
20
+ def call(env)
21
+ req = Rack::Request.new(env)
22
+ puts req.to_yaml
23
+
24
+ puts "User agent: #{env['HTTP_USER_AGENT']}"
25
+
26
+ client_credential_b64 = env['HTTP_PROXY_AUTHORIZATION']
27
+ # puts "B64: #{client_credential_b64}"
28
+
29
+ if client_credential_b64 != nil and client_credential_b64 != ''
30
+ # Decode the credentials:
31
+ encoded = client_credential_b64.split[1]
32
+ credentials = Base64.decode64(encoded).split(':', 2)
33
+ email = credentials[0]
34
+ password = credentials[1]
35
+
36
+ puts "Client password credentials email: #{email}, password, #{password}"
37
+
38
+ # Authenticate against the backend:
39
+ auth = @authenticator.authenticate(email, password)
40
+ allowed = auth[0].to_s == '201'
41
+ puts "Authenticated #{allowed ? 'approved.' : 'denied!'}\n\n"
42
+
43
+ result = [403, auth[1], [auth[2]]]
44
+ if allowed
45
+
46
+ method = req.request_method.downcase
47
+ method[0..0] = method[0..0].upcase
48
+
49
+ sub_request = Net::HTTP.const_get(method).new("#{req.path}#{"?" if req.query_string}#{req.query_string}")
50
+
51
+ if sub_request.request_body_permitted? and req.body
52
+ sub_request.body_stream = req.body
53
+ sub_request.content_length = req.content_length
54
+ sub_request.content_type = req.content_type
55
+ end
56
+
57
+ sub_request["X-Forwarded-For"] = (req.env["X-Forwarded-For"].to_s.split(/, +/) + [req.env['REMOTE_ADDR']]).join(", ")
58
+ sub_request["Accept-Encoding"] = req.accept_encoding
59
+ sub_request["Referer"] = req.referer
60
+
61
+ sub_response = Net::HTTP.start(@host, @port) do |http|
62
+ http.request(sub_request)
63
+ end
64
+
65
+ headers = {}
66
+ sub_response.each_header do |k,v|
67
+ headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
68
+ end
69
+
70
+ result = [sub_response.code.to_i, headers, [sub_response.read_body]]
71
+ end
72
+ else
73
+ # The client needs to retry, next time sending proxy credentials!
74
+ headers = {}
75
+ # sub_response.each_header do |k,v|
76
+ # headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
77
+ # end
78
+ headers['Proxy-Authenticate'] = 'Basic realm="A valid account is required. Please use your registered email address as your username."'
79
+ headers['Content-Type'] = 'text/plain'
80
+ result = [407, headers, ["Email/Password required!"]]
81
+ end
82
+
83
+
84
+ result
85
+ end
86
+ end
87
+
88
+ end
89
+
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'devise-proxy'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestDeviseProxy < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Preston Lee
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: jeweler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.4
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.8.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: A standalone Rack Middleware application that authenticates a username/password
63
+ against a devise-powered backend application before forwarding the original HTTP
64
+ request to the same application. Authentication is done on *every* request, so it
65
+ is advisable to use devise-proxy sparingly.
66
+ email: conmotto@gmail.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files:
70
+ - LICENSE
71
+ - README.md
72
+ files:
73
+ - Gemfile
74
+ - Gemfile.lock
75
+ - LICENSE
76
+ - README.md
77
+ - Rakefile
78
+ - VERSION
79
+ - config.ru
80
+ - config/devise-proxy.yml.sample
81
+ - lib/devise-proxy.rb
82
+ - lib/devise-proxy/authenticator.rb
83
+ - lib/devise-proxy/proxy.rb
84
+ - test/helper.rb
85
+ - test/test_devise-proxy.rb
86
+ homepage: http://github.com/preston/devise-proxy
87
+ licenses:
88
+ - BSD
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ segments:
100
+ - 0
101
+ hash: -4305826360320545188
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 1.8.24
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: A standalone Rack Middleware application that authenticates a username/password
114
+ against a devise-powered backend application before forwarding the original HTTP
115
+ request to the same application.
116
+ test_files: []