basic-auth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6f2d54c20566ea9d553b98485770f9802e322d2cb3573b664a0a2067c8eee538
4
+ data.tar.gz: c3d73ba6e0b115306a4c81b0c81ce06e0f2ad971343ff03b743db2484ca05b4d
5
+ SHA512:
6
+ metadata.gz: 7c4b2fd4f1caf23feb11523e8e55fcc71be1ee1f15ef03e5e44ac0f135e72609e82b63db96d55d5d5b0e47e06859377f6aab9d8581af92709e0f7bd7cd4db247
7
+ data.tar.gz: 180217ef64107865710dca4903d42b9ef97cb529afeefac3817a784f24e18e18ccb93587f24d9809d1e700997e10288597506a2869887cfe35848c9f946eb60e
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in basic_auth.gemspec
4
+ gemspec
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ basic-auth (0.1.0)
5
+ rack
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.3)
11
+ rack (2.1.1)
12
+ rake (10.5.0)
13
+ rspec (3.9.0)
14
+ rspec-core (~> 3.9.0)
15
+ rspec-expectations (~> 3.9.0)
16
+ rspec-mocks (~> 3.9.0)
17
+ rspec-core (3.9.1)
18
+ rspec-support (~> 3.9.1)
19
+ rspec-expectations (3.9.0)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.9.0)
22
+ rspec-mocks (3.9.1)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.9.0)
25
+ rspec-support (3.9.2)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ basic-auth!
32
+ bundler (~> 2.0)
33
+ rake (~> 10.0)
34
+ rspec (~> 3.0)
35
+
36
+ BUNDLED WITH
37
+ 2.1.2
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Tung Nguyen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,83 @@
1
+ # basic-auth Middleware
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/basic-auth.png)](http://badge.fury.io/rb/basic-auth)
4
+
5
+ [![BoltOps Badge](https://img.boltops.com/boltops/badges/boltops-badge.png)](https://www.boltops.com)
6
+
7
+ Basic Auth Rack Middleware that supports htpasswd files. It works with Rack compatible frameworks like [Jets](https://rubyonjets.com/), [Rails](https://rubyonrails.org/), [Sinatra](http://sinatrarb.com/), etc.
8
+
9
+ ## Sinatra Example
10
+
11
+ ```ruby
12
+ require 'sinatra'
13
+ require 'basic-auth'
14
+
15
+ use BasicAuth::Middleware
16
+
17
+ get '/' do
18
+ "42\n"
19
+ end
20
+ ```
21
+
22
+ ## Jets Example
23
+
24
+ config/application.rb:
25
+
26
+ ```ruby
27
+ Jets.application.configure do
28
+ config.middleware.use(BasicAuth::Middleware)
29
+ end
30
+ ```
31
+
32
+ ## Customizations
33
+
34
+ Option | Description
35
+ --- | ---
36
+ passwordfile | Path to the htpasswd file. Default: `config/htpasswd`
37
+ protect | Url patterns to protect. The default behavior is to protect all urls. Default: nil (results in protecting all).
38
+
39
+ Example:
40
+
41
+ ```ruby
42
+ use BasicAuth::Middleware, passwordfile: "config/pass.txt", protect: %r{/area51}
43
+ ```
44
+
45
+ The url paths under `/area51` will all be protected. Other urls like the homepage will not be protected.
46
+
47
+ ## Cached htpasswd
48
+
49
+ The htpasswd file is loaded into memory and cached. This means any changes you make to htpasswd, like adding users, will require a server restart. If you want to disable the cache, use `BASIC_AUTH_NO_CACHE=1`.
50
+
51
+ ## Generating htpasswd files
52
+
53
+ The `htpasswd` tool can be used to create htpasswd files. It is installed as part of the apache webserver. It's general form is:
54
+
55
+ htpasswd PASSWORDFILE USERNAME
56
+
57
+ Example:
58
+
59
+ $ htpasswd htpasswd user
60
+ New password:
61
+ Re-type new password:
62
+ Adding password for user user
63
+ $
64
+
65
+ There are also online htpasswd generators: [Htpasswd Generator](http://www.htaccesstools.com/htpasswd-generator/)
66
+
67
+ ## Installation
68
+
69
+ Add this line to your application's Gemfile:
70
+
71
+ gem "basic-auth"
72
+
73
+ And then execute:
74
+
75
+ bundle
76
+
77
+ ## Contributing
78
+
79
+ 1. Fork it
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 3. Commit your changes (`git commit -am "Add some feature"`)
82
+ 4. Push to the branch (`git push origin my-new-feature`)
83
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "basic_auth/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "basic-auth"
7
+ spec.version = BasicAuth::VERSION
8
+ spec.authors = ["Tung Nguyen"]
9
+ spec.email = ["tongueroo@gmail.com"]
10
+
11
+ spec.summary = "Basic Auth Rack Middleware that supports htpasswd files"
12
+ spec.homepage = "https://github.com/tongueroo/basic-auth"
13
+ spec.license = "MIT"
14
+
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "rack"
27
+
28
+ spec.add_development_dependency "bundler", "~> 2.0"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ end
@@ -0,0 +1 @@
1
+ require_relative "basic_auth"
@@ -0,0 +1,9 @@
1
+ require "basic_auth/version"
2
+
3
+ module BasicAuth
4
+ class Error < StandardError; end
5
+
6
+ autoload :Htpasswd, "basic_auth/htpasswd"
7
+ autoload :Matcher, "basic_auth/matcher"
8
+ autoload :Middleware, "basic_auth/middleware"
9
+ end
@@ -0,0 +1,139 @@
1
+ # Thanks: Based on https://github.com/h2o/h2o/blob/master/share/h2o/mruby/htpasswd.rb
2
+ #
3
+ # based on public-domain code by cho45
4
+ #
5
+ # Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to
9
+ # deal in the Software without restriction, including without limitation the
10
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
+ # sell copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
+ # IN THE SOFTWARE.
24
+ #
25
+ require "digest"
26
+
27
+ module BasicAuth
28
+ class Htpasswd
29
+
30
+ attr_accessor :path
31
+ attr_accessor :realm
32
+
33
+ def initialize(path, realm=nil)
34
+ @path = path
35
+ @realm = realm
36
+ end
37
+
38
+ def call(env)
39
+ if /\/\.ht/.match(env['PATH_INFO'])
40
+ return [ 404, { "Content-Type" => "text/plain" }, [ "not found" ] ]
41
+ end
42
+ auth = env['HTTP_AUTHORIZATION'] # Example: Basic dXNlcjpwYXNz
43
+ # dXNlcjpwYXNz is base64 encoded
44
+ if auth
45
+ method, cred = *auth.split(' ')
46
+ if method.casecmp("basic") == 0
47
+ user, pass = cred.unpack("m")[0].split(':', 2)
48
+ begin
49
+ if validate(user, pass)
50
+ return true
51
+ end
52
+ rescue => e
53
+ $stderr.puts "failed to validate password using file:#{@path}:#{e.message}"
54
+ return false
55
+ end
56
+ end
57
+ end
58
+ false
59
+ end
60
+
61
+ def validate(user, pass)
62
+ data.each do |line|
63
+ line_user, hash = line.chomp.split(':', 2)
64
+ if user == line_user && self.class.validate(pass, hash)
65
+ return true
66
+ end
67
+ end
68
+ return false
69
+ end
70
+
71
+ @@data = nil
72
+ def data
73
+ return @@data if @@data && !ENV['BASIC_AUTH_NO_CACHE']
74
+ @@data = File.readlines(@path)
75
+ end
76
+
77
+ def Htpasswd.crypt_md5(pass, salt)
78
+ ctx = Digest::MD5.new.update("#{pass}$apr1$#{salt}")
79
+ final = Digest::MD5.new.update("#{pass}#{salt}#{pass}").digest!.bytes
80
+
81
+ l = pass.length
82
+ while l > 0
83
+ ctx.update(final[0 .. (l > 16 ? 16 : l) - 1].pack("C*"))
84
+ l -= 16
85
+ end
86
+
87
+ l = pass.length
88
+ while l > 0
89
+ ctx.update(l % 2 != 0 ? "\0" : pass[0])
90
+ l >>= 1
91
+ end
92
+
93
+ final = ctx.digest!
94
+
95
+ 1000.times do |i|
96
+ ctx = Digest::MD5.new
97
+ ctx.update(i % 2 != 0 ? pass : final)
98
+ ctx.update(salt) if i % 3 != 0
99
+ ctx.update(pass) if i % 7 != 0
100
+ ctx.update(i % 2 != 0 ? final : pass)
101
+ final = ctx.digest!
102
+ end
103
+
104
+ final = final.bytes
105
+ hash = ""
106
+ for a, b, c in [[0, 6, 12], [1, 7, 13], [2, 8, 14], [3, 9, 15], [4, 10, 5]]
107
+ hash << _to64(final[a] << 16 | final[b] << 8 | final[c], 4)
108
+ end
109
+ hash << _to64(final[11], 2)
110
+
111
+ "$apr1$#{salt}$#{hash}"
112
+ end
113
+
114
+ def Htpasswd._to64(v, n)
115
+ chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
116
+ output = ""
117
+ n.times do
118
+ output << chars[v & 0x3f]
119
+ v >>= 6
120
+ end
121
+ output
122
+ end
123
+
124
+ def Htpasswd.crypt_sha1(pass)
125
+ "{SHA}" + [Digest::SHA1.new.update(pass).digest!].pack("m").chomp
126
+ end
127
+
128
+ def Htpasswd.validate(pass, hash)
129
+ if /^\$apr1\$(.*)\$/.match(hash)
130
+ encoded = crypt_md5(pass, $1)
131
+ elsif /^{SHA}/.match(hash)
132
+ encoded = crypt_sha1(pass)
133
+ else
134
+ raise "crypt-style password hash is not supported"
135
+ end
136
+ return encoded == hash
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,16 @@
1
+ module BasicAuth
2
+ class Matcher
3
+ def initialize(path, options={})
4
+ @path, @options = path, options
5
+ @protect = options[:protect]
6
+ end
7
+
8
+ def match?
9
+ return true unless @protect # defaults to protect all
10
+ # If user accidentally sets a string, change to a regexp
11
+ pattern = @protect.is_a?(String) ? Regexp.new(@protect) : @protect
12
+ matched = @path =~ pattern
13
+ !!matched
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ require "rack"
2
+
3
+ module BasicAuth
4
+ class Middleware < Rack::Auth::Basic
5
+ # Override initialize to allow middleware options. IE:
6
+ #
7
+ # use BasicAuth::Middleware, passwordfile: "htpasswd.txt"
8
+ #
9
+ def initialize(app, options={})
10
+ @app, @options = app, options
11
+ @passwordfile = options[:passwordfile] || "config/htpasswd"
12
+ end
13
+
14
+ def call(env)
15
+ path = Rack::Request.new(env).path
16
+ matcher = Matcher.new(path, @options)
17
+ return @app.call(env) unless matcher.match? # passthrough if route doesnt match
18
+
19
+ htpasswd = Htpasswd.new(@passwordfile)
20
+ authorized = htpasswd.call(env)
21
+ if authorized
22
+ @app.call(env)
23
+ else
24
+ unauthorized # from Rack::Auth::Basic
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module BasicAuth
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: basic-auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tung Nguyen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description:
70
+ email:
71
+ - tongueroo@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - basic-auth.gemspec
84
+ - lib/basic-auth.rb
85
+ - lib/basic_auth.rb
86
+ - lib/basic_auth/htpasswd.rb
87
+ - lib/basic_auth/matcher.rb
88
+ - lib/basic_auth/middleware.rb
89
+ - lib/basic_auth/version.rb
90
+ homepage: https://github.com/tongueroo/basic-auth
91
+ licenses:
92
+ - MIT
93
+ metadata:
94
+ homepage_uri: https://github.com/tongueroo/basic-auth
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubygems_version: 3.1.2
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Basic Auth Rack Middleware that supports htpasswd files
114
+ test_files: []