dpop 0.0.1 → 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.
- checksums.yaml +4 -4
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +80 -0
- data/README.md +97 -6
- data/lib/dpop/configuration.rb +24 -0
- data/lib/dpop/controller.rb +52 -0
- data/lib/dpop/cookie_jar.rb +42 -0
- data/lib/dpop/encryptor.rb +33 -0
- data/lib/dpop/key_generator.rb +22 -0
- data/lib/dpop/proof_generator.rb +79 -0
- data/lib/dpop/railtie.rb +10 -0
- data/lib/dpop/version.rb +1 -1
- data/lib/dpop.rb +46 -2
- metadata +128 -7
- data/sig/dpop.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 515c773b21830f39448b7cf146d976eb66c0121efb97a316063b9643d00589fb
|
4
|
+
data.tar.gz: 7c8e28c5dde868992435cd6e2df6c5801d809d1e3124b0ec2101b1f1ee7e7a30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c83c6fd46e8290ef434c7869b2fd3096771e829119308d2ff096ebfe6227df24ac2a2b64cef7f58a45a1fa2ba836e6abadc46f4c5067509fb3640c3d96bd929
|
7
|
+
data.tar.gz: c12968b246fb12df9a0e82318d799e48c11ea48df8ec1480e0ecbbe11ff4c78c39c270a11de70393820e5c8fd38fc1546bd76b7b5414ed120c95bb2e83b406d2
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rails
|
3
|
+
|
4
|
+
Style/StringLiterals:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Metrics/BlockLength:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/ParameterLists:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Naming/FileName:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Naming/MethodParameterName:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Rails/RakeEnvironment:
|
20
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dpop (0.1.0)
|
5
|
+
activesupport
|
6
|
+
jwt
|
7
|
+
openssl
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (7.0.3.1)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
ast (2.4.2)
|
18
|
+
concurrent-ruby (1.1.10)
|
19
|
+
diff-lcs (1.5.0)
|
20
|
+
i18n (1.12.0)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
jwt (2.4.1)
|
23
|
+
minitest (5.16.2)
|
24
|
+
openssl (3.0.0)
|
25
|
+
parallel (1.22.1)
|
26
|
+
parser (3.1.2.0)
|
27
|
+
ast (~> 2.4.1)
|
28
|
+
rack (2.2.3)
|
29
|
+
rainbow (3.1.1)
|
30
|
+
rake (13.0.6)
|
31
|
+
regexp_parser (2.3.1)
|
32
|
+
rexml (3.2.5)
|
33
|
+
rspec (3.11.0)
|
34
|
+
rspec-core (~> 3.11.0)
|
35
|
+
rspec-expectations (~> 3.11.0)
|
36
|
+
rspec-mocks (~> 3.11.0)
|
37
|
+
rspec-core (3.11.0)
|
38
|
+
rspec-support (~> 3.11.0)
|
39
|
+
rspec-expectations (3.11.0)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.11.0)
|
42
|
+
rspec-mocks (3.11.1)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.11.0)
|
45
|
+
rspec-support (3.11.0)
|
46
|
+
rubocop (1.28.2)
|
47
|
+
parallel (~> 1.10)
|
48
|
+
parser (>= 3.1.0.0)
|
49
|
+
rainbow (>= 2.2.2, < 4.0)
|
50
|
+
regexp_parser (>= 1.8, < 3.0)
|
51
|
+
rexml
|
52
|
+
rubocop-ast (>= 1.17.0, < 2.0)
|
53
|
+
ruby-progressbar (~> 1.7)
|
54
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
55
|
+
rubocop-ast (1.17.0)
|
56
|
+
parser (>= 3.1.1.0)
|
57
|
+
rubocop-rails (2.14.2)
|
58
|
+
activesupport (>= 4.2.0)
|
59
|
+
rack (>= 1.1)
|
60
|
+
rubocop (>= 1.7.0, < 2.0)
|
61
|
+
ruby-progressbar (1.11.0)
|
62
|
+
tzinfo (2.0.5)
|
63
|
+
concurrent-ruby (~> 1.0)
|
64
|
+
unicode-display_width (2.1.0)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
x86_64-darwin-19
|
69
|
+
|
70
|
+
DEPENDENCIES
|
71
|
+
bundler
|
72
|
+
dpop!
|
73
|
+
jwt
|
74
|
+
rake (~> 13.0)
|
75
|
+
rspec
|
76
|
+
rubocop
|
77
|
+
rubocop-rails
|
78
|
+
|
79
|
+
BUNDLED WITH
|
80
|
+
2.3.15
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Dpop
|
2
2
|
|
3
|
-
|
3
|
+
Implementation of DPoP ([Demonstrating Proof-of-Possession at the Application Layer](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop)) for Ruby and Rails apps.
|
4
4
|
|
5
|
-
|
5
|
+
Adds a
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -16,14 +16,105 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
|
19
|
+
In general, this gem provides two concepts: A wrapper for creating private keys that this gem can consume, and an API for consuming those private keys to generate Proof JWT's for a given request.
|
20
|
+
|
21
|
+
### Setup
|
22
|
+
|
23
|
+
This gem uses a configuration concept for setup, and then can be accessed through module methods on `Dpop`
|
24
|
+
|
25
|
+
Run the configurer to set with defaults:
|
26
|
+
```ruby
|
27
|
+
Dpop.configure
|
28
|
+
```
|
29
|
+
|
30
|
+
Or pass a block to overwrite defaults:
|
31
|
+
```ruby
|
32
|
+
Dpop.configure do |config|
|
33
|
+
config.encryption_key = MY_SECURE_SECRET_PASSPHRASE
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
|Configurable variable|Description|Default value|
|
38
|
+
|===|===|===|
|
39
|
+
|cookie_name|Cookie saved on the browser when using the Rails controller concern|"_proof_keys"|
|
40
|
+
|encryption_key|Secure passphrase used for encrypting cookes with Rails|ENV["DPOP_ENCRYPTION_KEY"]|
|
41
|
+
|generated_key_size|Byte size of generated private keys|1024|
|
42
|
+
|
43
|
+
|
44
|
+
### Module methods
|
45
|
+
|
46
|
+
To generate a consumable private key, run `Dpop.generate_key_pair`. That will return a PEM string, which can be used with openssl by running `OpenSSL::PKey::RSA.new(key)`
|
47
|
+
|
48
|
+
To generate a Proof JWT, run `Dpop.get_proof_with_key(key, htu: "https://www.website.call/path", htm: "GET"`. That will return a JWT string, which should be added to the Dpop header of your http request.
|
49
|
+
|
50
|
+
### Rails
|
51
|
+
|
52
|
+
In Rails apps, this gem automatically configures on initialization using a Railtie. At any time, those configuration variables can be overwritten manually as described above, but running `Dpop.configure` to initialize the gem isn't mandatory.
|
53
|
+
|
54
|
+
The app provides a controller concern that can be used to ensure user's browsers have a private key saved in their cookies, which can be relied on to prove possession of their browser. A proof can then be generated using that key, to be attached to your HTTP requests.
|
55
|
+
|
56
|
+
In your `ApplicationController`, add `include Dpop::Controller`.
|
57
|
+
|
58
|
+
In your controllers where you'd like to ensure your user has a key set, or in your `ApplicationController`, add `ensure_dpop!`
|
59
|
+
|
60
|
+
When you want to create a proof signed with that key, use `get_proof(htu: "https://www.website.call/path", htm: "GET")`
|
61
|
+
|
62
|
+
Example using `Net::HTTP`:
|
63
|
+
```
|
64
|
+
class MyController < ApplicationController
|
65
|
+
ensure_dpop!
|
66
|
+
|
67
|
+
def index
|
68
|
+
uri = URI("https://www.myresourcehost.com/index?page=1")
|
69
|
+
proof = get_proof(htu: dpop_htu(uri), htm: "GET")
|
70
|
+
|
71
|
+
req = Net::HTTP::Get.new(uri)
|
72
|
+
req['authorization'] = "DPoP #{my_access_token}"
|
73
|
+
req['dpop'] = proof
|
74
|
+
|
75
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
76
|
+
http.request(req)
|
77
|
+
end
|
78
|
+
|
79
|
+
@data = res.body
|
80
|
+
end
|
81
|
+
|
82
|
+
def create
|
83
|
+
uri = URI("https://www.myresourcehost.com/index?page=1")
|
84
|
+
proof = get_proof(htu: dpop_htu(uri), htm: "GET")
|
85
|
+
|
86
|
+
req = Net::HTTP::Post.new(uri)
|
87
|
+
req['authorization'] = "DPoP #{my_access_token}"
|
88
|
+
req['dpop'] = proof
|
89
|
+
|
90
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
91
|
+
http.request(req)
|
92
|
+
end
|
93
|
+
|
94
|
+
@data = res.body
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Only pass scheme, host, and path following DPoP spec
|
100
|
+
def dpop_htu(uri)
|
101
|
+
uri.fragment = dpop_uri.query = nil
|
102
|
+
uri
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
```
|
20
107
|
|
21
108
|
## Development
|
22
109
|
|
23
|
-
|
110
|
+
`bundle install` to setup. Develop using `bundle console` for ruby, or by installing the gem through `path:` in your consuming app.
|
24
111
|
|
25
|
-
To
|
112
|
+
To release a new version, update the version number in `version.rb`, run `bundle install` to update Gemfile.lock, and add a CHANGELOG.md entry for your version.
|
26
113
|
|
27
114
|
## Contributing
|
28
115
|
|
29
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
116
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/WilliamNHarvey/dpop-ruby. Please add clear testing instructions in your PR.
|
117
|
+
|
118
|
+
## License
|
119
|
+
|
120
|
+
[Apache Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Configures the app's module methods
|
5
|
+
class Configuration
|
6
|
+
attr_accessor :cookie_name, :encryption_key, :generated_key_size, :key_alg
|
7
|
+
|
8
|
+
DEFAULT_COOKIE_NAME = "_proof_keys"
|
9
|
+
DEFAULT_ENCRYPTION_KEY = ENV["DPOP_ENCRYPTION_KEY"] || ""
|
10
|
+
DEFAULT_GENERATED_KEY_SIZE = 1024
|
11
|
+
DEFAULT_KEY_ALG = :rsa
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
self.cookie_name = DEFAULT_COOKIE_NAME
|
15
|
+
self.encryption_key = DEFAULT_ENCRYPTION_KEY
|
16
|
+
self.generated_key_size = DEFAULT_GENERATED_KEY_SIZE
|
17
|
+
self.key_alg = DEFAULT_KEY_ALG
|
18
|
+
end
|
19
|
+
|
20
|
+
def encryptor
|
21
|
+
@encryptor ||= Dpop::Encryptor.new(encryption_key)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Controller concern for Rails
|
5
|
+
module Controller
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# Error for DPoP cookie not being found
|
9
|
+
class MissingDpopCookie < StandardError
|
10
|
+
def initialize(cookie_name)
|
11
|
+
super("No DPoP cookie found with name `#{cookie_name}`. Try running `ensure_dpop!` before using this concern.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
included do
|
16
|
+
class_attribute :ensure_dpop_on_actions
|
17
|
+
self.ensure_dpop_on_actions = false
|
18
|
+
|
19
|
+
# Set up the around_action which ensures the cookie is set on request if the controller has ensure_dpop! set
|
20
|
+
before_action :set_dpop_cookie
|
21
|
+
end
|
22
|
+
|
23
|
+
class_methods do
|
24
|
+
def ensure_dpop!
|
25
|
+
self.ensure_dpop_on_actions = true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_proof(**args)
|
30
|
+
dpop_key = cookie_jar[Dpop.config.cookie_name]
|
31
|
+
raise MissingDpopCookie, Dpop.config.cookie_name unless dpop_key
|
32
|
+
|
33
|
+
generator = Dpop::ProofGenerator.new(dpop_key, "RS256")
|
34
|
+
generator.create_dpop_proof(args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_dpop_cookie
|
38
|
+
return unless ensure_dpop_on_actions
|
39
|
+
return if cookie_jar[Dpop.config.cookie_name]
|
40
|
+
|
41
|
+
generated = Dpop::KeyGenerator.generate(Dpop.config.key_alg)
|
42
|
+
|
43
|
+
cookie_jar[Dpop.config.cookie_name] = generated
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def cookie_jar
|
49
|
+
Dpop::CookieJar.new(Dpop.config.encryptor, request.cookies)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Manages browser cookies
|
5
|
+
class CookieJar
|
6
|
+
# Error for when cookie is not decipherable
|
7
|
+
class InvalidCookieError < StandardError
|
8
|
+
def initialize(cookie_name, cookie_value)
|
9
|
+
super("invalid value for #{cookie_name}: #{cookie_value}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(encryptor, request_cookies)
|
14
|
+
@encryptor = encryptor
|
15
|
+
@request_cookies = request_cookies
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](cookie_name)
|
19
|
+
try_decrypt(cookie_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(cookie_name, value)
|
23
|
+
encrypted_value = @encryptor.encrypt_and_sign(value)
|
24
|
+
@request_cookies[cookie_name] = encrypted_value
|
25
|
+
end
|
26
|
+
|
27
|
+
def key?(cookie_name)
|
28
|
+
@request_cookies.key?(cookie_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def try_decrypt(cookie_name)
|
34
|
+
value = @request_cookies[cookie_name]
|
35
|
+
return nil if value.blank?
|
36
|
+
|
37
|
+
@encryptor.decrypt_and_verify(value)
|
38
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
39
|
+
raise InvalidCookieError.new(cookie_name, value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Encrypts and decrypts messages
|
5
|
+
class Encryptor
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
SECRET = "dpop encrypted message"
|
9
|
+
SIGN_SECRET = "signed dpop encrypted message"
|
10
|
+
CIPHER = "aes-256-gcm"
|
11
|
+
|
12
|
+
def_delegators :@message_encryptor, :encrypt_and_sign, :decrypt_and_verify
|
13
|
+
|
14
|
+
def initialize(secret)
|
15
|
+
@message_encryptor = build_message_encryptor(secret)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_message_encryptor(secret)
|
21
|
+
key_generator = ActiveSupport::CachingKeyGenerator.new(
|
22
|
+
ActiveSupport::KeyGenerator.new(
|
23
|
+
secret,
|
24
|
+
iterations: 1000,
|
25
|
+
hash_digest_class: OpenSSL::Digest::SHA256
|
26
|
+
)
|
27
|
+
)
|
28
|
+
secret = key_generator.generate_key(SECRET)[0, 32]
|
29
|
+
sign_secret = key_generator.generate_key(SIGN_SECRET)
|
30
|
+
ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON, cipher: CIPHER)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Generates private keys
|
5
|
+
module KeyGenerator
|
6
|
+
# Error for receiving an unrecognized algorithm
|
7
|
+
class UnsupportedAlgorithmError < StandardError
|
8
|
+
def initialize(alg)
|
9
|
+
super("Unsupported algorithm received: #{alg}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate(alg = :rsa)
|
14
|
+
# TODO: support more algs
|
15
|
+
raise UnsupportedAlgorithmError, alg if alg != :rsa
|
16
|
+
|
17
|
+
OpenSSL::PKey::RSA.generate(Dpop.config.generated_key_size).to_pem
|
18
|
+
end
|
19
|
+
|
20
|
+
module_function :generate
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpop
|
4
|
+
# Generates Proof JWT's
|
5
|
+
class ProofGenerator
|
6
|
+
JWT_TYPE = "dpop+jwt"
|
7
|
+
RSA = "RSA"
|
8
|
+
|
9
|
+
# Error for DPoP key being uninitialized
|
10
|
+
class MissingKeyError < StandardError
|
11
|
+
def initialize
|
12
|
+
super("DPoP key blank")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Error for unsupported key formats
|
17
|
+
class InvalidKeyError < StandardError
|
18
|
+
def initialize(key)
|
19
|
+
super("Unrecognized key format for DPoP key: #{key}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(dpop_key, alg)
|
24
|
+
raise MissingKeyError if dpop_key.blank?
|
25
|
+
|
26
|
+
@dpop_key = dpop_key
|
27
|
+
@alg = alg
|
28
|
+
end
|
29
|
+
|
30
|
+
# Takes the path being called. Returns a signed JWT
|
31
|
+
def create_dpop_proof(htu:, htm:, nonce: nil, ath: nil, iat: Time.now.to_i, jti: SecureRandom.uuid, **additional)
|
32
|
+
private_key, public_key = keys
|
33
|
+
|
34
|
+
headers = create_headers(public_key)
|
35
|
+
|
36
|
+
payload = create_payload(
|
37
|
+
htu: htu, htm: htm, ath: ath, iat: iat, jti: jti, nonce: nonce, **additional
|
38
|
+
)
|
39
|
+
|
40
|
+
JWT.encode(payload, private_key, @alg, headers)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_headers(public_key)
|
46
|
+
{
|
47
|
+
alg: @alg,
|
48
|
+
typ: JWT_TYPE,
|
49
|
+
jwk: public_key
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_payload(htu:, htm:, nonce: nil, ath: nil, iat: Time.now.to_i, jti: SecureRandom.uuid, **additional)
|
54
|
+
{
|
55
|
+
htu: htu,
|
56
|
+
htm: htm,
|
57
|
+
ath: ath,
|
58
|
+
iat: iat,
|
59
|
+
jti: jti,
|
60
|
+
nonce: nonce
|
61
|
+
}.merge(additional).compact
|
62
|
+
end
|
63
|
+
|
64
|
+
# We only support RSA keys in the form of pem strings.
|
65
|
+
def keys
|
66
|
+
return [@private_key, @public_key] if defined?(@private_key) && defined?(@public_key)
|
67
|
+
|
68
|
+
raise InvalidKeyError, @dpop_key unless @dpop_key.instance_of? String
|
69
|
+
|
70
|
+
@private_key = OpenSSL::PKey::RSA.new(@dpop_key)
|
71
|
+
@public_key = {
|
72
|
+
kty: RSA,
|
73
|
+
n: Base64.urlsafe_encode64(@private_key.n.to_s(2), padding: false),
|
74
|
+
e: Base64.urlsafe_encode64(@private_key.e.to_s(2), padding: false)
|
75
|
+
}
|
76
|
+
[@private_key, @public_key]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/dpop/railtie.rb
ADDED
data/lib/dpop/version.rb
CHANGED
data/lib/dpop.rb
CHANGED
@@ -1,8 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "active_support/json"
|
4
|
+
require "active_support/key_generator"
|
5
|
+
require "active_support/message_encryptor"
|
6
|
+
require "jwt"
|
7
|
+
require "openssl"
|
8
|
+
require "securerandom"
|
4
9
|
|
10
|
+
# DPoP top level methods
|
5
11
|
module Dpop
|
6
12
|
class Error < StandardError; end
|
7
|
-
|
13
|
+
|
14
|
+
autoload :Configuration, "dpop/configuration"
|
15
|
+
autoload :Controller, "dpop/controller"
|
16
|
+
autoload :CookieJar, "dpop/cookie_jar"
|
17
|
+
autoload :Encryptor, "dpop/encryptor"
|
18
|
+
autoload :KeyGenerator, "dpop/key_generator"
|
19
|
+
autoload :ProofGenerator, "dpop/proof_generator"
|
20
|
+
autoload :Version, "dpop/version"
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# Configure Dpop application-wide settings.
|
24
|
+
#
|
25
|
+
# Yields a configuration object that can be used to override default settings.
|
26
|
+
def configure
|
27
|
+
yield(configuration) if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the client's Configuration object, or creates one if not yet created.
|
31
|
+
def configuration
|
32
|
+
@configuration ||= Dpop::Configuration.new
|
33
|
+
end
|
34
|
+
|
35
|
+
alias config configuration
|
36
|
+
|
37
|
+
def get_proof_with_key(dpop_key, **args)
|
38
|
+
generator = Dpop::ProofGenerator.new(dpop_key, "RS256")
|
39
|
+
generator.create_dpop_proof(args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_key_pair(alg = :rsa)
|
43
|
+
Dpop::KeyGenerator.generate(alg)
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_integration
|
47
|
+
require "dpop/railtie" if defined?(Rails::Railtie)
|
48
|
+
end
|
49
|
+
end
|
8
50
|
end
|
51
|
+
|
52
|
+
Dpop.load_integration
|
metadata
CHANGED
@@ -1,15 +1,127 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dpop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WilliamNHarvey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
12
|
-
dependencies:
|
11
|
+
date: 2022-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
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: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: jwt
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: openssl
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
13
125
|
description:
|
14
126
|
email:
|
15
127
|
- williamnharvey@gmail.com
|
@@ -17,14 +129,23 @@ executables: []
|
|
17
129
|
extensions: []
|
18
130
|
extra_rdoc_files: []
|
19
131
|
files:
|
132
|
+
- ".rspec"
|
133
|
+
- ".rubocop.yml"
|
20
134
|
- CHANGELOG.md
|
21
135
|
- Gemfile
|
136
|
+
- Gemfile.lock
|
22
137
|
- LICENSE
|
23
138
|
- README.md
|
24
139
|
- Rakefile
|
25
140
|
- lib/dpop.rb
|
141
|
+
- lib/dpop/configuration.rb
|
142
|
+
- lib/dpop/controller.rb
|
143
|
+
- lib/dpop/cookie_jar.rb
|
144
|
+
- lib/dpop/encryptor.rb
|
145
|
+
- lib/dpop/key_generator.rb
|
146
|
+
- lib/dpop/proof_generator.rb
|
147
|
+
- lib/dpop/railtie.rb
|
26
148
|
- lib/dpop/version.rb
|
27
|
-
- sig/dpop.rbs
|
28
149
|
homepage: https://github.com/WilliamNHarvey/dpop-ruby
|
29
150
|
licenses: []
|
30
151
|
metadata:
|
@@ -39,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
160
|
requirements:
|
40
161
|
- - ">="
|
41
162
|
- !ruby/object:Gem::Version
|
42
|
-
version: 2.
|
163
|
+
version: 2.5.0
|
43
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
165
|
requirements:
|
45
166
|
- - ">="
|
@@ -49,6 +170,6 @@ requirements: []
|
|
49
170
|
rubygems_version: 3.1.2
|
50
171
|
signing_key:
|
51
172
|
specification_version: 4
|
52
|
-
summary: Implementation of DPoP (
|
53
|
-
Layer) for Ruby and Rails
|
173
|
+
summary: Implementation of DPoP (Demonstrating Proof-of-Possession at the Application
|
174
|
+
Layer) for Ruby and Rails
|
54
175
|
test_files: []
|
data/sig/dpop.rbs
DELETED