devise-proxy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []