keycard 0.1.1 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04e5999db1a74c237714b9c8afae5bca2ac11c0c33bc8d56c174967082331ee7
4
- data.tar.gz: db2486afcc74b2777fb74f0ce02fd6f6c3499c69823d39af9db7bd4403d31bb7
3
+ metadata.gz: 5ba441d104509e55f853e1003f6dd2d8c39f362e5e93ee619b0dd9378f8c13b8
4
+ data.tar.gz: 0d503c7e8c4682348e2c6d1ba9d9d0425fdf61429a278882368bad5cb19c4823
5
5
  SHA512:
6
- metadata.gz: 671cff5c7be3e97ff2b4325ff94786f3dbb3d82ffb03e5efd015bf95a8e73a1d9c92a34ca47aa8c2eaf124bea691d0560f765ee854db4fa2e5127b3e4484f160
7
- data.tar.gz: 7ebe3ac9d5019acd351fc63f430e65c52e7d711db036713db96fc9be5b8c962013d7808bb4f3f5c1993b7f2526ad95719ab3733b628abf9c33b2d6ede48f8fdc
6
+ metadata.gz: 578ff3eb3e114a3060b0236f6c471fabf45e947b1f2184828f68206eab35071bfa182482cfbab4e9a1750a48e2e127d1aa4e4feda050a11e53c1937ad0778837
7
+ data.tar.gz: a268b75e7207d0de7626b8f675567eddce0c070158343e2f55d424c6868c06837bfcd03c0be68a3ff8b1edc42aa5798df7d3b59cbadb5b00bea1173a0e855e6d
data/README.md CHANGED
@@ -37,9 +37,44 @@ And then execute:
37
37
 
38
38
  $ bundle
39
39
 
40
- Or install it yourself as:
40
+ ## Configuration
41
41
 
42
- $ gem install keycard
42
+ There are two aspects of Keycard that are configurable: the database for IP
43
+ ranges as they map to institutions (IP blocks map to networks, and networks are
44
+ associated with institutions), and the access mode (whether your application is
45
+ served directly or behind a reverse proxy). These will be unified eventually,
46
+ but for now, they are configured separately.
47
+
48
+ ## For the Database
49
+
50
+ For the database, there is a Railtie that, when running in a Rails app,
51
+ attempts to use the same connection information as ActiveRecord. If you are
52
+ running in this configuration, you will need to run a `rake db:migrate` to
53
+ create the Keycard tables and add them to your `db/schema.rb`. From there forward,
54
+ running `db:setup` or `db:schema:load` will create these tables for you. There is
55
+ a `keycard:migrate` Rake task if you want to run it separately, but it hooks into
56
+ the Rails `db:migrate` by default for convenience.
57
+
58
+ If you need to customize the database configuration, which will be typical for
59
+ at least the production environment, the easiest way is to define an
60
+ initializer. In a multi-application environment, the database may be read-only,
61
+ which will require the `Keycard::DB.config` to have its `readonly` property set
62
+ to `true`. You can also set either the `Keycard::DB.config.opts` to the options
63
+ to pass to the Sequel connection or set `Keycard::DB.config.url` to use a
64
+ connction string. The latter is equivalent to setting the `KEYCARD_DATABASE_URL`
65
+ environment variable.
66
+
67
+ ## For the Access Mode
68
+
69
+ To extract the username and client IP from each request, Keycard must be
70
+ configured for an "access mode". This can be set in an initializer, under the
71
+ `Keycard.config.access` property, and should be either `:direct` if clients
72
+ will make HTTP requests directly to the Ruby webserver, or `:proxy` if a
73
+ reverse proxy will be used.
74
+
75
+ Under the hood, these modes amount to using either `REMOTE_USER` and
76
+ `REMOTE_ADDR` in the environment set by the Ruby webserver for direct mode or
77
+ the `X-Forwarded-User` and `X-Forwarded-For` headers set by a reverse proxy.
43
78
 
44
79
  ## License
45
80
 
data/keycard.gemspec CHANGED
@@ -25,7 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.add_dependency "mysql2"
29
28
  spec.add_dependency "sequel"
30
29
 
31
30
  spec.add_development_dependency "bundler", "~> 1.16"
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keycard
4
+ # This request wrapper should be used when the application will serve HTTP
5
+ # requests directly or through a proxy that sets up the usual environment.
6
+ class DirectRequest < SimpleDelegator
7
+ def self.for(request)
8
+ new(request)
9
+ end
10
+
11
+ def username
12
+ env['REMOTE_USER'] || ''
13
+ end
14
+
15
+ def client_ip
16
+ (env['REMOTE_ADDR'] || '').split(',').first || ''
17
+ end
18
+ end
19
+ end
@@ -26,7 +26,7 @@ module Keycard
26
26
  end
27
27
 
28
28
  def attributes_for(request)
29
- return {} unless (numeric_ip = numeric_ip(request.remote_ip))
29
+ return {} unless (numeric_ip = numeric_ip(request.client_ip))
30
30
 
31
31
  insts = insts_for_ip(numeric_ip)
32
32
 
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keycard
4
+ # This request wrapper should be used when the application will be served
5
+ # behind a reverse proxy. It relies on the trusted relationship with the
6
+ # proxy to use HTTP headers for forwarded values.
7
+ #
8
+ # The typical headers forwarded are X-Forwarded-User and X-Forwarded-For,
9
+ # which, somewhat confusingly, are transposed into HTTP_X_REMOTE_USER and
10
+ # HTTP_X_FORWARDED_FOR once the Rack request is assembled.
11
+ class ProxiedRequest < SimpleDelegator
12
+ def self.for(request)
13
+ new(request)
14
+ end
15
+
16
+ def username
17
+ env['HTTP_X_REMOTE_USER'] || ''
18
+ end
19
+
20
+ def client_ip
21
+ (env['HTTP_X_FORWARDED_FOR'] || '').split(',').first || ''
22
+ end
23
+ end
24
+ end
@@ -66,9 +66,14 @@ module Keycard
66
66
  initializer "keycard.before_initializers", before: :load_config_initializers do
67
67
  config = Keycard::DB.config
68
68
  unless config.url
69
- opts = ActiveRecord::Base.connection.instance_variable_get(:@config).dup
70
- opts.delete(:flags)
71
- config[:opts] = opts
69
+ case Rails.env
70
+ when "development"
71
+ config[:opts] = { adapter: 'sqlite', database: "db/keycard_development.sqlite3" }
72
+ when "test"
73
+ config[:opts] = { adapter: 'sqlite' }
74
+ else
75
+ raise "Keycard::DB.config must be configured"
76
+ end
72
77
  end
73
78
 
74
79
  Railtie.before_blocks.each do |block|
@@ -5,9 +5,10 @@ module Keycard
5
5
  # complete set of things that determine the user's #identity), given a Rack
6
6
  # request.
7
7
  class RequestAttributes
8
- def initialize(request, finder: InstitutionFinder.new)
9
- @finder = finder
10
- @request = request
8
+ def initialize(request, finder: InstitutionFinder.new, request_factory: default_factory)
9
+ @request = request
10
+ @finder = finder
11
+ @request_factory = request_factory
11
12
  end
12
13
 
13
14
  def [](attr)
@@ -15,12 +16,34 @@ module Keycard
15
16
  end
16
17
 
17
18
  def all
18
- finder.attributes_for(request)
19
+ user_attributes.merge(finder.attributes_for(request))
19
20
  end
20
21
 
21
22
  private
22
23
 
24
+ def user_attributes
25
+ { username: request.username }
26
+ end
27
+
28
+ def request
29
+ request_factory.for(@request)
30
+ end
31
+
32
+ def default_factory
33
+ access = Keycard.config.access.to_sym
34
+ case access
35
+ when :direct
36
+ DirectRequest
37
+ when :proxy
38
+ ProxiedRequest
39
+ else
40
+ # TODO: Warn about this once to the appropriate log; probably in a config check, not here.
41
+ # puts "Keycard does not recognize the '#{access}' access mode, using 'direct'."
42
+ DirectRequest
43
+ end
44
+ end
45
+
23
46
  attr_reader :finder
24
- attr_reader :request
47
+ attr_reader :request_factory
25
48
  end
26
49
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Keycard
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/keycard.rb CHANGED
@@ -2,12 +2,20 @@
2
2
 
3
3
  require "keycard/version"
4
4
  require "sequel"
5
+ require "ostruct"
5
6
 
6
7
  # All of the Keycard components are contained within this top-level module.
7
8
  module Keycard
9
+ def self.config
10
+ @config ||= OpenStruct.new(
11
+ access: :direct
12
+ )
13
+ end
8
14
  end
9
15
 
10
16
  require "keycard/db"
11
17
  require "keycard/railtie" if defined?(Rails)
12
18
  require "keycard/request_attributes"
13
19
  require "keycard/institution_finder"
20
+ require "keycard/direct_request"
21
+ require "keycard/proxied_request"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keycard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Botimer
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2018-03-23 00:00:00.000000000 Z
12
+ date: 2018-06-08 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: mysql2
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: sequel
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -202,7 +188,9 @@ files:
202
188
  - keycard.gemspec
203
189
  - lib/keycard.rb
204
190
  - lib/keycard/db.rb
191
+ - lib/keycard/direct_request.rb
205
192
  - lib/keycard/institution_finder.rb
193
+ - lib/keycard/proxied_request.rb
206
194
  - lib/keycard/railtie.rb
207
195
  - lib/keycard/request_attributes.rb
208
196
  - lib/keycard/version.rb